# mypy: 允许未类型化定义
""
torch.autograd 提供了实现任意标量值函数自动微分的类和函数。
它只需要对现有代码进行最小改动——你只需声明 :class:`Tensor` s
需要计算梯度的变量应使用 `requires_grad=True` 关键字。
目前,我们仅支持浮点类型 :class:`Tensor` 的 autograd
half、float、double 和 bfloat16)以及复数类型:class:`Tensor`(cfloat、cdouble)。
""
import 警告
from collections.abc import 序列
from 打字 import
演员表,
可选的,
联合
import 火炬
from 火炬 import
_vmap 内部
from torch.overrides import handle_torch_function, 具有 torch 函数,
类似于 tensor
from torch 的类型 import _size, _TensorOrTensors, _TensorOrTensorsOrGradEdge
from . import forward_ad, 功能性,
图
from .异常模式 import
检测异常,
设置检测异常
from .函数 import
函数,
嵌套 IO 函数
from .梯度模式 import (
_强制原始视图跟踪,
_不安全保留版本计数器,
启用梯度,
inference_mode,
不梯度,
设置梯度启用,
设置多线程启用,
)
from .gradcheck import gradcheck, gradgradcheck
from .graph import _engine_run_backward
from .变量 import
变量
全部 = [
"变量",
"功能",
"向后",
"梯度模式",
"嵌套 IO 函数",
检测异常,
启用梯度,
梯度,
梯度检查,
"gradgradcheck",
"推理模式",
"关闭梯度",
"设置检测异常",
set_grad_enabled,
set_multithreading_enabled,
变量,
]
_可选张量 =
可选[
PyTorch.
张量]
_形状或嵌套形状 =
联合[
_大小,
序列[
尺寸
]
PyTorch.
张量]
定义
计算_形状(
输出:
并集[
PyTorch.
张量,
图.
梯度边缘
]
研究生:
PyTorch.
张量,
是否批处理研究生: bool,
) -> 元组[
_形状或嵌套形状,
_形状或嵌套形状
]
# 确保两个张量要么都是嵌套的,要么都不是嵌套的
# 循环导入
from torch.nested._internal.nested_tensor import NestedTensor
如果 isinstance(
输出,
图.
梯度边缘):
我们已经检查过我们不是 C++嵌套张量
如果 is_grads_batched:
提升 RuntimeError(
批量梯度不支持与 GradientEdge 一起使用)
out_metadata = 输出.
节点.
输入元数据[
输出.
输出编号]
返回
PyTorch.
大小(
输出元数据.
形状),
梯度.
形状
如果
输出.
是否嵌套
以及
非 isinstance(
输出,
嵌套张量):
如果
是否批处理梯度:
提升 RuntimeError(
"不支持嵌套张量中的批处理梯度。")
输出形状 =
输出.
_嵌套张量大小()
梯度形状 =
梯度.
_嵌套张量大小()
返回
输出形状,
梯度形状
归一化输出形状 =
输出.
形状
归一化梯度形状 =
梯度.
形状
如果
非
是否批处理梯度
否则
梯度.
形状[1
]
返回
注册输出形状,
注册梯度形状
定义 _make_grads(
输出:
联盟[
序列[
PyTorch.
张量
]
序列[
图.
梯度边缘
]]
梯度:
序列[
可选张量
]
是否批处理梯度: bool,
) -> 元组[
可选张量, ...
]
新梯度:
列表[
可选张量] =
输入文本为空,请提供需要翻译的文本
为
出,
毕业生
在
压缩(
输出,
毕业生):
出去 =
演技(
联合[
PyTorch.
张量,
图.
梯度边缘
]
输出)
输出大小 =
无。
输出设备 =
无。
如果 isinstance(
输出,
图.
梯度边缘):
输出元数据 =
输出.
节点.
输入元数据[
输出.
输出编号]
输出大小 =
PyTorch.
尺寸(
输出元数据.
形状)
输出数据类型 =
输出元数据.dtype
输出设备 =
输出元数据.
设备
输出是否嵌套 =
输出元数据.
是否嵌套张量
如果
输出元数据.
是否是 C++嵌套张量:
抛出 RuntimeError(
"C++嵌套 Tensor 不支持与 GradientEdge"
)
out_is_cpp_nested = 假
else:
# 循环导入
from torch.nested._internal.nested_tensor import NestedTensor
断言 isinstance(
输出,
PyTorch.
张量)
输出数据类型 =
输出.dtype
输出是否嵌套 =
输出.
是嵌套的
输出_is_cpp_nested =
输出_is_nested
以及
非 isinstance(
输出,
嵌套张量)
如果
非
输出是 C++嵌套:
输出大小 =
出.
形状
如果 isinstance(
毕业生,
PyTorch.
张量):
from torch.fx.experimental.symbolic_shapes import 预期为真,
等式
一阶导数 =
梯度
如果
非
是否梯度批处理
否则
梯度[0]
# TODO: 我们可以在统一使用后删除此条件
表示锯齿状维度的单例整型,以便于嵌套张量的 size()调用
以便于嵌套张量的 size()调用
如果
输出为 cpp 嵌套:
断言 isinstance(
输出,
PyTorch.
张量)
形状匹配 =
PyTorch.
大小相同(
输出,
第一梯度)
else:
我们需要做常规大小检查,而不通过操作符
以便能够处理未备份的符号
(expect_true 确保我们可以处理未备份的)
断言
输出大小
是
非
无。
形状匹配 =
预期为真(
相等(
输出大小,
第一梯度.
尺寸()))
如果
非
形状匹配:
外部 =
角色(
联合[
PyTorch.
张量,
图.
梯度边缘
]
输出)
输出形状,
累积形状 =
_计算形状(
输出,
第一梯度,
是否批处理梯度
)
如果
是否批处理梯度:
抛出 RuntimeError(
如果 `is_grads_batched=True`,我们将每个 grad_output 的第一个维度解释为批维度。
"每个 grad_output 的第一个维度被解释为批维度。"
"剩余维度的尺寸预期应与"
"相应的输出形状相匹配,但检测到不匹配:grad_output["
"梯度"
+ str(梯度.
索引(
梯度))
+ "] 形状为 "
+ str(梯度形状)
+ " 和输出["
+ str(输出.
索引(
输出))
+ "] 的形状为 "
+ str(输出形状)
+ ". "
"如果您只想将`grad_output`中的某些张量视为 "
"批处理,请考虑使用 vmap。"
)
else:
抛出 RuntimeError(
"形状不匹配:grad_output["
+ str(研究生.
索引(
研究生))
+ "] 的形状为 "
+ str(研究生形状)
+ "和输出["
+ str(输出.
索引(
出))
+ "]的形状为"
+ str(输出形状)
+ "."
)
如果
输出数据类型.
是否为复数 !=
梯度.
数据类型.
是复杂的:
抛出 RuntimeError(
对于复杂的张量,grad_output 和 output
都需要具有相同的数据类型。
"dtype 不匹配:grad_output["
+ str(梯度.
索引(
梯度值))
+ "]的数据类型为"
+ str(研究生.
数据类型)
+ "并且输出["
+ str(输出.
索引(
输出))
+ "] 的数据类型为 "
+ str(输出数据类型)
+ “点”
)
新毕业生.
添加(
毕业)
elif 毕业
是
无:
如果 isinstance(
出,
图.
梯度边缘)
或者
出.
需要梯度:
# 类型:忽略[已定义]
如果 isinstance(
出,
图.
梯度边缘):
断言
输出大小
是
非
无。
输出元素数量为 1 =
所有(o == 1
为 o
在
输出大小)
else:
断言 isinstance(
输出,
PyTorch.
张量)
out_numel_is_1 = 输出.
元素数量() == 1
如果
非 out_numel_is_1:
提升 RuntimeError(
"梯度只能为标量输出隐式创建"
)
如果
非 out_dtype.is_floating_point:
msg = (
"梯度只能为实数标量输出隐式创建"
f"但得到了"{out_dtype}"
)
提升 RuntimeError(
消息)
如果 isinstance(
输出,
图.
梯度边缘):
断言
输出大小
是
非
无。
断言
输出设备
是
非
无。
新员工.
添加(
PyTorch.
一(
输出大小,
数据类型=
输出数据类型,
设备=
输出设备,
)
)
else:
断言 isinstance(
输出,
PyTorch.
张量)
新梯度.
添加(
PyTorch.
喜欢的(
出,
内存格式=
PyTorch.
保留格式)
)
else:
新毕业生.
添加(
无)
else:
提升 TypeError(
"梯度可以是张量或 None,但得到了"
+ 类型(
梯度).__name__
)
返回
元组(
新梯度)
定义
张量或张量到元组的转换(
张量:
可选[_TensorOrTensors
]
长度:
整型
) -> 元组[
可选张量, ...
]
如果
张量
是
无:
返回 (
无,) *
长度
如果 isinstance(
张量,
PyTorch.
张量):
返回 (
张量,)
返回
元组(
张量)
[文档]
定义
反向(
张量:
_张量或张量或梯度边,
累加张量:
可选[
_张量或张量列表] =
无,
保留图结构:
可选[bool] =
无,
创建图:
布尔 = False,
梯度变量:
可选[
_Tensor 或 Tensors] =
无,
输入:
可选[
_Tensor 或 Tensors 或 GradEdge] =
无,
) -> 无:
r计算给定张量相对于图叶的梯度之和。
使用链式法则对图进行微分。如果任何 ``tensors``
是非标量(即其数据包含多个元素)并且需要
梯度,则将计算雅可比-向量积。
函数还需要额外指定 ``grad_tensors``。
它应该是一个长度匹配的序列,包含“向量”
在雅可比-向量乘积中,通常是相对于对应张量的函数梯度(``None`` 是对于该值的可接受值)
相对于对应张量的函数梯度(``None`` 是一个可接受值)
所有不需要梯度张量的张量。
此函数在叶子节点中累积梯度 - 你可能需要将其清零。
在调用之前,请查看 `.grad` 属性或将其设置为 `None`。
请参阅::ref:`默认梯度布局`。
关于累积梯度的内存布局详情。
.. 注意:
使用此方法并设置 `create_graph=True` 将创建一个引用循环
参数及其梯度之间可能导致内存泄漏。
我们建议在创建图时使用 `autograd.grad` 来避免这种情况。
如果您必须使用此函数,请确保在使用后重置参数的 `.grad` 字段为 `None` 以断开循环并避免泄漏。
参数的 `.grad` 字段重置为 `None`,以断开循环并避免泄漏。
.. 注意::
如果您运行任何前向操作,创建 `grad_tensors`,以及/或调用 `backward`
在用户指定的 CUDA 流上下文中,请参阅
ref:`反向传播的流语义`.
.. 注意::
当提供 `inputs` 并给定输入不是叶子节点时,
当前实现将调用其 grad_fn(即使严格来说不需要获取这些梯度)。
这是一个实现细节,用户不应依赖。
更多详情请见 https://github.com/pytorch/pytorch/pull/60521#issuecomment-867061780。
参数:
张量(Sequence[Tensor] 或 Tensor 或 Sequence[GradientEdge] 或 GradientEdge):张量
导数将被计算。
grad_tensors (Sequence[Tensor 或 None]或 Tensor, 可选): "向量"
雅可比-向量积,通常是对每个元素的梯度
对应的张量。对于标量张量或不需要梯度的张量,可以指定 None 值。
如果 None 值对所有不需要梯度的张量都适用。
如果 grad_tensors 可以接受 None 值,则此参数是可选的。
retain_graph(布尔值,可选):如果为 False,则用于计算梯度的图将被保留。
将被释放。请注意,在几乎所有情况下,将此选项设置为“True”
不需要,通常可以通过更有效的方法来解决这个问题
方式。默认为 `create_graph` 的值。
创建图(布尔值,可选):如果 ``True``,则创建导数的图
可构建,以便计算高阶导数乘积。
默认为 ``False``。
输入(Sequence[Tensor] 或 Tensor 或 Sequence[GradientEdge],可选):相对于这些输入的梯度
将累积到 ``.grad`` 中。所有其他 Tensor 都将被忽略。如果
未提供,梯度累积到所有叶张量中
用于计算::`tensors`。
"""
如果
PyTorch._C.
都是 functorch 转换激活():
提升 RuntimeError(
backward() 在 functorch 转换内部调用。这并不是“
"请使用 functorch.grad 或 functorch.vjp 代替"
"或在 functorch 转换外部调用 backward()。"
)
如果
梯度变量
是
非
无:
警告.
警告(
"`grad_variables` 已弃用。请使用 `grad_tensors` 代替。",
未来警告,
栈级别=2,
)
如果 grad_tensors
是
无:
grad_tensors = grad_variables
else:
提升 RuntimeError(
"`grad_tensors` 和 `grad_variables`(已弃用)"
"两个参数都传递给 `backward()`。请只"
使用 `grad_tensors`。
)
如果
输入
是
非
无。
以及 len(
输入) == 0:
提升 RuntimeError(
`backward()` 函数的 `inputs` 参数不能为空。)
如果 is_tensor_like(
张量)
或者 isinstance(
张量,
图.
梯度边缘):
张量 =
投射(
联盟[
元组[
PyTorch.
张量
]
元组[
图.
梯度边缘
]] (
张量,)
)
else:
张量 =
元组(
张量)
输入 = (
(输入,)
如果 isinstance(
输入, (
PyTorch.
张量,
图.
梯度边缘))
否则
元组(
输入)
如果
输入
是
非
无。
否则 ()
)
grad_tensors_ = _tensor_or_tensors_to_tuple(梯度张量, len(
张量))
梯度张量_ = _make_grads(
张量, grad_tensors_,
是否批处理梯度=False)
如果
保留图
是
无:
保留图 =
创建图
我们重复下面相同的注释的原因是
一些 Python 版本会在跟踪回溯中打印出多行函数的第一行调用
以及一些打印出最后一行
_engine_run_backward(
张量,
grad_tensors_,
保留图,
创建图,
输入,
允许不可达=True,
累加梯度=True,
)
[文档]
定义
梯度(
输出:
_张量或张量或梯度边,
输入:
_张量或张量或梯度边,
梯度输出:
可选[
_张量或张量列表] =
无,
保留图结构:
可选[bool] =
无,
创建图:
布尔 = False,
仅输入:
布尔 = True,
允许未使用:
可选[bool] =
无,
是否批处理梯度:
布尔 = False,
实现梯度:
布尔 = False,
) -> 元组[
PyTorch.
张量, ...
]
r计算并返回输出相对于输入的梯度的总和。
``grad_outputs`` 应该是一个长度与 ``output`` 匹配的序列
包含向量-雅可比乘积中的 "vector",通常是预先计算的
对每个输出的梯度。如果一个输出不需要 require_grad,那么梯度可以是 ``None``)。
。
.. 注意::
如果您运行任何前向操作,创建 ``grad_outputs``,以及/或调用 ``grad``
在用户指定的 CUDA 流上下文中,请参阅
ref:`反向传播的流语义`.
.. 注意:
``only_inputs`` 参数已弃用,现在将被忽略(默认为 ``True``)。
要累积图的其他部分的梯度,请使用
``torch.autograd.backward``。
参数:
输出(Tensor 或 GradientEdge 序列):微分函数的输出。
输入(Tensor 或 GradientEdge 序列):相对于该梯度将被返回(而不是累积到 ``.grad`` 中)的输入。
返回值(序列 Tensor):向量-雅可比积中的“向量”。
grad_outputs(序列 Tensor):向量-雅可比积中的“向量”。
通常针对每个输出计算梯度。可以指定标量值。
张量或不需要梯度的项。如果 None 值可以接受的话。
对于所有 grad_tensors,此参数是可选的。默认:None。
retain_graph(布尔值,可选):如果为 False,则不保留用于计算梯度的图。
将被释放。请注意,在几乎所有情况下,将此选项设置为“True”
不需要,通常可以通过更有效的方法来解决这个问题
方式。默认为 `create_graph` 的值。
创建图(布尔值,可选):如果 ``True``,则创建导数的图
可以构建,以便计算高阶导数乘积。
默认:``False``。
允许未使用(Optional[bool],optional):如果 ``False``,指定输入
未被用于计算输出(因此它们的梯度为)
总是零(zero)是一个错误。默认为 `materialize_grads` 的值。
is_grads_batched (bool, 可选): 如果 ``True``,每个的每一维度的梯度将被批处理
张量在 `grad_outputs` 中将被解释为批量维度。
而不是计算单个向量-雅可比乘积,我们计算
每个批次中每个“向量”的向量-雅可比积批次。
我们使用 vmap 原型功能作为后端以向量化调用
输入到自动微分引擎中,以便这个计算可以执行
单次调用。与之前相比,这应该会带来性能提升。
手动循环并多次执行反向操作。注意,
由于此功能为实验性,可能会有性能
请使用 `torch._C._debug_only_display_vmap_fallback_warnings(True)` 来显示任何性能警告,如果存在警告,请在 github 上提交问题
以显示任何性能警告,如果存在警告,请在 github 上提交问题
适用于您的用例。默认为 ``False``。
materialize_grads (bool, 可选): 如果 ``True``,将未使用输入的梯度设置为 ``None``。
而不是 ``None``。这在计算高阶导数时很有用。
如果 ``materialize_grads`` 为 ``True`` 且 ``allow_unused`` 为 ``False``,则会引发错误
将抛出异常。默认为 ``False``。
"""
如果
材料化梯度
以及
允许未使用
是 False:
提升
值错误(
"预期 allow_unused 应为 True 或在 materialize_grads=True 时未传递,"
"但得到:allow_unused=False。"
)
如果
允许未使用
是
无:
允许未使用 =
材料化梯度
如果
是否与张量类似(
输出)
或者 isinstance(
输出,
图.
梯度边缘):
输出 =
角色(
联盟[
序列[
PyTorch.
张量
]
序列[
图.
梯度边缘
]] (
输出,)
)
else:
输出 =
元组(
输出)
如果
类似于张量(
输入)
或者 isinstance(
输入,
图.
梯度边缘):
输入 =
角色(
_张量或张量或梯度边, (
输入,))
else:
输入 =
元组(
输入)
输出 =
元组(i
为 i
在
输出
如果
是否为张量类型(i))
输入张量 =
元组(i
为 i
在
输入
如果
类似张量的(i))
可覆盖的参数 =
输出 t +
输入
如果
有 torch 功能(
可覆盖的参数):
返回 handle_torch_function(
梯度,
可覆盖的参数,
输出,
输入,
梯度输出=
梯度输出,
保留图=
保留图,
创建图=
创建图,
仅输入=
仅输入,
允许未使用=
允许未使用,
是否批处理梯度=
是否批处理梯度,
材料化梯度=
材料渐变,
)
如果
非
仅输入:
警告.
警告(
"only_inputs 参数已弃用,现在将忽略。"
"(默认为 True)。要累积图的其他部分的梯度,请使用 torch.autograd.backward。"
"部分,请使用 torch.autograd.backward。",
FutureWarning,
栈级别=2,
)
grad_outputs_ = _tensor_or_tensors_to_tuple(grad_outputs, len(outputs))
grad_outputs_ = _make_grads(
outputs, grad_outputs_, 是否梯度批处理=
是否梯度批处理
)
如果
是否保留图
是
无:
是否保留图 =
创建图
# 以下重复多次注释的原因是因为
# 一些 Python 版本在堆栈跟踪中打印多行函数的第一个调用行
# 一些则打印最后一个调用行
如果
是否批处理梯度:
定义
反向传播(gO):
返回 _engine_run_backward(
输出,
gO,
保留图,
创建图,
输入,
允许未使用,
累加梯度=False,
)
结果 =
_vmap 内部._vmap(vjp, 0, 0,
允许空值通过=True)(
grad_outputs_
)
else:
结果 = _engine_run_backward(
outputs,
grad_outputs_,
retain_graph,
创建图,
输入,
允许未使用,
累加梯度=False,
)
如果
材料化梯度:
如果
任何(
结果[i]
是
无。
以及
非
是否与张量类似(
输入[i])
为 i
在
范围(len(
输入))
):
提升 RuntimeError(
"当给定的输入是梯度边时,不能使用 materialize_grads"
)
结果 =
元组(
输出
如果
输出
是
非
无。
否则
PyTorch.
等于零的(
输入,
需要梯度=True)
为 (
输出,
输入)
在 zip(
结果,
输入)
)
返回
结果
# 此函数适用于梯度检查点的情况
# 优化。目前,仅在通过 torch.autograd.backward()调用执行引擎时,才支持梯度检查点
# # 如果执行引擎是通过 torch.autograd.backward()调用的,则当前支持梯度检查点
输入参数未传递。torch.autograd.grad()不支持。
这是因为如果指定了输入,则不会计算梯度
# 其他内容,例如模型参数如权重、偏差等。
#
此函数返回检查点是否有效,即 torch.autograd.backward
# 或不,即 torch.autograd.grad。该实现通过维护一个线程
本地变量在 torch/csrc/autograd/engine.cpp 中,用于查看节点任务
在栈中,并在 evaluate_function 中执行 NodeTask 之前
检查是否必须使用可重入的向后操作。
请参阅 https://github.com/pytorch/pytorch/pull/4594 以获取更多讨论/上下文
定义 _is_checkpoint_valid():
返回
变量._execution_engine.is_checkpoint_valid()
定义
变量(*
参数, **
关键字参数):
# 无需注意:D103
提升 RuntimeError(
torch.autograd.variable(...) 已弃用,请使用 torch.tensor(...) 代替
)
# 钩子变量.Variable 以修复 FX 代码生成问题。FX 大致通过以下方式生成调用
# f"{fn.__module__}.{fn.__name__}(...). 这会产生 torch.autograd.variable.Variable(...) 在
# torch.autograd.variable 模块被不幸地遮蔽了。
# 已弃用的函数 - variable(...)。
variable.变量 =
变量
# 类型:忽略[已定义]
如果
非
PyTorch._C._autograd_init():
提升 RuntimeError(
自动微分初始化失败)
导入所有原生方法/类
from torch._C._autograd import (
_add_metadata_json,
_disable_profiler,
_disable_profiler_legacy,
启用分析器,
启用分析器(旧版),
启用记录函数,
获取序列号,
动态步进,
动态事件,
默认钩子保存 pop 张量,
准备分析器,
_profiler_enabled,
_ProfilerResult,
_push_saved_tensors_default_hooks,
_record_function_with_args_enter,
记录带参数的函数退出,
设置空测试观察者,
支持的活动,
切换集合动态,
设备类型,
动作可用,
分析器事件,
保存张量,
)
from torch._C._profiler import 分析器活动,
分析器配置,
分析器状态
from . import 分析器
定义
为设备注册 Python 张量类(
设备, cls):
如果
非 isinstance(cls,
类型):
提升 RuntimeError(
"cls 不是一个 typeinfo 对象")
PyTorch._C.
为设备注册 Python 类(
设备, cls)
多线程启用 =
PyTorch._C.
_多线程启用_
PyTorch._C.
_添加文档字符串_(
多线程启用,
"当前是否已启用多线程。"
)
是否启用视图回放 =
PyTorch._C.
_是否启用视图回放
PyTorch._C.
_添加文档字符串(
视频回放是否已启用,
如果当前已启用视频回放,则返回 True。
)