pytorch学习笔记第三篇———自动梯度(torch.autograd)
Posted 非晚非晚
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytorch学习笔记第三篇———自动梯度(torch.autograd)相关的知识,希望对你有一定的参考价值。
训练神经网路(NN, neural network)分为
正向传播和反向传播
。
在正向传播中
,NN 对正确的输出进行最佳猜测。 它通过其每个函数运行输入数据以进行猜测。在反向传播中
,NN 根据其猜测中的误差调整其参数。 它通过从输出向后遍历,收集有关函数参数(梯度)的误差导数并使用梯度下降来优化参数来实现。
1. 一个神经网络例子
本例神经网络过程如下图
下面是一个完整的神经网络例子,包括前向传播与反向传播,具体过程见注释。
import torch, torchvision
model = torchvision.models.resnet18(pretrained=True) #从官网下载已经训练的过模型
data = torch.rand(1, 3, 64, 64) #随机生成4维数据:单个图像、3通道、高度和宽度
labels = torch.rand(1, 1000) #labels随机值
prediction = model(data) # 正向传播:对输入的数据进行预测
loss = (prediction - labels).sum() # 计算误差
loss.backward() # 反向传播:Autograd会为每个模型参数计算梯度,并将参数存储在.grad属性中
# 学习率:0.01,动量:0.9,。优化器中注册模型的所有参数
optim = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)
# 启动梯度下降。优化器通过.grad中存储的梯度来调整每个参数
optim.step() #gradient descent
2. Autograd的微分
我们看看Autograd怎么自动求梯度。我们定义
Q
=
3
a
2
−
b
2
Q=3a^2-b^2
Q=3a2−b2,我们知道
∂
Q
∂
a
=
9
a
2
;
∂
Q
∂
b
=
−
2
b
2
\\textstyle\\frac{\\partial Q}{\\partial a}=9a^2 ;\\textstyle\\frac{\\partial Q}{\\partial b}=-2b^2
∂a∂Q=9a2;∂b∂Q=−2b2
下面使用程序对它们进行验证。
import torch
# 定义两个张亮
a = torch.tensor([2., 3.], requires_grad=True)
b = torch.tensor([6., 4.], requires_grad=True)
# 定义Q张量
Q = 3*a**3 - b**2
# 反向传播计算梯度,Autograd将计算结果保存在.grad中
external_grad = torch.tensor([1., 1.]) # Q本身的梯度(Q对Q求导)
Q.backward(gradient=external_grad)
# 查看梯度结果
print(9*a**2 == a.grad)
print(-2*b == b.grad)
输出:
tensor([True, True])
tensor([True, True])
可以看到自动梯度与手动测算一致。
3. 计算图
从概念上讲,Autograd 在由函数对象组成的有向无环图(DAG,Directed acyclic graph)中
记录数据(张量)和所有已执行的操作(以及由此产生的新张量)。 在此 DAG 中,叶子是输入张量,根是输出张量
。 通过从根到叶跟踪此图,可以使用链式规则自动计算梯度。
在正向传播中,Autograd 同时执行两项操作:
- 运行请求的操作以计算结果张量
- 在 DAG 中维护操作的梯度函数。
当在 DAG 根目录上调用.backward()时,后退通道开始。 autograd然后:
- 从每个.grad_fn计算梯度,
- 将它们累积在各自的张量的.grad属性中,然后
- 使用链式规则,一直传播到叶子张量。
下面是我们示例中 DAG 的直观表示。 在图中,箭头指向前进的方向。 节点代表正向传播中每个操作的反向函数。 蓝色的叶节点代表我们的叶张量a和b
。
注意:DAG 在 PyTorch 中是动态的
。要注意的重要一点是,图是从头开始重新创建的; 在每个.backward()调用之后,Autograd 开始填充新图。 这正是允许您在模型中使用控制流语句的原因。 您可以根据需要在每次迭代中更改形状,大小和操作。
4. 从 DAG 中排除
torch.autograd跟踪所有将其requires_grad标志设置为True的张量的操作。 对于不需要梯度的张量,将此属性设置为False会将其从梯度计算 DAG 中排除。
注意:在运算中,即使只有一个输入张量具有requires_grad=True,操作的输出张量也将需要梯度。
例如:
import torch
x = torch.rand(5, 5) # 默认不需要
y = torch.rand(5, 5) # 默认不需要
z = torch.rand((5, 5), requires_grad=True) # 设置为需要
a = x + y #x、y为不需要,所以a为不需要
print(f"Does `a` require gradients? : {a.requires_grad}")
b = x + z # z为需要,所以b为需要
print(f"Does `b` require gradients?: {b.requires_grad}")
输出:
Does `a` require gradients? : False
Does `b` require gradients?: True
在 NN 中,不计算梯度的参数通常称为冻结参数
。 如果事先知道您不需要这些参数的梯度,则“冻结”模型的一部分很有用(通过减少自动梯度计算,这会带来一些表现优势)。
从 DAG 中排除很重要的另一个常见用例是调整预训练网络。如下例中,先冻结所有的模型,然后给model.fc赋予新的线性层,只需要计算它的权重与偏差
。
from torch import nn, optim
model = torchvision.models.resnet18(pretrained=True)
# Freeze all the parameters in the network
# 先冻结所有参数
for param in model.parameters():
param.requires_grad = False
# 给model.fc赋予新的参数,计算梯度的唯一参数为model.fc,计算它的权重和偏差
model.fc = nn.Linear(512, 10)
# Optimize only the classifier
optimizer = optim.SGD(model.fc.parameters(), lr=1e-2, momentum=0.9)
以上是关于pytorch学习笔记第三篇———自动梯度(torch.autograd)的主要内容,如果未能解决你的问题,请参考以下文章
Pytorch深度学习50篇·······第三篇:非监督学习