涉及知识点
Tensor属性:.grad,.grad_fn, .requires_grad
Tensor函数:.backward(),.detach(),,retain_grad()
函数:.zero_grad()
求梯度函数backward()以及其参数gradient
计算图
雅各比矩阵
前向传播过程
接下来的内容都以下面的两段代码为例:
import torch
# 假设我们有一个可微的Tensor
x = torch.tensor([1, 2, 3], requires_grad=True,dtype=float)
# 执行一个可微操作
y = x * 2
z = y.mean()
z.backward()
# 查看Tensor的梯度信息
print(z.grad) #输出None
print(y.grad) #输出None
print(x.grad) #输出[0.6667,0.6667,0.6667]
import torch
# 假设我们有一个可微的Tensor
x = torch.tensor([1, 2, 3], requires_grad=True,dtype=float)
# 执行一个可微操作
y = x * 2
v = torch.tensor([2,1,1],dtype=float)
y.backward(v)
# 查看Tensor的梯度信息
print(y.grad) #输出None
print(x.grad) #输出[4.,2.,2.]
计算图,grad_fn,requires_grad
先看第一段代码。pytorch在前向传播的时候,如果经过的是可微操作(比如一个nn.Module
中的层,或者是一个torch.autograd
中的函数(如矩阵乘法)),那么将该操作并入计算图中。同时会记录对应tensor的grad_fn属性。方便后续进行反向传播计算。
在第一段代码里,x.grad_fn为None(x是人为创建的),y.grad_fn为MultiBackward,z.grad_fn为MeanBackward。
另外要注意requires_grad参数。只有tensor的requires_grad为True时,pytorch才会保留梯度信息。一般来说requires_grad默认是False(为了省空间)。但是神经网络中网络参数的requires_grad默认为True。
若一个tensor A 的requires_grad为True,则在计算图中与它相关的,涉及到计算该tensor的变量,requires_grad都会被设定为True(不然就无法计算A的梯度了)
grad,backward()以及其参数gradient
仅仅是前向传播计算,变量的grad仍然为None。只有调用了backward()函数,变量的grad才会被计算出来。
但是这里有好几个注意点:
- 所谓的grad就是导数。例如 y = x ∗ 2 y = x*2 y=x∗2,那么x的grad就是2(单变量,多变量下面会谈到)可以看看第一段代码的输出,自己计算一下
- 由于pytorch的内存管理机制,计算图中非叶子节点变量的grad是不保留的。这就是为什么第一段代码中z,y的grad都为None。如果要保留,就要使用retain_grad函数
- pytorch中基本都是处理的多变量的梯度计算。所以调用backward时,pytorch底层是使用雅各比矩阵来计算梯度的。由于雅各比矩阵计算方式的原因,如果想要按照第一段代码中 z . b a c k w a r d ( ) z.backward() z.backward()的方式调用,则要求 z z z为标量。否则就需要像第二段代码中的方式,人为提供 g r a d i e n t gradient gradient参数。(具体原因各位可以去看看雅各比矩阵的原理雅可比矩阵 Jacobian & 海塞矩阵 Hessian - 知乎 (zhihu.com))