自动微分包 - torch.autograd¶
torch.autograd
提供实现自动
任意标量值函数的微分。它要求最少
对现有代码的更改 - 您只需声明 s
对于哪些梯度,应该使用关键字计算。
截至目前,我们只支持浮点类型 (
half、float、double 和 bfloat16)和复杂类型(cfloat、cdouble)的 Half 和 Double 类型。Tensor
requires_grad=True
Tensor
Tensor
计算给定张量相对于图形叶子的梯度之和。 |
|
计算并返回输出相对于输入的梯度之和。 |
正向模式自动微分¶
警告
此 API 处于测试阶段。尽管函数签名不太可能更改,但改进 在我们认为这一点稳定之前,已经规划了运维覆盖范围。
有关如何使用此 API 的详细步骤,请参阅前向模式 AD 教程。
启用正向 AD 的上下文管理器。 |
|
将张量值与正向梯度(切线)相关联,以创建“双张量”,用于计算正向 AD 梯度。 |
|
解压缩一个 “dual tensor” 以获得其 Tensor 值和其正向 AD 梯度。 |
功能更高的 API¶
警告
此 API 处于测试阶段。尽管函数签名不太可能更改,但 major 在我们认为这稳定之前,我们计划了对性能的改进。
本节包含基于上述基本 API 构建的 autograd 的更高级别 API 并允许您计算雅可比矩阵、黑森矩阵等。
此 API 适用于用户提供的函数,这些函数仅将 Tensor 作为输入并返回
只有 Tensors。
如果您的函数采用其他不是 Tensor 或未设置 requires_grad 的 Tensor 的参数,
您可以使用 Lambda 来捕获它们。
例如,对于一个接受三个输入的函数,一个 Tensor 我们需要雅可比矩阵,另一个
张量,该张量应被视为常量和布尔标志,因为您可以将其用作 .f
f(input, constant, flag=flag)
functional.jacobian(lambda x: f(x, constant, flag=flag), input)
计算给定函数的雅可比矩阵的函数。 |
|
计算给定标量函数的 Hessian 矩阵的函数。 |
|
计算向量与给定函数在输入给定点的雅可比行列式之间的点积的函数。 |
|
计算给定函数在输入给定点的雅可比矩阵与向量 之间的点积的函数。 |
|
计算向量与给定标量函数的 Hessian 矩阵之间在输入给定点处的点积的函数。 |
|
计算给定标量函数的 Hessian 矩阵与输入给定点处的向量之间的点积的函数。 |
在本地禁用梯度计算¶
有关差异的更多信息,请参阅本地禁用梯度计算 在 no-grad 和 inference 模式以及其他相关机制之间 可能会与两者混淆。
禁用梯度计算的上下文管理器。 |
|
启用梯度计算的 context-manager 来启用梯度计算。 |
|
将梯度计算设置为 on 或 off 的 context-manager。 |
|
启用或禁用推理模式的上下文管理器 |
默认渐变布局¶
当非稀疏在 OR 期间收到非稀疏梯度时,按如下方式累积。
param
param.grad
如果 最初是 :param.grad
None
如果 的内存不重叠且密集,则 为 使用 strides 匹配创建(因此匹配 的 layout) 的 Layout) 。
param
.grad
param
param
否则,将使用 rowmajor-contiguous strides 创建。
.grad
如果已经具有 non-sparse 属性:param
.grad
如果 , 累积到 in-place,这将保留其步幅。
create_graph=False
backward()
.grad
如果 , 替换为 new tensor ,它会尝试(但不能保证) 匹配先前存在的 的 步幅。
create_graph=True
backward()
.grad
.grad + new grad
.grad
默认行为(让 s 在 first 之前,以便根据 1 或 2 创建它们的布局),
并随时间保留(根据 3 或 4) 获得最佳性能。
对布局的调用或不会影响布局。.grad
None
backward()
model.zero_grad()
optimizer.zero_grad()
.grad
事实上,将所有 s 重置为每个
蓄积期,例如:.grad
None
for iterations...
...
for param in model.parameters():
param.grad = None
loss.backward()
这样每次都会根据 1 或 2 重新创建它们,
是某些网络的有效替代方案,或者可以提高某些网络的性能。model.zero_grad()
optimizer.zero_grad()
手动渐变布局¶
如果您需要手动控制 的步幅,
分配具有所需步幅的归零张量
在第一个 之前,并且永远不要将其重置为 。
3 保证您的布局在满足 .
4 表示即使 ..grad
param.grad =
backward()
None
create_graph=False
create_graph=True
对 Tensor 的就地操作¶
在 autograd 中支持就地操作是一件困难的事情,我们不鼓励这样做 它们在大多数情况下的使用。Autograd 激进的缓冲区释放和重用使 它非常有效,并且很少有就地操作的情况 实际上,将内存使用量降低了任何显著的量。除非您正在操作 在内存压力很大的情况下,您可能永远不需要使用它们。
就地正确性检查¶
所有 s 都会跟踪应用于它们的就地操作,并且
如果实现检测到张量被保存为 backward in one of
函数,但之后被就地修改,则会引发错误
一旦 backward pass 开始。这可确保在就地使用
函数,并且没有看到任何错误,则可以确保计算出的
梯度是正确的。Tensor
变量 (已弃用)¶
警告
变量 API 已弃用:不再需要变量
将 autograd 与 Tensors 结合使用。Autograd 自动支持设置为 .请在下面找到有关以下内容的快速指南
已更改:requires_grad
True
Variable(tensor)
并且仍然按预期工作, 但它们返回 Tensor 而不是 Variables。Variable(tensor, requires_grad)
var.data
与 是一回事。tensor.data
现在,方法适用于张量 具有相同的方法名称。
var.backward(), var.detach(), var.register_hook()
此外,现在可以使用 using factory 创建张量
方法,如 、
、 等
如下所示:
requires_grad=True
autograd_tensor = torch.randn((2, 3, 4), requires_grad=True)
Tensor autograd 函数¶
|
|
|
是如果需要为此 Tensor 计算梯度,否则。 |
|
按照约定,所有具有 which is 的 Tensor 都将是叶 Tensor。 |
|
计算当前张量的梯度 w.r.t. |
|
返回与当前图形分离的新 Tensor。 |
|
将 Tensor 与创建它的图形分离,使其成为叶子。 |
|
注册一个向后钩子。 |
|
功能¶
-
class (*args, **kwargs)[来源]
torch.autograd.
Function
¶ Base 类创建自定义 autograd。功能
创建自定义 autograd.Function,将此类子类化并实现 和
static 方法。然后,要使用您的自定义 op 中,调用 class method 。不要直接打电话
。
apply
为确保正确性和最佳性能,请确保调用 正确的方法并使用 验证你的后向函数
。
ctx
有关如何使用此类的更多详细信息,请参阅扩展 torch.autograd 。
例子:
>>> class Exp(Function): >>> @staticmethod >>> def forward(ctx, i): >>> result = i.exp() >>> ctx.save_for_backward(result) >>> return result >>> >>> @staticmethod >>> def backward(ctx, grad_output): >>> result, = ctx.saved_tensors >>> return grad_output * result >>> >>> # Use it by calling the apply method: >>> output = Exp.apply(input)
执行操作。 |
|
定义使用向后模式自动微分(别名 vjp 函数)来区分操作的公式。 |
|
定义用于区分具有正向模式自动微分的操作的公式。 |
上下文方法混入¶
将给定的张量标记为在就地操作中修改。 |
|
将输出标记为不可微分。 |
|
设置是否具体化输出 grad 张量。 |
数值梯度检查¶
检查通过小有限差分计算的梯度与解析梯度 w.r.t. |
|
检查通过小有限差分计算的梯度的梯度与解析梯度 w.r.t. |
分析器¶
Autograd 包含一个分析器,可让您检查不同
运算符 - 在 CPU 和 GPU 上。有两种模式
目前实现 - 仅使用 CPU 。
和基于 nvprof 的(同时注册 CPU 和 GPU 活动)。
-
类 (enabled=True, *, use_cuda=False, record_shapes=False, with_flops=False,profile_memory=False, with_stack=False, with_modules=False, use_kineto=False, use_cpu=真)[来源]
torch.autograd.profiler.
profile
¶ 管理 autograd 分析器状态并保存结果摘要的上下文管理器。 在后台,它只记录在 C++ 中执行的函数的事件,并且 将这些事件公开给 Python。您可以将任何代码包装到其中,它将 仅报告 PyTorch 函数的运行时。 注意:profiler 是线程本地的,会自动传播到异步任务中
- 参数
enabled (bool, optional) – 将此设置为 False 将使此上下文管理器为空操作。
use_cuda (bool, optional) – 使用 cudaEvent API 启用 CUDA 事件的计时。 为每个张量操作增加大约 4us 的开销。
record_shapes (bool, optional) – 如果设置了形状记录,则信息 将收集 About input 维度。这允许人们看到哪个 维度已在后台使用,并由它们进一步分组 使用 prof.key_averages(group_by_input_shape=True)。请注意, 形状记录可能会扭曲您的分析数据。建议 使用带和不带形状记录的单独运行来验证计时。 对于最底层的事件(在某些情况下,偏斜可以忽略不计 的嵌套函数调用)。但对于更高级别的函数,总 自身 CPU 时间可能会因形状 收集。
with_flops (bool, optional) – 如果设置了 with_flops,分析器将估计 使用运算符的输入形状的 FLOPs(浮点运算)值。 这允许估计硬件性能。现在 此选项仅适用于矩阵乘法和 2D 卷积运算符。
profile_memory (bool, optional) – 跟踪张量内存分配/释放。
with_stack (bool, optional) – 记录操作的源信息 (文件和行号)。
with_modules (bool) – 记录模块层次结构(包括函数名称) 对应于 op 的 callstack。例如,如果模块 A 的 forward 调用的 模块 B 的 forward 包含一个 aten::add 操作, 那么 aten::add 的模块层次结构是 A.B 请注意,目前仅对 TorchScript 模型提供此支持 而不是 Eager Mode 模型。
use_kineto (bool, optional) – 实验性,使用 Kineto 分析器启用性能分析。
use_cpu (bool, optional) – 分析 CPU 事件;设置为 requires 并可用于降低仅 GPU 分析的开销。
False
use_kineto=True
例
>>> x = torch.randn((1, 1), requires_grad=True) >>> with torch.autograd.profiler.profile() as prof: >>> for _ in range(100): # any normal python code, really! >>> y = x ** 2 >> y.backward() >>> # NOTE: some columns were removed for brevity >>> print(prof.key_averages().table(sort_by="self_cpu_time_total")) ----------------------------------- --------------- --------------- --------------- Name Self CPU total CPU time avg Number of Calls ----------------------------------- --------------- --------------- --------------- mul 32.048ms 32.048ms 200 pow 27.041ms 27.041ms 200 PowBackward0 9.727ms 55.483ms 100 torch::autograd::AccumulateGrad 9.148ms 9.148ms 100 torch::autograd::GraphRoot 691.816us 691.816us 100 ----------------------------------- --------------- --------------- ---------------
将 EventList 导出为 Chrome 跟踪工具文件。 |
|
将所有函数事件的键平均。 |
|
返回获取的 CPU 上花费的总时间,作为所有事件的所有自身时间的总和。 |
|
对所有事件求平均值。 |
-
class (enabled=True, record_shapes=False)[来源]
torch.autograd.profiler.
emit_nvtx
¶ 上下文管理器,使每个 autograd 操作发出 NVTX 范围。
在 nvprof 下运行程序时,它很有用:
nvprof --profile-from-start off -o trace_name.prof -- <regular command here>
不幸的是,没有办法强制 nvprof 刷新它收集的数据 到磁盘,因此对于 CUDA 分析,必须使用此上下文管理器来注释 nvprof 跟踪并等待进程退出,然后再检查它们。 然后,可以使用 NVIDIA Visual Profiler (nvvp) 来可视化时间线,也可以
加载结果进行检查 例如,在 Python REPL 中。
- 参数
enabled (bool, optional, default=True) – 设置此上下文管理器为无操作。 违约:。
enabled=False
True
record_shapes (bool, optional, default=False) – 如果 ,则 nvtx 范围包装 每个 autograd op 都会附加有关收到的 Tensor 参数大小的信息 通过该运算,格式如下:非张量参数将用 表示。 参数将按照后端操作接收它们的顺序列出。 请注意,此顺序可能与传递这些参数的顺序不匹配 在 Python 端。另请注意,形状录制可能会增加 nvtx 范围创建的开销。
record_shapes=True
[[arg0.size(0), arg0.size(1), ...], [arg1.size(0), arg1.size(1), ...], ...]
[]
例
>>> with torch.cuda.profiler.profile(): ... model(x) # Warmup CUDA memory allocator and profiler ... with torch.autograd.profiler.emit_nvtx(): ... model(x)
前向-后向关联
在 Nvidia Visual Profiler 中查看使用
创建的配置文件时, 将每个向后传递 OP 与相应的前向传递 OP 相关联可能很困难。 为了简化此任务,
将序列号信息附加到 it 生成。
在前向传递期间,每个函数范围都用 . 是正在运行的 counter,每次创建新的 backward Function 对象并储藏为 backward 时递增。 因此,与每个前向函数范围关联的注释告诉您 如果 backward Function 对象是由这个 forward 函数创建的,则 向后对象将接收序列号 N。 在向后传递期间,包装每个 C++ 向后函数调用的顶级范围用 . 是 创建 backward 对象时使用。通过比较 backward 中的数字和 forward 中的数字,您可以跟踪哪个 forward op 创建了每个 backward Function。
seq=<N>
seq
seq=<N>
apply()
stashed seq=<M>
M
stashed seq
seq
在向后传递期间执行的任何函数也都用 .在 default backward (with ) 此信息无关紧要,事实上,对于所有此类函数,可能只是 0。仅与 向后 Function 对象的方法很有用,可以作为关联这些 Function 的一种方式 对象。
seq=<N>
create_graph=False
N
apply()
双后退
另一方面,如果正在进行向后传递 with(换句话说, 如果要设置双向后),则每个函数在 Backward 被赋予一个非零的、有用的 。这些函数本身可以创建 Function 对象 稍后在 double-backward 期间执行,就像 forward pass 中的原始函数一样。 backward 和 double-backward 之间的关系在概念上与关系相同 between forward and backward:函数仍然发出当前序列号标记的范围, 它们创建的 Function 对象仍然会存储这些序列号,并且在最终的 double-backward 时,Function 对象的范围仍然用数字标记,这些数字可以与 backward pass 中的 seq 数字进行比较。
create_graph=True
seq=<N>
apply()
stashed seq
打开 nvprof 跟踪文件并解析 autograd 注释。 |
异常检测¶
-
类 [来源]
torch.autograd.
detect_anomaly
¶ Context-manager 为 autograd 引擎启用异常检测。
这执行两项操作:
在启用检测的情况下运行正向传递将允许向后 pass 打印创建失败的 forward 操作的回溯 backward 函数。
任何生成 “nan” 值的反向计算都将引发错误。
警告
此模式应仅用于调试,因为测试不同 会减慢程序的执行速度。
例
>>> import torch >>> from torch import autograd >>> class MyFunc(autograd.Function): ... @staticmethod ... def forward(ctx, inp): ... return inp.clone() ... @staticmethod ... def backward(ctx, gO): ... # Error during the backward pass ... raise RuntimeError("Some error in backward") ... return gO.clone() >>> def run_fn(a): ... out = MyFunc.apply(a) ... return out.sum() >>> inp = torch.rand(10, 10, requires_grad=True) >>> out = run_fn(inp) >>> out.backward() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/your/pytorch/install/torch/_tensor.py", line 93, in backward torch.autograd.backward(self, gradient, retain_graph, create_graph) File "/your/pytorch/install/torch/autograd/__init__.py", line 90, in backward allow_unreachable=True) # allow_unreachable flag File "/your/pytorch/install/torch/autograd/function.py", line 76, in apply return self._forward_cls.backward(self, *args) File "<stdin>", line 8, in backward RuntimeError: Some error in backward >>> with autograd.detect_anomaly(): ... inp = torch.rand(10, 10, requires_grad=True) ... out = run_fn(inp) ... out.backward() Traceback of forward call that caused the error: File "tmp.py", line 53, in <module> out = run_fn(inp) File "tmp.py", line 44, in run_fn out = MyFunc.apply(a) Traceback (most recent call last): File "<stdin>", line 4, in <module> File "/your/pytorch/install/torch/_tensor.py", line 93, in backward torch.autograd.backward(self, gradient, retain_graph, create_graph) File "/your/pytorch/install/torch/autograd/__init__.py", line 90, in backward allow_unreachable=True) # allow_unreachable flag File "/your/pytorch/install/torch/autograd/function.py", line 76, in apply return self._forward_cls.backward(self, *args) File "<stdin>", line 8, in backward RuntimeError: Some error in backward
保存的张量默认钩子¶
某些操作需要在正向传递期间保存中间结果 以执行向后传递。 您可以使用钩子定义如何打包/解包这些保存的张量。 一个常见的应用程序是通过保存这些中间结果来交换计算来换取内存 到磁盘或 CPU,而不是将它们留在 GPU 上。如果您 请注意,您的模型在评估期间适合 GPU,但不适合训练。 另请参阅已保存张量的 Hooks。
-
类 (pack_hook, unpack_hook)[来源]
torch.autograd.graph.
saved_tensors_hooks
¶ 为保存的张量设置一对 pack / unpack 钩子的上下文管理器。
使用此 context-manager 来定义操作的中间结果如何 应在保存之前打包,并在检索时解压缩。
在该上下文中,每次 操作保存一个张量用于向后(这包括中间结果 使用 but 保存 以及由 PyTorch 定义的操作记录的那些)。然后,的输出将存储在计算图中,而不是 原始张量。
pack_hook
save_for_backward()
pack_hook
当需要访问保存的张量时,将调用 The , 即在执行
或
时。它将打包对象作为参数 返回 和 应该返回一个具有相同 content 作为原始张量(作为输入传递给相应的 )。
unpack_hook
pack_hook
pack_hook
钩子应具有以下签名:
pack_hook(tensor: Tensor) -> 任意
unpack_hook(任意) -> 张量
其中,返回值 of 是 的有效输入 。
pack_hook
unpack_hook
一般来说,您希望在以下方面相等 value、size、dtype 和 device。
unpack_hook(pack_hook(t))
t
例:
>>> def pack_hook(x): ... print("Packing", x) ... return x >>> >>> def unpack_hook(x): ... print("Unpacking", x) ... return x >>> >>> a = torch.ones(5, requires_grad=True) >>> b = torch.ones(5, requires_grad=True) * 2 >>> with torch.autograd.graph.saved_tensors_hooks(pack_hook, unpack_hook): ... y = a * b Packing tensor([1., 1., 1., 1., 1.]) Packing tensor([2., 2., 2., 2., 2.]) >>> y.sum().backward() Unpacking tensor([1., 1., 1., 1., 1.]) Unpacking tensor([2., 2., 2., 2., 2.])
警告
对任一 hook 的 input 执行就地操作可能会导致 更改为未定义的行为。
警告
一次只允许一对钩子。当递归嵌套 this 时 context-manager 中,只会应用最里面的一对钩子。
-
class (pin_memory=False)[来源]
torch.autograd.graph.
save_on_cpu
¶ Context-manager,前向传递保存的张量将位于该 存储在 CPU 上,然后检索以进行 backward。
在此上下文管理器中执行操作时,中间 在正向传递期间保存在图表中的结果将移动到 CPU, 然后,在需要时复制回原始设备以进行向后传递。 如果图形已在 CPU 上,则不执行张量复制。
使用此上下文管理器将计算换成 GPU 内存使用(例如 当你的模型在训练期间不适合 GPU 内存时)。
例:
>>> a = torch.randn(5, requires_grad=True, device="cuda") >>> b = torch.randn(5, requires_grad=True, device="cuda") >>> c = torch.randn(5, requires_grad=True, device="cuda") >>> >>> def f(a, b, c): ... prod_1 = a * b # a and b are saved on GPU ... with torch.autograd.graph.save_on_cpu(): ... prod_2 = prod_1 * c # prod_1 and c are saved on CPU ... y = prod_2 * a # prod_2 and a are saved on GPU ... return y >>> >>> y = f(a, b, c) >>> del a, b, c # for illustration only >>> # the content of a, b, and prod_2 are still alive on GPU >>> # the content of prod_1 and c only live on CPU >>> y.sum().backward() # all CPU tensors are moved back to GPU, for backward >>> # all intermediary tensors are released (deleted) after the call to backward