torch之grad
一、grad
`grad`是指梯度的缩写。梯度在深度学习中非常重要,因为它们是使用反向传播算法进行网络训练时所需要计算的。PyTorch通过自动微分引擎Autograd提供了自动计算梯度的功能。每个`Tensor`对象都有一个`.grad`属性,这个属性会保存该`Tensor`的梯度。
二、与grad相关的几个概念
1、`requires_grad`: 如果一个`Tensor`的`requires_grad`属性被设置为`True`,PyTorch会追踪所有与这个张量有关的操作。那么在进行反向传播时,你就可以自动得到这个`Tensor`的梯度了。
2、`.backward()`: 当你完成了前向传递并计算出了损失之后,你可以调用损失`Tensor`上的`.backward()`方法来计算梯度。这个操作会计算损失相对于模型参数的梯度。
3、`.grad`: 在调用`.backward()`之后,所有参与运算并设置了`requires_grad=True`的`Tensor`的梯度将累积在它们的`.grad`属性中。
4、`.detach()`: 如果你希望从计算历史中移除一个`Tensor`,使其以后的操作不再追踪计算梯度,可以使用`.detach()`方法。
三、关于自动计算梯度的例子
a = torch.tensor([1,2,3.], requires_grad=True) # 这里将requires_grad设置为True标记需要追踪 out = a * a # 这里定义了out关于a的函数为 out = a * a y = out.sum() # 这里定义了y关于对out的求和 y.backward() # 将y进行反向传播给a : 其实是对y的关于a的各个标量求偏导 print(a.grad) # 那么结果即为2a: [2,4,6]
如上是关于计算grad的简单例子,具体说明已经在注释中说明。
如果y有多步操作,那么求导则是将每一步都整合起来
a = torch.tensor([1,2,3.], requires_grad=True) # 这里将requires_grad设置为True标记需要追踪 out = a * a # 这里定义了out关于a的函数为 out = a * a y = out.sum() # 这里定义了y关于对out的求和 y += torch.matmul(out, out) # 这里增加了一步矩阵乘法的操作 out * out y.backward() # 将y进行反向传播给a : 其实是对y的关于a的各个标量求偏导; 到这里y的公式为y = a * a + a^4 print(a.grad) # 那么求导结果即为 2a + 4a^3
四、detach
网上很多关于data和detach的说明
共同点:
data和detach()返回和 x 的相同数据 tensor,而且这个新的tensor和原来的tensor是共用数据的,一者改变,另一者也会跟着改变,而且新分离得到的tensor的require s_grad = False, 即不可求导的。
差异点:
1、data是属性,detach() 是方法;
2、通过data分离的对象,原对象是无感知的进而在data对象的改变不能被原对象 autograd 追踪求微分;
3、通过detach() 分离的对象,原对象知道,当detach()对象改变时候,原对象再追踪求微分则会抛出异常。
a = torch.tensor([1,2,3.], requires_grad=True) # 这里将requires_grad设置为True标记需要追踪 out = a.sigmoid() c = out.detach() # 通过detach,则c值改变,out的值也会随之改变,因为他们是共用数据 c.zero_() out.sum().backward() # out值被改变了,则这里会抛出异常,不允许再被求导 print(a.grad)
当然,如果上面不调用c.zero_()则在接下去的out.sum().backward()不会抛出异常
如果使用c = out.data也是不会报错,但是输出的是全0的结果
a = torch.tensor([1,2,3.], requires_grad=True) # 这里将requires_grad设置为True标记需要追踪 out = a.sigmoid() c = out.data c.zero_() # 这里更新了c的值,同时out的值也会被原地更新 out.sum().backward() print(a.grad) # 这里返回的是 tensor([0., 0., 0.])
那么,如果out直接调用out.zero_()会怎样呢?
a = torch.tensor([1,2,3.], requires_grad=True) # 这里将requires_grad设置为True标记需要追踪 out = a.sigmoid() out.zero_() out.sum().backward() # RuntimeError: one of the variables needed for gradient computation has been modified by an inplace operation: # [torch.FloatTensor [3]], which is output 0 of SigmoidBackward0, is at version 1; expected version 0 instead. print(a.grad)
跟detach一样,也是会报错;因为out自身处于追踪状态,当自身内部的数据被原地更新是会感知的到。所以在后续进行反向传播时候报错了
具体解释:由于梯度是根据原始计算图通过链式法则进行反向传播的,
如果你更改了计算图中的某些值(比如将`out`设置为0),
那么原始计算图就会丢失,因此无法再进行梯度的计算。
这也就是为什么`out.sum().backward()`会抛出错误的原因。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?