什么是 PyTorch 中的自动微分?
自动微分(Automatic Differentiation,AD)是机器学习中重要的数学工具之一,也是 PyTorch 中的核心特性之一。通过自动微分,我们可以在不手动计算导数的情况下,快速准确地计算出损失函数对于模型参数的导数。这极大地简化了模型训练过程中的数学计算,并且使得深度学习算法的实现更加方便。
自动微分在 PyTorch 中的算法原理
PyTorch 中的自动微分实现了反向自动微分(Reverse Mode Automatic Differentiation,RMAD),也被称为反向模式自动微分。在该算法中,模型的前向传播和反向传播分别对应着两个阶段:
-
前向传播阶段:在前向传播过程中,我们将输入数据通过神经网络模型,得到预测输出的结果。在这个阶段,我们需要保留模型中每一步计算的中间结果(张量),以便在后续的反向传播中使用。
-
反向传播阶段:在反向传播过程中,我们首先计算损失函数对于预测输出的梯度,然后通过链式规则逐层计算模型参数的梯度。这个过程中,PyTorch 会自动根据前向传播阶段保留的中间结果来计算每一步的梯度值,并用梯度下降等优化算法来更新模型参数。
PyTorch 自动微分的公式推导
接下来,我们来推导一下 PyTorch 自动微分的公式。假设我们的模型为一个多层感知机(Multi-Layer Perceptron,MLP),其中包含了两个隐藏层和一个输出层。我们使用交叉熵损失函数作为模型的训练目标。
首先,我们定义模型的输出为 y = f ( x ) y = f(x) y=f(x),其中 x x x 是输入数据, y y y 是模型的预测输出。损失函数可以表示为 L ( y , y true ) L(y, y_{\text{true}}) L(y,ytrue),其中 y true y_{\text{true}} ytrue 是真实标签。
模型的目标是最小化损失函数 L L L,即 minimize θ L ( y , y true ) \underset{\theta}{\text{minimize}}\,L(y, y_{\text{true}}) θminimizeL(y,ytrue),其中 θ \theta θ 是模型的参数。
根据链式法则,我们可以推导出损失函数对于模型参数的导数为:
∂ L ∂ θ = ∂ L ∂ y ⋅ ∂ y ∂ θ \frac{{\partial L}}{{\partial \theta}} = \frac{{\partial L}}{{\partial y}} \cdot \frac{{\partial y}}{{\partial \theta}} ∂θ∂L=∂y∂L⋅∂θ∂y
对于每个参数 θ i \theta_i θi,我们可以使用梯度下降等优化算法来更新该参数的值:
θ i ← θ i − α ⋅ ∂ L ∂ θ i \theta_i \leftarrow \theta_i - \alpha \cdot \frac{{\partial L}}{{\partial \theta_i}} θi←θi−α⋅∂θi∂L
其中 α \alpha α 是学习率。
PyTorch 自动微分的计算步骤
-
定义模型结构:我们需要定义一个包含两个隐藏层和一个输出层的多层感知机模型。
-
设置损失函数:我们选择交叉熵损失函数作为模型的训练目标。
-
前向传播:将输入数据 x x x 通过模型,得到预测输出 y y y。在这个过程中,PyTorch 会自动记录并保留每一步的计算结果(张量)。
-
计算损失函数:将预测输出 y y y 和真实标签 y true y_{\text{true}} ytrue 传入损失函数,得到损失值 L L L。
-
反向传播:调用
L.backward()
函数,PyTorch 会自动根据链式法则计算出损失函数对于模型参数的梯度。 -
参数更新:根据梯度下降等优化算法,使用以下公式来更新模型参数: θ i ← θ i − α ⋅ ∂ L ∂ θ i \theta_i \leftarrow \theta_i - \alpha \cdot \frac{{\partial L}}{{\partial \theta_i}} θi←θi−α⋅∂θi∂L,其中 α \alpha α 是学习率。
-
重复步骤 3-6,直到达到设定的训练迭代次数或者收敛条件。
PyTorch 自动微分的 Python 代码示例
import torch
import torch.nn as nn
import torch.optim as optim
# 定义多层感知机模型
class MLP(nn.Module):
def __init__(self):
super(MLP, self).__init__()
self.fc1 = nn.Linear(10, 100)
self.fc2 = nn.Linear(100, 100)
self.fc3 = nn.Linear(100, 1)
self.sigmoid = nn.Sigmoid()
def forward(self, x):
x = self.fc1(x)
x = self.sigmoid(x)
x = self.fc2(x)
x = self.sigmoid(x)
x = self.fc3(x)
output = self.sigmoid(x)
return output
# 创建模型实例
model = MLP()
# 定义损失函数和优化器
criterion = nn.BCELoss()
optimizer = optim.SGD(model.parameters(), lr=0.1)
# 输入数据
x = torch.randn(100, 10)
y_true = torch.tensor([0, 1] * 50, dtype=torch.float).unsqueeze(1)
# 前向传播
y_pred = model(x)
# 计算损失函数
loss = criterion(y_pred, y_true)
# 反向传播
loss.backward()
# 参数更新
optimizer.step()
上述代码实现了一个具有三个全连接层的多层感知机模型,使用sigmoid激活函数,并以交叉熵损失函数和随机梯度下降(SGD)作为优化算法。输入数据 x
的形状为 (100, 10)
,真实标签 y_true
的形状为 (100, 1)
。
在训练过程中,我们先进行前向传播来得到预测输出 y_pred
,然后计算损失函数 loss
。接下来调用 loss.backward()
完成反向传播,并调用优化器的 step()
函数来更新模型参数。
PyTorch 自动微分的代码细节解释
-
torch.autograd
: PyTorch 通过torch.autograd
模块实现了自动微分。在计算图中,张量对象通过.requires_grad=True
属性来追踪其计算历史,并构建计算图。 -
backward()
: 调用张量对象的.backward()
方法会进行反向传播计算导数。此过程中,PyTorch 使用计算图中的链式法则来自动计算梯度。 -
nn.Module
: PyTorch 中的神经网络模型都是通过继承nn.Module
类来实现的。在定义模型的forward()
方法时,我们需要写明每一步的计算过程,而 PyTorch 会自动记录中间结果用于后向传播。 -
nn.Module.parameters()
:parameters()
方法可以返回模型中可学习的参数。 -
optim.SGD
: PyTorch 中的优化器用于更新模型参数。我们可以使用optim.SGD
来使用随机梯度下降算法。
通过 PyTorch 中的自动微分功能,我们可以方便地构建和训练复杂的神经网络模型。这种便捷性对于机器学习的发展来说非常重要。