自动求导机制

本说明将概述Autograd如何工作并记录操作。了解这些并不是绝对必要的,但我们建议您熟悉它,因为它将帮助您编写更高效,更简洁的程序,并可帮助您进行调试。

从后向中排除子图

每个变量都有两个标志:requires_gradvolatile。它们都允许从梯度计算中精细地排除子图,并可以提高效率。

requires_grad

如果有一个单一的输入操作需要梯度,它的输出也需要梯度。相反,只有所有输入都不需要梯度,输出才不需要。如果其中所有的变量都不需要梯度进行,后向计算不会在子图中执行。

>>> x = Variable(torch.randn(5, 5))
>>> y = Variable(torch.randn(5, 5))
>>> z = Variable(torch.randn(5, 5), requires_grad=True)
>>> a = x + y
>>> a.requires_grad
False
>>> b = a + z
>>> b.requires_grad
True

这个标志特别有用,当您想要冻结部分模型时,或者您事先知道不会使用某些参数的梯度。例如,如果要对预先训练的CNN进行优化,只要切换冻结模型中的requires_grad标志就足够了,直到计算到最后一层才会保存中间缓冲区,其中的仿射变换将使用需要梯度的权重并且网络的输出也将需要它们。

model = torchvision.models.resnet18(pretrained=True)
for param in model.parameters():
    param.requires_grad = False
# Replace the last fully-connected layer
# Parameters of newly constructed modules have requires_grad=True by default
model.fc = nn.Linear(512, 100)

# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)

volatile

纯粹的inference模式下推荐使用volatile,当你确定你甚至不会调用.backward()时。它比任何其他自动求导的设置更有效——它将使用绝对最小的内存来评估模型。volatile也决定了require_grad is False

volatile不同于require_grad的传递。如果一个操作甚至只有有一个volatile的输入,它的输出也将是volatileVolatility比“不需要梯度”更容易传递——只需要一个volatile的输入即可得到一个volatile的输出,相对的,需要所有的输入“不需要梯度”才能得到不需要梯度的输出。使用volatile标志,您不需要更改模型参数的任何设置来用于inference。创建一个volatile的输入就够了,这将保证不会保存中间状态。

>>> regular_input = Variable(torch.randn(5, 5))
>>> volatile_input = Variable(torch.randn(5, 5), volatile=True)
>>> model = torchvision.models.resnet18(pretrained=True)
>>> model(regular_input).requires_grad
True
>>> model(volatile_input).requires_grad
False
>>> model(volatile_input).volatile
True
>>> model(volatile_input).creator is None
True

自动求导如何编码历史信息

每个变量都有一个.creator属性,它指向把它作为输出的函数。这是一个由Function对象作为节点组成的有向无环图(DAG)的入口点,它们之间的引用就是图的边。每次执行一个操作时,一个表示它的新Function就被实例化,它的forward()方法被调用,并且它输出的Variable的创建者被设置为这个Function。然后,通过跟踪从任何变量到叶节点的路径,可以重建创建数据的操作序列,并自动计算梯度。

需要注意的一点是,整个图在每次迭代时都是从头开始重新创建的,这就允许使用任意的Python控制流语句,这样可以在每次迭代时改变图的整体形状和大小。在启动训练之前不必对所有可能的路径进行编码—— what you run is what you differentiate.

Variable上的In-place操作

在自动求导中支持in-place操作是一件很困难的事情,我们在大多数情况下都不鼓励使用它们。Autograd的缓冲区释放和重用非常高效,并且很少场合下in-place操作能实际上明显降低内存的使用量。除非您在内存压力很大的情况下,否则您可能永远不需要使用它们。

限制in-place操作适用性主要有两个原因:

1.覆盖梯度计算所需的值。这就是为什么变量不支持log_。它的梯度公式需要原始输入,而虽然通过计算反向操作可以重新创建它,但在数值上是不稳定的,并且需要额外的工作,这往往会与使用这些功能的目的相悖。

2.每个in-place操作实际上需要实现重写计算图。不合适的版本只需分配新对象并保留对旧图的引用,而in-place操作则需要将所有输入的creator更改为表示此操作的Function。这就比较棘手,特别是如果有许多变量引用相同的存储(例如通过索引或转置创建的),并且如果被修改输入的存储被任何其他Variable引用,则in-place函数实际上会抛出错误。

