掘金 人工智能 09月17日
PyTorch 反向传播原理图解与代码解析
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文旨在为初学者深入浅出地讲解PyTorch中反向传播的实现原理。通过生活化比喻(如开餐馆调配方)、图解计算图、以及详细的代码示例,文章清晰地阐述了前向传播、反向传播(利用链式法则计算梯度)和参数更新的完整流程。重点介绍了PyTorch的autograd自动微分系统如何通过计算图自动求导,并解答了梯度累积、标量损失等常见问题,最后提炼出反向传播的“清零-前向-反传-更新”四步黄金流程。

🎯 **生活化比喻与核心概念**:文章以“开餐馆调配方”为喻,将神经网络参数比作调料,损失值比作顾客打分。反向传播被形象地描述为“智能调料顾问”,通过倒推计算出每种“调料”(参数)对最终“打分”(损失)的影响大小,即梯度,从而指导优化器调整参数以减小损失。

📈 **PyTorch 反向传播三步走**:1. **前向传播**:计算预测值并得出损失。2. **反向传播**:调用 `loss.backward()`,PyTorch 利用链式法则通过计算图自动计算每个参数的梯度,并存储在 `.grad` 属性中。3. **更新参数**:在 `torch.no_grad()` 上下文中,根据梯度和学习率更新参数,随后必须调用 `zero_grad()` 清空梯度以准备下一次迭代。

🔗 **计算图(Computational Graph)**:PyTorch 在前向传播时构建一个动态计算图,记录所有操作和张量之间的依赖关系。反向传播时,从损失节点出发,沿着图的反向路径,利用内置的导数公式和链式法则高效地计算出所有叶子节点的梯度。

💡 **关键细节与常见问题**:文章强调了每次反向传播前必须调用 `zero_grad()` 避免梯度累积;解释了损失函数必须是标量才能直接调用 `backward()`,否则需要提供权重;区分了 `.backward()` 和 `torch.autograd.grad()` 的用法,并总结了训练神经网络的“清零-前向-反传-更新”四步黄金流程。

我们用生活化比喻 + 图解 + 代码示例 + 分步拆解,向初学者彻底讲清楚:


🎯 PyTorch 中反向传播(Backpropagation)的实现原理 —— 通俗易懂版

💡 一句话总结:反向传播 = PyTorch 帮你自动算“每个参数对最终损失的影响有多大”,然后告诉优化器怎么调参数让损失变小!


一、生活化比喻:开餐馆调配方 🍜

你开了一家拉面馆,顾客打分(损失值)不太高。

你想改进配方 → 需要知道:

反向传播 = 你的“智能调料顾问”
它尝一口最终成品(损失),然后倒着推算
“这次打分低,主要是盐放多了 → 下次少放0.5克!”
“酱油影响不大,保持原样。”
“煮面时间很关键,多煮5秒分能涨!”

👉 它不是尝每一种调料组合(太慢),而是用数学倒推每种调料的“影响力”(梯度)


二、神经网络中的“调料” = 参数(weights, bias)

在神经网络中:


三、PyTorch 反向传播三步走(核心!)

✅ 步骤1:前向传播(做菜)

计算预测值 → 计算损失

import torchw = 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)y_pred = w * x + b        # 预测:2*3 + 1 = 7loss = (y_pred - y_true)**2  # 损失:(7-8)² = 1

✅ 步骤2:反向传播(顾问算梯度)

loss.backward()  # ← 关键!PyTorch 自动计算所有梯度

PyTorch 在后台做了什么?

    loss 开始,反向遍历计算图链式法则(Chain Rule)一层层求导:
      ∂loss/∂y_pred = 2*(y_pred - y_true) = 2*(7-8) = -2∂y_pred/∂w = x = 3 → 所以 ∂loss/∂w = ∂loss/∂y_pred * ∂y_pred/∂w = -2 * 3 = -6∂y_pred/∂b = 1 → 所以 ∂loss/∂b = -2 * 1 = -2
    把结果存到 .grad
print(w.grad)  # tensor(-6.) ← “盐”的梯度print(b.grad)  # tensor(-2.) ← “酱油”的梯度

📌 梯度含义

    w.grad = -6 → 如果 w 增加1,loss 会减少6(因为负号)→ 应该增加 w!b.grad = -2 → 同理,应该增加 b!

✅ 步骤3:更新参数(按建议调配方)

