一文讲清 PyTorch 自动求导(Autograd)

37 阅读4分钟

我们用生活化比喻 + 简单代码 + 图解思维,向初学者彻底讲清楚:


🎯 PyTorch 自动求导(Autograd)—— 什么是?为什么用?怎么用?


一、一句话总结:

自动求导 = PyTorch 帮你自动算梯度,不用手写导数公式!

就像你开车不用自己造发动机,PyTorch 的 autograd 系统帮你自动计算神经网络中每个参数的“变化方向”,让模型能自己学习!


二、生活化比喻:登山向导 🧭

想象你是一个登山者(模型),站在一座雾气弥漫的山上(损失函数曲面),你想最快下山(最小化损失)。但你看不清路!

PyTorch 自动求导 = 你的智能登山向导
它会告诉你:“现在往左前方倾斜 30 度,坡度最陡,下降最快!” —— 这个“方向+坡度”,就是梯度(gradient)

你不用自己拿纸笔算山坡导数,向导(autograd)自动帮你算好!


三、为什么需要自动求导?

在机器学习/深度学习中,我们要:

  1. 定义一个模型(比如 y = w * x + b)
  2. 定义一个损失函数(比如预测值和真实值的差距)
  3. 调整参数(w, b)让损失变小 → 需要知道损失对 w 和 b 的导数(梯度)
  4. 用梯度下降更新参数:w = w - lr * grad_w

🔍 问题:如果模型有百万参数,手写导数?不可能!

✅ 解决方案:PyTorch 自动求导系统(autograd)自动帮你算所有梯度!


四、核心概念三要素

概念说明
requires_grad=True告诉 PyTorch:“这个张量是我需要求梯度的参数!”
.backward()“开始反向传播,计算所有梯度!”
.grad存放计算好的梯度值(导数)

五、代码示例:从 0 学会自动求导

🧮 例子:计算 y = x² 在 x=3 处的导数

我们知道:dy/dx = 2x → x=3 时,导数应为 6。

import torch

# 1. 创建张量,设置 requires_grad=True —— “我要对它求导!”
x = torch.tensor(3.0, requires_grad=True)

# 2. 定义计算过程(前向传播)
y = x ** 2  # y = x²

# 3. 反向传播 —— 自动计算梯度
y.backward()  # 相当于 dy/dx

# 4. 查看梯度
print(x.grad)  # 输出:tensor(6.) ✅ 正确!

📈 例子2:带多个变量 —— y = a * x + b

import torch

x = torch.tensor(2.0)
a = torch.tensor(3.0, requires_grad=True)  # 要求导
b = torch.tensor(1.0, requires_grad=True)  # 要求导

y = a * x + b  # y = 3*2 + 1 = 7

y.backward()   # 自动计算 dy/da 和 dy/db

print("dy/da =", a.grad)  # dy/da = x = 2.0 → 输出:tensor(2.)
print("dy/db =", b.grad)  # dy/db = 1 → 输出:tensor(1.)

注意

  • 不是所有张量都需要梯度,只有你关心的参数(如神经网络权重)才设 requires_grad=True
  • backward() 默认只对标量(一个数)求导。如果是向量,要传 gradient 参数(后面讲)

六、在神经网络中的真实应用场景

import torch
import torch.nn as nn

# 定义一个简单线性模型
model = nn.Linear(1, 1)  # y = w*x + b

# 损失函数
loss_fn = nn.MSELoss()

# 优化器(它会用 .grad 来更新参数)
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# 假数据
x = torch.tensor([[1.0], [2.0], [3.0]])
y_true = torch.tensor([[2.0], [4.0], [6.0]])  # 真实值:y = 2*x

for epoch in range(100):
    optimizer.zero_grad()        # 1️⃣ 清空旧梯度

    y_pred = model(x)            # 2️⃣ 前向传播
    loss = loss_fn(y_pred, y_true)  # 计算损失

    loss.backward()              # 3️⃣ 自动求导!计算所有参数的梯度

    optimizer.step()             # 4️⃣ 用梯度更新参数 w 和 b

    if epoch % 20 == 0:
        print(f"Epoch {epoch}, Loss: {loss.item():.4f}")

📌 关键四步:

  1. zero_grad() —— 清除上一轮梯度(否则会累加!)
  2. 前向计算 → 得到 loss
  3. loss.backward() —— 自动计算所有 requires_grad=True 参数的梯度
  4. optimizer.step() —— 用梯度更新参数

七、常见问题 & 注意事项(初学者必看!)

❗ 1. 为什么梯度是累加的?

PyTorch 默认梯度累加(为了支持梯度累积等高级技巧),所以每次训练前必须清零

optimizer.zero_grad()
# 或者
model.zero_grad()

❗ 2. 什么时候用 requires_grad=True

  • 神经网络的参数(weights, bias) → 框架自动设置(如 nn.Linear
  • 你自己定义的需要优化的变量 → 手动设置
  • 输入数据(x)通常不需要求导 → 保持默认 False

❗ 3. 如果 y 不是标量怎么办?

x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x ** 2  # y = [4., 9.] —— 向量!

# ❌ 不能直接 y.backward()!
# ✅ 要传一个权重向量(通常用于多输出)
y.backward(torch.tensor([1.0, 1.0]))  # 相当于对 y.sum() 求导

print(x.grad)  # 输出:tensor([4., 6.]) → 2x 在 x=2,3 处

💡 简单记:loss 一定要是标量(一个数),比如 loss.mean()loss.sum()


八、图解自动求导(计算图)

PyTorch 在后台为你构建“计算图”:

x (requires_grad=True)
│
▼
y = x ** 2
│
▼
loss = y  → 标量
│
▼
loss.backward() → 从 loss 开始,反向传播,计算 dy/dx

每个操作(+、*、sin、exp...)PyTorch 都知道怎么求导,自动链式法则组合!


九、总结:自动求导三步走

  1. 标记:对需要求导的张量设置 requires_grad=True
  2. 计算:进行前向计算,得到最终标量(如 loss)
  3. 反传:调用 .backward(),PyTorch 自动计算所有梯度,存到 .grad

🎁 给初学者的贴心提示:

  • ✅ 自动求导是深度学习的“发动机”,不用怕数学,PyTorch 帮你搞定导数!
  • ✅ 多写几个小例子(比如 y = sin(x), y = x * log(x)),亲手验证梯度
  • ✅ 调试时打印 .grad 看看值对不对,是很好的学习方式
  • ✅ 记住:zero_grad()forwardbackward()step() 是训练循环黄金四步!