在此示例中,我们从中加载了经过预训练的resnet18模型torchvision。我们创建一个随机数据张量以表示具有3个通道,高度和宽度为64的单个图像,并将其对应的label值初始化为一些随机值。

import torch, torchvision
model = torchvision.models.resnet18(pretrained=True)
data = torch.rand(1, 3, 64, 64)
labels = torch.rand(1, 1000)

接下来,我们通过模型的每一层运行输入数据以进行预测。这是前传。

prediction = model(data) # forward pass

我们使用模型的预测和相应的标签来计算误差(loss)。下一步是通过网络反向传播此错误。当我们调用.backward()误差张量时,开始向后传播。然后,Autograd将为每个模型参数计算梯度并将其存储在参数的.grad属性中。

loss = (prediction - labels).sum()
loss.backward() # backward pass

接下来,我们加载一个优化器,在本例中为SGD,学习率为0.01,动量为0.9。我们在优化器中注册模型的所有参数。

optim = torch.optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

最后,我们呼吁.step()启动梯度下降。优化器通过存储在中的梯度来调整每个参数.grad。

optim.step() #gradient descent

至此,您已经具备了训练神经网络所需的一切。以下各节详细介绍了autograd的工作原理-随时跳过它们。

微调
在NN中,不计算梯度的参数通常称为冻结参数。如果事先知道不需要这些参数的梯度,则“冻结”模型的一部分很有用(这通过减少自动梯度计算而提供了一些性能优势)。

从DAG中排除很重要的另一个常见用例是对预训练的网络进行 微调

在微调中,我们冻结了大部分模型,通常仅修改分类器层以对新标签进行预测。让我们来看一个小例子来说明这一点。和以前一样,我们加载一个预训练的resnet18模型,并冻结所有参数。

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

假设我们要在具有10个标签的新数据集上微调模型。在resnet中,分类器是最后一个线性层model.fc。我们可以简单地将其替换为充当我们的分类器的新线性层(默认情况下为未冻结)。

model.fc = nn.Linear(512, 10)

现在,除了的参数外,模型中的所有参数model.fc都将冻结。计算梯度的唯一参数是的权重和偏差model.fc。

# Optimize only the classifier
optimizer = optim.SGD(model.parameters(), lr=1e-2, momentum=0.9)

请注意,尽管我们在优化器中注册了所有参数,但唯一可计算梯度的参数(因此会在梯度下降中进行更新)是分类器的权重和偏差。

相同的排除功能可作为torch.no_grad()中的上下文管理器使用