PyTorch基础知识讲解(三)自动微分与模型微调

autograd

pytorch 中 tensor 特有的自动微分机制,tensor可以保留在参与运算时的微分(required_grad=True),并用于反向传播。

通常,在进行推理时,我们不需要保存微分,此时可以使用with torch.no_grad():来指定一个无微分的上下文管理器,在该环境中进行推理的步骤。

另外,在对已经预训练好的模型,可以对模型的参数进行冻结(required_grad=False),随后使用少量的线性层用于下游任务训练。
准。

1. 模型训练步骤摘要

这里我们回顾了在单次训练(不考虑迭代轮次等细节,只关注核心代码)时需要做的主要步骤,同时假设我们已经有预训练好的模型。

  1. 加载 resnet18 预训练模型,加载训练数据及标签
  2. 前向传播,计算损失
  3. 反向传播,计算梯度
  4. 依据梯度更新参数权重
import torch, torchvision
from torchvision.models import ResNet18_Weights
# data: 输入, 表示1个 batch 中包含一个样本, 该样本包含3个通道(C), 大小为 64x64
# labels: 输出, 表示1个输出, 表示输入属于这 1000 个类的概率
torch.random.seed = 0
model = torchvision.models.resnet18(weights=ResNet18_Weights.IMAGENET1K_V1)
data = torch.rand((1, 3, 64, 64))
labels = torch.rand(1, 1000)
data.shape, labels.shape
(torch.Size([1, 3, 64, 64]), torch.Size([1, 1000]))
# 1. 通过模型的每一层来运行输入数据,进行预测。这就是前向传播
y = model(data)
y.shape
torch.Size([1, 1000])
# 2. 使用模型的预测和相应的标签来计算误差(损失)。下一步是通过网络反向传播这个误差。
#    当我们在误差tensor上调用.backward()时,后向传播就开始了。然后,Autograd计算
#    并将每个模型参数的梯度存储在参数的.grad属性中。
loss = ((labels-y)**2).sum()
loss.backward()
loss
tensor(1056.4602, grad_fn=<SumBackward0>)
# 3. 加载一个优化器,例如SGD,设置超参数:学习率为0.01,动量为0.9。
#    同时,在优化器中注册模型的所有参数。
sgd = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)
sgd
SGD (
Parameter Group 0
    dampening: 0
    foreach: None
    lr: 0.01
    maximize: False
    momentum: 0.9
    nesterov: False
    weight_decay: 0
)
# 4. 调用.step()来启动梯度下降。优化器通过存储在.grad中的梯度调整每个参数
sgd.step()

2. 自动微分与计算图

# 默认情况下, 一个 tensor 的保留微分这一属性是 False
a = torch.tensor([1., 2.])
a.requires_grad
False
a = torch.tensor([1., 2.], requires_grad=True)
b = torch.tensor([2.4, 3.6], requires_grad=True)
Y = a*a + a*b + b*b
Y, Y.requires_grad
(tensor([ 9.1600, 24.1600], grad_fn=<AddBackward0>), True)
# 计算Y关于 a, b的微分
Y.sum().backward()
a.grad == 2*a+b, b.grad== 2*b+a
(tensor([True, True]), tensor([True, True]))

从概念上讲,autograd在一个由Function对象组成的有向无环图(DAG)中保存了数据(tensor)和所有执行的操作(以及产生的新tensor)的记录。在这个DAG中,叶子是输入tensor,根部是输出tensor。通过追踪这个图从根到叶,你可以使用链式规则自动计算梯度。

在一个前向传递中,autograd同时做两件事:

运行请求的操作,计算出结果的tensor,以及
在DAG中维护该操作的梯度函数。
当在DAG根上调用.backward()时,后向传递开始了。

计算每个.grad_fn的梯度。
将它们累积到各自的tensor的 .grad 属性中,并且
使用链规则,一直传播到叶子tensor。

3. 模型参数冻结

在NN中,不计算梯度的参数通常被称为冻结参数。如果你事先知道你不需要这些参数的梯度,那么 "冻结 "你的模型的一部分是很有用的(这通过减少自动梯度计算提供了一些性能上的好处)。

从DAG中排除的另一个常见情况是对预训练的网络进行微调。

在微调中,我们冻结了大部分模型,通常只修改分类器层以对新标签进行预测。

# 仍然以 resnet18 为例, 如下冻结了模型所有参数
for para in model.parameters():
    para.requires_grad = False
# fc 是 resnet 的最后一个线性层
model.fc
Linear(in_features=512, out_features=1000, bias=True)
# 简单的将其进行替换, 例如假设需要训练一个 10 类别的分类器
from torch import nn
model.fc = nn.Linear(512, 10)
# 随后即可在这个冻结大部分参数的预训练模型上进行微调训练
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值