来自 千问
在 PyTorch 中,反向传播是模型训练的核心环节。简单来说,它的作用就是**"自动算出每个参数(权重)对最终错误(损失)的影响有多大"**,从而指导优化器知道该往哪个方向调整参数才能让模型变得更好。
PyTorch 的核心优势在于它通过 torch.autograd 模块实现了自动微分,你不需要手动推导复杂的导数公式,只需要构建前向计算过程,PyTorch 就能自动帮你搞定反向传播。
核心原理:三步走
在 PyTorch 中实现反向传播通常遵循以下三个关键步骤:
- 前向传播:计算模型的预测值,并计算出损失(Loss)。
- 反向传播 :调用
loss.backward(),PyTorch 自动计算梯度。 - 更新参数:优化器根据计算出的梯度更新模型权重。
详细解析与代码示例
为了让你彻底理解,我们用一个最简单的线性回归例子来拆解这个过程。
1. 准备工作:标记需要追踪的变量
首先,我们需要告诉 PyTorch:"请帮我盯着这个变量,我要计算它的梯度。" 这是通过设置 requires_grad=True 来实现的。
python
import torch
# 定义权重 w 和偏置 b,并标记 requires_grad=True
w = torch.tensor(2.0, requires_grad=True)
b = torch.tensor(1.0, requires_grad=True)
x = torch.tensor(3.0) # 输入数据,不需要计算梯度
y_true = torch.tensor(8.0) # 真实标签
2. 前向传播:构建计算图
我们进行正常的计算:y_pred = w * x + b。在这个过程中,PyTorch 不仅计算了结果,还在后台悄悄构建了一张计算图(Computational Graph)。这张图记录了数据是如何流动和变换的。
python
# 前向传播
y_pred = w * x + b # 预测值: 2*3 + 1 = 7
loss = (y_pred - y_true)**2 # 损失: (7-8)² = 1
# 此时,loss 是一个标量(Scalar),且它知道它是怎么算出来的
3. 反向传播:自动计算梯度
这是最关键的一步。我们调用 loss.backward()。PyTorch 会从 loss 开始,沿着刚才构建的计算图反向 遍历,利用链式法则 自动计算出 w 和 b 的梯度,并把结果存储在 w.grad 和 b.grad 中。
python
# 反向传播
loss.backward()
# 查看计算出的梯度
print(f"w 的梯度: {w.grad}") # 输出: tensor(-6.)
print(f"b 的梯度: {b.grad}") # 输出: tensor(-2.)
发生了什么?(数学推导)
- 对 w 求导 :
d(loss)/d(w) = 2*(y_pred - y_true) * x = 2*(7-8)*3 = -6 - 对 b 求导 :
d(loss)/d(b) = 2*(y_pred - y_true) * 1 = 2*(7-8)*1 = -2
PyTorch 帮你自动完成了这些复杂的求导计算。
4. 更新参数:梯度下降
拿到了梯度,我们就可以更新参数了。注意:更新参数的操作通常需要包裹在 torch.no_grad() 中,以防止更新操作被记录进计算图(否则会造成内存泄漏)。
python
learning_rate = 0.1
with torch.no_grad(): # 暂时关闭梯度追踪
# 梯度下降更新公式:参数 = 参数 - 学习率 * 梯度
w -= learning_rate * w.grad
b -= learning_rate * b.grad
# ⚠️ 重要:清空梯度
# 如果不清零,下次计算的梯度会和这次的累加在一起(变成累加器)
w.grad.zero_()
b.grad.zero_()
在真实模型训练中的完整流程
在实际使用 nn.Module 和 DataLoader 时,代码结构通常是这样的:
python
import torch
import torch.nn as nn
import torch.optim as optim
# 假设 model 是你的神经网络,criterion 是损失函数
model = nn.Linear(1, 1) # 示例模型
criterion = nn.MSELoss()
optimizer = optim.SGD(model.parameters(), lr=0.01)
# 训练循环
for epoch in range(100):
# 1. 获取数据
inputs, targets = get_data()
# 2. 前向传播
outputs = model(inputs)
loss = criterion(outputs, targets)
# 3. 反向传播前,先清空上一轮的梯度(非常重要!)
optimizer.zero_grad() # 或者 model.zero_grad()
# 4. 反向传播:计算梯度
loss.backward()
# 5. 更新参数
optimizer.step()
关键注意事项
- 梯度累加 :PyTorch 默认会将梯度累加 。这意味着如果你不手动调用
optimizer.zero_grad()或w.grad.zero_(),每次backward()计算出的梯度都会加到之前的梯度上。这在某些场景(如梯度累积模拟大 batch)下是有用的,但在标准训练中必须清零。 requires_grad:只有设置了requires_grad=True的张量,才会计算和存储梯度。no_grad:在推理(测试)阶段或更新参数时,使用with torch.no_grad():可以节省内存并防止意外构建计算图。
总结来说,PyTorch 的反向传播机制就是:构建计算图 -> 调用 .backward() -> 获取 .grad -> 更新参数。这套机制让深度学习的实现变得异常简洁和直观。