In-place正确性检查

每个变量保留有version counter,它每次都会递增,当在任何操作中被使用时。当Function保存任何用于后向的tensor时,还会保存其包含变量的version counter。一旦访问self.saved_tensors,它将被检查,如果它大于保存的值,则会引起错误。

<think>嗯,用户想了解PyTorch中的自动求导机制,包括原理和使用教程。好的,首先我需要回忆一下PyTorch的自动求导是如何工作的。记得自动求导的核心是计算图和反向传播。当用户创建一个张量并设置requires_grad=True时,PyTorch会跟踪所有相关的操作,构建计算图。然后在反向传播时,根据链式法则计算梯度。 接下来,用户可能需要具体的例子来说明这个过程。例如,如何创建需要梯度的张量,执行前向计算,然后调用backward()方法。需要提到张量的grad属性,以及梯度累积的问题,记得在训练循环中要清零梯度。 另外,用户可能对控制梯度追踪的上下文管理器感兴趣,比如torch.no_grad(),或者如何修改张量的requires_grad属性。这部分需要解释清楚不同场景下的使用方式,比如在评估模型时关闭梯度计算以节省内存和计算资源。 还要注意引用相关的资料,比如参考资料中提到PyTorch的动态计算图特性,以及自动求导如何支持灵活的网络结构。可能还需要提到一些常见问题,比如为什么需要手动清零梯度,以及如何避免梯度爆炸或消失的问题。 用户的问题可能涉及自动求导的具体实现细节,比如计算图的结构,反向传播的链式法则应用。需要简明扼要地解释这些概念,避免过于深入底层实现,但又要足够清晰,让用户理解基本的工作原理。 最后,根据用户提供的引用内容,确保回答中正确引用相关段落,比如引用[3]中提到的计算图和反向传播,引用[5]中关于requires_grad参数的注意事项。这些引用需要自然地融入回答中,帮助用户定位更多信息。 总结一下,回答的结构应该先介绍自动求导的基本原理,包括计算图和反向传播,然后逐步展示使用教程,涵盖张量创建、前向传播、反向传播、梯度处理,以及控制梯度追踪的方法。最后通过示例代码和注意事项来强化理解,并生成相关问题引导用户深入学习。</think>### PyTorch自动求导机制详解 #### 一、自动求导核心原理 PyTorch的自动求导机制基于**动态计算图**和**反向传播算法**实现。当创建张量并设置`requires_grad=True`时,系统会记录所有相关运算,构建计算图[^3]。例如: ```python w = torch.randn(5, 3, requires_grad=True) # 标记需要追踪梯度 b = torch.randn(3, requires_grad=True) ``` 每个运算会生成一个`Function`节点,记录操作的梯度计算方式。当执行反向传播时,系统通过链式法则从输出层向输入层逐层计算梯度。 #### 二、使用流程说明(含代码) 1. **前向传播构建计算图** ```python x = torch.tensor([2.0], requires_grad=True) y = x**3 + 2*x + 1 # 自动记录运算关系 ``` 2. **反向传播梯度计算** ```python y.backward() # 自动计算dy/dx print(x.grad) # 输出导数值:3x² + 2 = 3*4 + 2 = 14 ``` 3. **梯度清零机制** ```python optimizer.zero_grad() # 必须手动清零,否则梯度会累积 ``` #### 三、关键控制方法 1. **梯度追踪控制** ```python with torch.no_grad(): # 关闭梯度追踪 inference = model(input) # 适用于推理场景 ``` 2. **参数冻结技巧** ```python for param in model.layer.parameters(): param.requires_grad_(False) # 冻结指定层参数 ``` #### 四、注意事项 1. 非叶子节点的梯度默认不保留,可通过`retain_graph=True`保持计算图[^5] 2. 原位操作(如`x += 1`)会破坏梯度计算,应使用`x = x + 1`[^2] 3. 自定义反向传播可通过重写`backward()`方法实现 #### 五、典型应用示例 ```python # 简单线性回归训练 w = torch.randn(1, requires_grad=True) b = torch.zeros(1, requires_grad=True) for epoch in range(100): y_pred = w * x_data + b loss = ((y_pred - y_data)**2).mean() loss.backward() with torch.no_grad(): w -= 0.01 * w.grad b -= 0.01 * b.grad w.grad.zero_() b.grad.zero_() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值