【PyTorch】PyTorch 自动微分与完整手动实现对比

PyTorch 自动微分与完整手动实现对比

  • 一、手动实现前向传播
    • [1. 问题设定](#1. 问题设定)
    • 2.代码实现
    • [3. 手动计算梯度(反向传播)](#3. 手动计算梯度(反向传播))
    • [4. 参数更新(手动实现 optimizer.step ())](#4. 参数更新(手动实现 optimizer.step ()))
  • [二、 PyTorch 自动微分](#二、 PyTorch 自动微分)
  • [三、 总结](#三、 总结)

一、手动实现前向传播

1. 问题设定

2.代码实现

python 复制代码
# 输入数据和标签
x = [1.0, 2.0]  # 输入特征
y = 3.0         # 真实标签

# 模型参数(随机初始化)
w = [0.5, 0.5]  # 权重
b = 0.1         # 偏置

# 前向传播计算预测值
y_pred = w[0] * x[0] + w[1] * x[1] + b

# 计算损失(MSE)
loss = 0.5 * (y_pred - y) ** 2

print(f"预测值: {y_pred}, 损失: {loss}")

3. 手动计算梯度(反向传播)

python 复制代码
# 计算中间梯度
dL_dy_pred = y_pred - y  # ∂L/∂ŷ

# 计算参数梯度
dL_dw1 = dL_dy_pred * x[0]  # ∂L/∂w1 = ∂L/∂ŷ * ∂ŷ/∂w1
dL_dw2 = dL_dy_pred * x[1]  # ∂L/∂w2 = ∂L/∂ŷ * ∂ŷ/∂w2
dL_db = dL_dy_pred         # ∂L/∂b = ∂L/∂ŷ * ∂ŷ/∂b

print(f"梯度: ∂L/∂w1 = {dL_dw1}, ∂L/∂w2 = {dL_dw2}, ∂L/∂b = {dL_db}")

4. 参数更新(手动实现 optimizer.step ())

使用梯度下降更新参数:

python 复制代码
learning_rate = 0.01

# 更新参数
w[0] = w[0] - learning_rate * dL_dw1
w[1] = w[1] - learning_rate * dL_dw2
b = b - learning_rate * dL_db

print(f"更新后的参数: w = {w}, b = {b}")

二、 PyTorch 自动微分

python 复制代码
import torch
import torch.nn as nn

# ===== PyTorch 自动微分实现 =====
# 创建模型和数据
net = nn.Sequential(nn.Linear(2, 1))
net[0].weight.data = torch.tensor([[0.5, 0.5]])  # 初始权重
net[0].bias.data = torch.tensor([0.1])          # 初始偏置

x_tensor = torch.tensor([[1.0, 2.0]], requires_grad=False)
y_tensor = torch.tensor([[3.0]])

# 前向传播
y_pred_tensor = net(x_tensor)
loss_tensor = nn.MSELoss()(y_pred_tensor, y_tensor)

# 反向传播
loss_tensor.backward()

print("\nPyTorch 自动微分结果:")
print(f"预测值: {y_pred_tensor.item()}, 损失: {loss_tensor.item()}")
print(f"梯度: ∂L/∂w1 = {net[0].weight.grad[0, 0].item()}, "
     f"∂L/∂w2 = {net[0].weight.grad[0, 1].item()}, "
     f"∂L/∂b = {net[0].bias.grad.item()}")

# ===== 手动实现结果 =====
print("\n手动实现结果:")
print(f"预测值: {y_pred}, 损失: {loss}")
print(f"梯度: ∂L/∂w1 = {dL_dw1}, ∂L/∂w2 = {dL_dw2}, ∂L/∂b = {dL_db}")

输出对比(假设学习率为 0.01)

python 复制代码
PyTorch 自动微分结果:
预测值: 1.6, 损失: 0.98
梯度: ∂L/∂w1 = 1.4, ∂L/∂w2 = 2.8, ∂L/∂b = 1.4

手动实现结果:
预测值: 1.6, 损失: 0.98
梯度: ∂L/∂w1 = 1.4, ∂L/∂w2 = 2.8, ∂L/∂b = 1.4

三、 总结

计算图的本质

无论使用 PyTorch 还是手动计算,梯度的流动路径都是由数学公式决定的。PyTorch 只是自动帮你构建了这个路径。
链式法则的核心作用

梯度从损失函数开始,通过链式法则逐层传递到每个参数。例如:

复制代码
∂L/∂w1 = (∂L/∂ŷ) * (∂ŷ/∂w1) = (ŷ - y) * x1

PyTorch 的自动微分

当你调用 loss.backward() 时,PyTorch 会:

  • 自动追踪从 loss 到 weight 和 bias 的所有操作路径。
  • 对每个操作应用链式法则计算局部梯度。
  • 将最终梯度存储在 weight.grad 和 bias.grad 中。