learning_rate = 0.1with torch.no_grad():  # 更新参数时,不记录梯度    w -= learning_rate * w.grad  # w = 2.0 - 0.1*(-6) = 2.0 + 0.6 = 2.6    b -= learning_rate * b.grad  # b = 1.0 - 0.1*(-2) = 1.0 + 0.2 = 1.2# 别忘了清空梯度!w.grad.zero_()b.grad.zero_()

下次预测:y_pred = 2.6*3 + 1.2 = 9.0loss = (9-8)² = 1(咦?变大了?别急,学习率可能太大,或需要更多轮)


四、PyTorch 如何实现自动求导?—— 计算图(Computational Graph)

PyTorch 在前向传播时,偷偷画了一张“操作流程图”

     w      \       * → y_pred → ( - ) → ( **2 ) → loss      /           /    x           y_true     \      b

当你调用 loss.backward()

    loss 节点开始反向遍历图对每个操作(**2, -, *, +),PyTorch 内置了导数公式用链式法则组合:∂loss/∂w = ∂loss/∂y_pred * ∂y_pred/∂w

✅ 就像你有“乘法求导公式”、“平方求导公式”,PyTorch 什么操作的导数都会!


五、代码完整示例(带循环)

import torch# 参数(调料)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)learning_rate = 0.01for step in range(100):    # 1️⃣ 前向传播    y_pred = w * x + b    loss = (y_pred - y_true) ** 2    # 2️⃣ 反向传播    loss.backward()    # 3️⃣ 更新参数    with torch.no_grad():        w -= learning_rate * w.grad        b -= learning_rate * b.grad    # 4️⃣ 清空梯度(必须!)    w.grad.zero_()    b.grad.zero_()    if step % 20 == 0:        print(f"Step {step}: w={w.item():.3f}, b={b.item():.3f}, loss={loss.item():.3f}")# 输出:# Step 0: w=2.000, b=1.000, loss=1.000# Step 20: w=2.360, b=1.120, loss=0.130# Step 40: w=2.504, b=1.168, loss=0.017# Step 60: w=2.562, b=1.187, loss=0.002# Step 80: w=2.585, b=1.195, loss=0.000

✅ 看!参数自动调整,损失越来越小!


六、为什么需要“计算图”?


七、常见问题解答(初学者必看!)

❓ 1. 为什么梯度会“累积”?为什么要 zero_grad()

w = torch.tensor(2.0, requires_grad=True)loss1 = w ** 2loss1.backward()print(w.grad)  # tensor(4.)loss2 = w * 3loss2.backward()print(w.grad)  # tensor(7.) ← 4 + 3!梯度累加了!

必须在每次 .backward() 前清零

optimizer.zero_grad()  # 或 w.grad.zero_()loss.backward()

🧠 比喻:顾问上次的建议还没清空,这次又加新建议 → 会混乱!


❓ 2. 为什么 loss 必须是标量(一个数)?

w = torch.tensor([2.0, 3.0], requires_grad=True)y = w ** 2  # [4., 9.]y.backward()  # ❌ 报错!

✅ 必须传一个“权重”:

y.backward(torch.tensor([1.0, 1.0]))  # 相当于对 y.sum() 求导print(w.grad)  # tensor([4., 6.]) → 2w 在 w=2,3 处

🧠 比喻:顾客给了多个打分(向量),顾问不知道按哪个优化 → 你要告诉它“综合打分 = 打分1 + 打分2”


❓ 3. .backward()torch.autograd.grad() 有什么区别?


八、总结:反向传播四步黄金流程

在训练神经网络时,永远记住这四步:

for data in dataloader:    optimizer.zero_grad()       # 1️⃣ 清空旧梯度        outputs = model(inputs)     # 2️⃣ 前向传播    loss = criterion(outputs, labels)        loss.backward()             # 3️⃣ 反向传播 → 自动计算梯度        optimizer.step()            # 4️⃣ 用梯度更新参数

🎁 给初学者的终极口诀:

“清零 → 前向 → 反传 → 更新”
“梯度是参数调整的方向盘”
“PyTorch 是你的自动求导小助手”


🎉 恭喜你!现在你已经彻底理解了反向传播的原理和实现!
这不是魔法,而是链式法则 + 计算图 + 自动微分的工程奇迹!

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

PyTorch 反向传播 Backpropagation 自动微分 Autograd 计算图 Computational Graph 深度学习 Deep Learning 梯度下降 Gradient Descent 神经网络 Neural Networks
相关文章