【他山之石】Pytorch Autograd与计算图
“他山之石,可以攻玉”,站在巨人的肩膀才能看得更高,走得更远。在科研的道路上,更需借助东风才能更快前行。为此,我们特别搜集整理了一些实用的代码链接,数据集,软件,编程技巧等,开辟“他山之石”专栏,助你乘风破浪,一路奋勇向前,敬请关注。
地址:https://www.zhihu.com/people/zhi-zuo-ren-23
import torch
默认读者掌握偏导数计算,链式法则,雅可比行列式等数学基础
01
data:该Tensor节点存储的数值
requires_grad:表示是否需要计算此tensor的梯度,默认False。当创建时指明为True,或者该tensor由其它该属性为True的tensor计算得到时,设置为True。通过.requires_grad_()来就地改变
grad:存储梯度的值,初始为None。当计算图后方有一个tensor(out)调用backward()时,存储 d(out)/ d(tensor_now)
grad_fn:反向传播时,用来计算梯度的函数。若tensor是通过初始化建立,或作为操作数tensor的requires_grad属性全为为False时为None,若是存在由其它requires_grad为True的tensor计算得到的为有特定函数
is_leaf:所有requires_grad=False的Tensors都为叶子节点,所有用户显示初始化的Tensors也为叶子节点
Example 1
x = torch.ones((2,2), requires_grad = True)
print(x)
print(x.grad_fn) #初始化建立的Tensor为None
print(x.is_leaf) #初始化建立为叶子节点
y = x + 5
print(y.grad_fn) #由requires_grad为True的tensor计算得到,有相应函数
print(y.is_leaf) #由requires_grad为True的tensor计算得到,requires_grad为True,非叶子节点
tensor([[1., 1.],
[1., 1.]], requires_grad=True)
None
True
<AddBackward0 object at 0x000001EBCDA654A8>
False
Example 2
x = torch.ones((2,2), requires_grad = True)
y = torch.rand((2,2)) #默认为False
z = x + y #操作数有一个为True,则结果也为True
print(y.requires_grad)
print(z.requires_grad)
False
True
Example 3
x = torch.randn(3,3) # 缺失情况下默认 requires_grad = False
y = x ** 3
print(x.requires_grad) # 默认 requires_grad = False
print(y.requires_grad) #算得y的所有操作数requires_grad = False,则y也为False
print(y.grad_fn) #算得y的所有操作数requires_grad = False,则y该属性为None
print(y.is_leaf) #算得y的所有操作数requires_grad = False,则y是叶子节点
print()
x.requires_grad_(True) #就地修改x是否需要记录梯度
print(x.requires_grad) # True
print()
print(y.requires_grad) # 算得y的所有操作数不会自动改变,仍是原来的x,所以仍为Fasle
print(y.grad_fn) #None
print()
y = x ** 3
print(y.requires_grad) # 算得y的所有操作数x重置,requires_grad = True,则y也为True
print(y.grad_fn) #存在
False
False
None
True
True
False
None
True
<PowBackward0 object at 0x00000251D73BB710>
02
完成计算后,可以调用.backward()来完成所有梯度计算。此Tensor的梯度将累积到叶子节点的.grad属性中,所以每次计算都要将梯度清零。若想要保留中间节点的梯度,则需要在调用.backward()方法前调用.retain_grad()方法。另一方面,.backward()只能完成标量对标量或者标量对张量的求导,所以在使用y.backward()时,如果y是标量,则不需要为backward()传入任何参数;否则,需要传入一个与y同形的Tensor,假设y由自变量x计算而来,w是和y同形的张量,则y.backward(w)的含义是:先计算l = torch.sum(y * w),则l是个标量,然后求l对自变量x的导数。
Example 1(from CS231n Lecture 4)
x = torch.tensor([-2],dtype = torch.float, requires_grad = True) #只有浮点数才能进入backward运算,神经网络均要求浮点数
y = torch.tensor([5],dtype = torch.float, requires_grad = True)
z = torch.tensor([-4],dtype = torch.float, requires_grad = True)
q = x + y
out = q * z
out.backward(torch.tensor([1.])) #浮点数的简单设置形式
print(out.grad) #非叶子节点不保留中间梯度
print(q.grad) #非叶子节点不保留中间梯度
print(x.grad.item())
print(y.grad.item())
print(z.grad.item())
None
None
-4.0
-4.0
3.0
Example 2(from CS231n Lecture 4)
W = torch.tensor([[1.,1.],[2.,2.]], requires_grad = True)
x = torch.ones((2,1), requires_grad = True)
out = W @ x
print(W)
print(x)
print(out)
out.backward(torch.ones_like(out)) #保留非叶子节点的梯度
print(out.grad)
print(W.grad)
print(x.grad)
tensor([[1., 1.],
[2., 2.]], requires_grad=True)
tensor([[1.],
[1.]], requires_grad=True)
tensor([[2.],
[4.]], grad_fn=<MmBackward>)
None
tensor([[1., 1.],
[1., 1.]])
tensor([[3.],
[3.]])
x = torch.tensor(1., requires_grad=True)
y1 = x ** 2
with torch.no_grad(): #将不需要记录梯度的代码块放入,常用
y2 = x ** 3
y3 = y1 + y2
print(x.requires_grad)
print(y1, y1.requires_grad) # True
print(y2, y2.requires_grad) # False
print(y3, y3.requires_grad) # True
y1.retain_grad() #保留非叶子节点的梯度
y2.retain_grad() #保留非叶子节点的梯度
y3.retain_grad() #保留非叶子节点的梯度
y3.backward()
print()
print(y3.grad)
print(y2.grad)
print(y1.grad)
print(x.grad) #y2路径不被计算,所以不是5,而是2
True
tensor(1., grad_fn=<PowBackward0>) True
tensor(1.) False
tensor(2., grad_fn=<AddBackward0>) True
tensor(1.)
None
tensor(1.)
tensor(2.)
03
model = ...
optim = torch.optim.SGD(model.parameters()) #将模型参数放入优化器迭代
out = model(input)
loss = (out - label).sum()
model.zero_grad() #清除梯度,不然backward会累加
loss.backward() #梯度计算
optim.step() #梯度迭代
for param in model.parameters():
param.requires_grad = False #将model的所有可训练参数全部冻结,之后就不会计算,减小计算开销
model.Dense = nn.Linear(512, 10) #修改需要调试的层,这层的参数是现在唯一可训练的
optimizer = optim.SGD(model.Dense.parameters()) #仅仅改变Dense层的参数
“他山之石”历史文章
tensorflow2.4性能调优最佳实践
PyTorch | DDP系列:入门教程、实现原理与源代码解析、实战与技巧
教你用PyTorch玩转Transformer英译中翻译模型!
深度学习工程技巧之网格调参
PyTorch使用预训练模型进行模型加载
深度学习调参经验总结
PyTorch实现断点继续训练
Pytorch/Tensorflow-gpu训练并行加速trick(含代码)
从NumPy开始实现一个支持Auto-grad的CNN框架
pytorch_lightning 全程笔记
深度学习中的那些Trade-off
PyTorch 手把手搭建神经网络 (MNIST)
autograd源码剖析
更多他山之石专栏文章,
请点击文章底部“阅读原文”查看
分享、点赞、在看,给个三连击呗!