关于Pytorch中autograd和backward的一些笔记
参考自《Pytorch autograd,backward详解》:
1 Tensor
Pytorch中所有的计算其实都可以回归到Tensor上,所以有必要重新认识一下Tensor。
如果我们需要计算某个Tensor的导数,那么我们需要设置其.requires_grad
属性为True
。为方便说明,在本文中对于这种我们自己定义的变量,我们称之为叶子节点(leaf nodes),而基于叶子节点得到的中间或最终变量则可称之为结果节点。
另外一个Tensor中通常会记录如下图中所示的属性:
data
: 即存储的数据信息requires_grad
: 设置为True
则表示该 Tensor 需要求导grad
: 该 Tensor 的梯度值,每次在计算 backward 时都需要将前一时刻的梯度归零,否则梯度值会一直累加,这个会在后面讲到。grad_fn
: 叶子节点通常为 None,只有结果节点的 grad_fn 才有效,用于指示梯度函数是哪种类型。is_leaf
: 用来指示该 Tensor 是否是叶子节点。
举例:
x = torch.rand(3, requires_grad=True) y = x ** 2 z = x + x print( 'x requires grad: {}, is leaf: {}, grad: {}, grad_fn: {}.' .format(x.requires_grad, x.is_leaf, x.grad, x.grad_fn) ) print( 'y requires grad: {}, is leaf: {}, grad: {}, grad_fn: {}.' .format(y.requires_grad, y.is_leaf, y.grad, y.grad_fn) ) print( 'z requires grad: {}, is leaf: {}, grad: {}, grad_fn: {}.' .format(z.requires_grad, z.is_leaf, z.grad, z.grad_fn) )
运行结果:
x requires grad: True, is leaf: True, grad: None, grad_fn: None. y requires grad: True, is leaf: False, grad: None, grad_fn: <PowBackward0 object at 0x0000021A3002CD88>. z requires grad: True, is leaf: False, grad: None, grad_fn: <AddBackward0 object at 0x0000021A3002CD88>.
2 torch.autograd.backward
如下代码:
x = torch.tensor(1.0, requires_grad=True) y = torch.tensor(2.0, requires_grad=True) z = x**2+y z.backward() print(z, x.grad, y.grad) >>> tensor(3., grad_fn=<AddBackward0>) tensor(2.) tensor(1.)
当 z 是一个标量,当调用它的 backward 方法后会根据链式法则自动计算出叶子节点的梯度值。
但是如果遇到 z 是一个向量或者是一个矩阵的情况,这个时候又该怎么计算梯度呢?这种情况我们需要定义grad_tensor
来计算矩阵的梯度。在介绍为什么使用之前我们先看一下源代码中backward的接口是如何定义的:
torch.autograd.backward( tensors, grad_tensors=None, retain_graph=None, create_graph=False, grad_variables=None)
tensor
: 用于计算梯度的 tensor。也就是说这两种方式是等价的:torch.autograd.backward(z) == z.backward()
grad_tensors
: 在计算非标量的梯度时会用到。他其实也是一个tensor,它的shape一般需要和前面的tensor
保持一致。retain_graph
: 通常在调用一次 backward 后,pytorch 会自动把计算图销毁,所以要想对某个变量重复调用 backward,则需要将该参数设置为True
create_graph
: 当设置为True
的时候可以用来计算更高阶的梯度grad_variables
: 这个官方说法是 grad_variables' is deprecated. Use 'grad_tensors' instead. 也就是说这个参数后面版本中应该会丢弃,直接使用grad_tensors
就好了。
pytorch设计了grad_tensors
这么一个参数。它的作用相当于“权重”。
先看一个例子:
x = torch.ones(2,requires_grad=True) z = x + 2 z.backward() >>> ... RuntimeError: grad can be implicitly created only for scalar outputs
上面的报错信息意思是只有对标量输出它才会计算梯度,而求一个矩阵对另一矩阵的导数束手无策。
那么我们只要想办法把 转变成一个标量不就好了?比如我们可以对 求和,然后用求和得到的标量在分别对 求导,这样不会对结果有影响,例如:
x = torch.ones(2,requires_grad=True) z = x + 2 z.sum().backward() print(x.grad) >>> tensor([1., 1.])
而grad_tensors
这个参数就扮演了帮助求和的作用。
换句话说,就是对 和一个权重张量grad_tensors
进行 hadamard product 后求和。这也是 grad_tensors 需要与传入的 tensor 大小一致的原因。
x = torch.ones(2,requires_grad=True) z = x + 2 z.backward(torch.ones_like(z)) # grad_tensors需要与输入tensor大小一致 print(x.grad) >>> tensor([1., 1.])
3 torch.autograd.grad
torch.autograd.grad( outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False)
看了前面的内容后再看这个函数就很好理解了,各参数作用如下:
outputs
: 结果节点,即被求导数inputs
: 叶子节点grad_outputs
: 类似于backward
方法中的grad_tensors
retain_graph
: 同上create_graph
: 同上only_inputs
: 默认为True
,如果为True
,则只会返回指定input
的梯度值。 若为False
,则会计算所有叶子节点的梯度,并且将计算得到的梯度累加到各自的.grad
属性上去。allow_unused
: 默认为False
, 即必须要指定input
,如果没有指定的话则报错。
注意该函数返回的是 tuple 类型。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
2019-02-24 CCPC-Wannafly Winter Camp Day1 Div1 - 爬爬爬山 - [最短路][堆优化dijkstra]
2019-02-24 CCPC-Wannafly Winter Camp Day1 Div1 - 夺宝奇兵 - [贪心+线段树]