news 2026/7/2 4:57:28

loss.backward() 到底在干什么?一篇讲透计算图与反向传播

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
loss.backward() 到底在干什么?一篇讲透计算图与反向传播

loss.backward() 到底在干什么?一篇讲透计算图与反向传播

整理说明:本文基于 B 站视频【第05讲《计算图与反向传播:梯度如何流动》】公开信息、课程逐字稿与配套资料进行原创整理。不是逐字转写,而是把核心概念、手算流程、代码练习和排错方法整理成科研小白可以照着学的教程。

视频来源:B站 @Ai学术叫叫兽
视频链接:https://www.bilibili.com/video/BV1y5Ko6DEcR/
视频时长:约 19 分 28 秒

很多同学第一次看到 PyTorch 里的这行代码:

loss.backward()

第一反应通常是:这是不是一个“魔法按钮”?

明明我们只看到一个 Loss,点一下backward(),模型里成千上万个参数突然就都有了梯度。哪个权重要变大,哪个偏置要变小,每个参数该改多少,好像模型自己都知道了。

但它不是魔法。

反向传播的本质其实很朴素:用计算图记录计算路线,再用链式法则沿着路线反向追责。

这一讲只解决一个核心问题:

模型预测错了以后,最终错误是怎么分摊到前面每一个参数上的?

如果你能把这个问题讲清楚,后面学深层神经网络、CNN、YOLO 训练、Loss 曲线、梯度消失和梯度爆炸,就不会只是在背术语。

文末也给大家整理了复盘清单和资料领取话术。PPT、讲义和动画资料可以无偿送给大家,适合课后反复对着复盘。


01 先建立一个画面:前向做题,反向追责

上一讲我们讲过一个最简单的神经元:

z = w·x + b a = sigmoid(z) L = loss(a, y)

它的前向过程很像学生做题:

输入x进来,模型用权重w和偏置b算出线性得分z,再通过 sigmoid 得到预测概率a,最后和真实标签y比较,得到 Loss。

这一步回答的是:

模型怎么做预测?

但训练真正关心的是下一步:

预测错了以后,模型怎么知道每个参数应该怎么改?

这就像考试总分低了,不能只说“考差了”。你还要追问:

问题在模型里对应什么
哪道题扣分最多?哪个计算节点对 Loss 影响大
是概念错,还是计算错?是前向输出异常,还是梯度传递异常
下次该补哪里?哪个参数该往什么方向更新
是小修小补,还是大幅调整?梯度大小和学习率共同决定更新步长

所以,反向传播可以先理解成一句话:

Loss 是最后的错误结果,计算图是路线图,链式法则是追责方法,梯度是每个参数收到的调整通知。


02 六个关键词:把反向传播拆成小白能懂的语言

反向传播难,很多时候不是因为公式本身难,而是几个词混在一起了。

我们先把 6 个核心概念讲清楚。

概念一句话理解小白记法
计算图用节点和箭头表示计算依赖关系计算路线图
前向传播从输入一路算到预测和 Loss模型先做一遍题
局部导数某个节点输出对输入的敏感程度每一小段有多敏感
链式法则把路径上的局部导数乘起来一段一段追影响
反向传播从 Loss 出发反向计算每个参数梯度从结果往回分责任
梯度Loss 对参数的变化率参数该往哪改、改多猛

把这几个词连起来,就是本讲最重要的一句话:

计算图记录计算路线,前向传播得到 Loss,局部导数描述每一小段敏感度,链式法则把敏感度串起来,反向传播把梯度传回参数,优化器再根据梯度更新参数。

这句话能顺口说出来,反向传播的主线就稳了。


03 为什么一定要画计算图?

很多初学者会问:既然最后都是求导,为什么不直接背公式?

因为神经网络不是一个短公式,而是一条很长的计算链。

以单神经元为例:

x, w, b → z → a → L

每个箭头表示一次依赖:

节点它从哪来它到哪去
x输入特征参与计算z
w权重参数参与计算z
b偏置参数参与计算z
zw·x + b送入 sigmoid
asigmoid(z)和标签比较算 Loss
Lloss(a, y)反向传播从这里开始

计算图的价值不只是“画得好看”,而是它能回答训练排错里最关键的三个问题:

  1. 这个变量从哪里来?
  2. 这个变量到哪里去?
  3. 如果 Loss 异常,错误信号能不能沿着这条路传回来?

真实训练里,很多问题并不是链式法则错了,而是计算图在某一步断了。

比如你不小心写了:

value=tensor.item()

或者把参与求导的张量转成了 NumPy 数组再参与计算,前面的梯度可能就断了。表面看 Loss 还在,实际上参数已经收不到有效梯度。

所以对科研小白来说,计算图不是可有可无的图示,而是训练排错地图。


04 手把手手算一遍:梯度到底怎么传到 w?

我们用一个小到能手算的例子:

z = w x + b a = sigmoid(z) L = (a - y)^2

前向传播按顺序算:

  1. x、w、b算出z
  2. z放进 sigmoid 得到a
  3. a和标签y比较得到L

现在问题来了:

如果 Loss 大了,怎么知道w应该怎么改?

反向传播不会从L一步跳到w,它会沿着计算图一段一段问:

L → a → z → w

每一段都问一个“敏感度”:

追问数学表达人话解释
Loss 对预测有多敏感?∂L/∂aa变一点,Loss 变多少
预测对线性得分有多敏感?∂a/∂zz变一点,sigmoid 输出变多少
线性得分对权重有多敏感?∂z/∂ww变一点,z变多少

链式法则就是把三段影响乘起来:

∂L/∂w = ∂L/∂a · ∂a/∂z · ∂z/∂w

为了让它更落地,我们带一个数字例子:

x = 2 w = 0.5 b = 0 y = 1 z = 0.5 × 2 + 0 = 1 a = sigmoid(1) ≈ 0.731 L = (0.731 - 1)^2 ≈ 0.072

各段导数:

∂L/∂a = 2(a - y) ≈ -0.538 ∂a/∂z = a(1-a) ≈ 0.197 ∂z/∂w = x = 2

所以:

∂L/∂w ≈ -0.538 × 0.197 × 2 ≈ -0.212

这个负号很重要。它表示:在当前位置,w增大一点,Loss 会下降。所以梯度下降更新时:

w ← w - α∂L/∂w

如果学习率α = 0.1

w_new = 0.5 - 0.1 × (-0.212) = 0.5212

也就是说,权重会被稍微调大一点。

这就是反向传播最核心的直觉:

最终错误不是凭空分给参数的,而是沿着前向计算走过的路,反方向追回去的。


05 PyTorch 里 backward() 做了什么?

很多人学反向传播,是从 PyTorch 这一套训练代码开始的:

optimizer.zero_grad()pred=model(x)loss=criterion(pred,y)loss.backward()optimizer.step()

这一段可以拆成 5 步:

代码对应机制小白解释
optimizer.zero_grad()清空旧梯度先把上次的责任通知清掉
pred = model(x)前向传播模型做题,得到预测
loss = criterion(pred, y)计算 Loss拿预测和答案对分
loss.backward()反向传播沿计算图反向计算梯度
optimizer.step()参数更新根据梯度真正改参数

注意两个最容易混的点:

第一,backward()只是计算梯度,它不会直接更新参数。

第二,真正改变参数的是optimizer.step()

你可以把训练想象成一次“批改作业”:

前向传播:学生先做题 计算 Loss:老师打分 反向传播:分析每一步错在哪里 优化器更新:根据分析结果调整学习方式

06 科研小白实操:用 20 行代码看见梯度

下面这个最小例子,建议你真的跑一遍。

代码文件我已经放在本文资料包里:

code_snippets/01_manual_scalar_backprop.py code_snippets/02_pytorch_autograd_backward.py

如果你只想先看 PyTorch 版,可以运行:

python code_snippets/02_pytorch_autograd_backward.py

核心代码如下:

importtorch x=torch.tensor(2.0)y=torch.tensor(1.0)w=torch.tensor(0.5,requires_grad=True)b=torch.tensor(0.0,requires_grad=True)z=w*x+b a=torch.sigmoid(z)loss=(a-y)**2loss.backward()print("z =",z.item())print("a =",a.item())print("loss =",loss.item())print("dL/dw =",w.grad.item())print("dL/db =",b.grad.item())

你会看到w.gradb.grad不再是空的。

这说明 PyTorch 已经根据计算图,帮你把Loss → a → z → w/b这条链路走完了。

建议你做 3 个小实验:

  1. w = 0.5改成w = -2.0,看看 Loss 和梯度怎么变。
  2. 把标签y = 1.0改成y = 0.0,观察梯度方向是否变化。
  3. loss.backward()后加一行print(w.grad),再运行两次,理解为什么训练循环里要zero_grad()

小白阶段不要急着改复杂模型。先把这个极简例子跑懂,你以后看 CNN 和 YOLO 的训练循环,会轻松很多。


07 梯度不是误差:这是很多人卡住的地方

这一讲里最容易混淆的一句话是:

误差告诉你错了,梯度告诉你往哪改。

它们不是一回事。

对比项误差 / Loss梯度
关注什么预测和标签差多少参数变化会怎样影响 Loss
作用衡量当前结果好不好指导参数往哪更新
例子这次考试扣了 20 分应该重点补哪类题
代码位置loss = criterion(pred, y)loss.backward()后的param.grad

如果只知道 Loss 大,你只知道模型错了。

但你不知道:

  1. 是哪个参数影响更大?
  2. 应该增大还是减小?
  3. 每个参数应该改大步还是小步?

这些信息都来自梯度。

所以调模型时,不要只盯着 Loss 曲线,也要学会检查梯度:

forname,pinmodel.named_parameters():ifp.gradisnotNone:print(name,p.grad.abs().mean().item())

如果很多层梯度接近 0,可能存在梯度消失、计算图断裂或学习信号太弱。

如果梯度特别大,Loss 还来回震荡,可能存在梯度爆炸或学习率过大。


08 梯度消失和梯度爆炸,为什么会出现?

深层网络里,梯度要经过很多层才能传回前面的参数。

每经过一层,都会乘上一个局部导数。

如果很多局部导数都小于 1:

0.5 × 0.5 × 0.5 × 0.5 × ... → 越乘越小

梯度就可能越来越小,这叫梯度消失。

如果很多局部导数都大于 1:

2 × 2 × 2 × 2 × ... → 越乘越大

梯度就可能越来越大,这叫梯度爆炸。

这就是为什么后面学深层神经网络时,要讨论:

  1. 激活函数怎么选
  2. 参数怎么初始化
  3. 学习率怎么设置
  4. 是否需要归一化
  5. 是否需要残差连接

它们不是“高级装饰”,而是在帮助梯度稳定流动。


09 真实训练排错:按这 5 步检查

很多科研小白一遇到训练异常,就马上想换模型、换优化器、换更大的网络。

先别急。

真实项目里,大量问题都出在数据、shape、标签和计算链路上。

建议按下面 5 步排查:

步骤你要问什么常见问题
1. 输入是什么进入模型的是图片、张量还是特征?通道顺序错、归一化错、batch 维丢失
2. 输出是什么输出是概率、logits、Loss 还是指标?把 logits 当概率、Loss 对象搞错
3. shape 对吗预测和标签形状是否匹配?[B, C][B]搞混
4. 梯度通吗param.grad是否存在、是否为 0?计算图断裂、忘记requires_grad
5. 参数更新了吗optimizer.step()后参数是否变化?忘记 step、学习率为 0、梯度被清空

最重要的是:

不要一上来就换模型。先确认输入、输出、中间变量、梯度、参数更新这条链路是通的。


10 结合图像任务理解:错误会传回前面的卷积核

放到图像模型里,反向传播就更有画面感了。

比如一个猫狗分类模型,把猫预测成了狗。

Loss 变大以后,错误信号不会只停在最后一层。

它会沿着计算图一路往回传:

分类输出 → 分类层权重 → 高级特征 → 中级特征 → 低级卷积核

前面的卷积核并不是天生会看边缘、纹理和形状。

它们一开始通常是随机初始化的。之所以后来能学出边缘、纹理、局部结构,是因为每一次预测错误都会通过反向传播把调整信号传回来。

这也解释了为什么标签质量非常重要。

如果标签错了,Loss 给出的方向就会偏;反向传播会非常认真地把这个错误方向传给参数。

模型不是故意学错,是你给它的学习信号错了。

所以做科研项目时,永远记住三件事:

  1. 数据是否正确
  2. 标签是否可靠
  3. 梯度是否能稳定传回前面的层

11 常见误区:别再这样理解反向传播

误区正确理解
反向传播是模型自己想明白了它是链式法则在计算图上的高效应用
梯度就是误差本身误差描述错多少,梯度描述往哪改
有 Loss 就一定能训练有 Loss 只能衡量错误,不代表梯度稳定
层数越深一定越好深层网络表达力更强,但梯度更难稳定传递
backward()会自动更新参数backward()算梯度,optimizer.step()才更新参数
Loss 不降就换模型先查数据、shape、标签、梯度和学习率

如果你刚入门,最该背的不是一堆公式,而是这句话:

前向传播让模型知道自己错了多少,反向传播让每个参数知道自己该怎么改。


12 随堂自测:3 道题判断你是否真的懂了

建议停 30 秒,自己答一下。

题 1:画出单神经元计算图

请画出:

z = w·x + b a = sigmoid(z) L = loss(a, y)

参考答案:

x, w, b → z → a → L

前向从左往右算,反向从右往左传梯度。

题 2:为什么链式法则适合多层网络?

因为多层网络本质上是很多函数一层一层嵌套起来。

前面参数不是直接影响 Loss,而是通过很多中间节点间接影响 Loss。链式法则可以把每一小段的局部影响乘起来,得到最前面参数对最终 Loss 的总影响。

题 3:误差和梯度有什么区别?

误差描述预测结果和标签差了多少。

梯度描述某个参数变化会怎样影响误差。

一句话:

误差告诉你错了,梯度告诉你往哪改。


13 课后按这个顺序学,别乱

如果你是科研小白,建议按下面 4 步复盘:

  1. 先看第 3 页核心定义表:把计算图、前向传播、局部导数、链式法则、反向传播、梯度讲顺。
  2. 再看第 5 页机制流程图:复述“前向计算 → 保存中间量 → 从 Loss 开始 → 局部反传 → 累积梯度 → 更新参数”。
  3. 然后手算第 6 页例子:用z=wx+b、a=sigmoid(z)、L=(a-y)^2推一遍∂L/∂w
  4. 最后跑本文代码:观察loss.backward()w.grad怎么出现。

如果你能做到这 4 件事,这一讲就过关了。


14 一句话总结

本讲可以压缩成一条训练链路:

计算图记录路线 前向传播得到 Loss 局部导数描述每一小段敏感度 链式法则把敏感度串起来 反向传播把梯度传回参数 优化器根据梯度更新参数

再压缩成一句人话:

前向是数据流,反向是梯度流;前向产生错误,反向分摊责任。

下一讲会进入向量化和 Batch:当样本很多、参数很多时,如何用矩阵一次性高效计算。

如果你想系统学习这套“从深度学习到 YOLO26”的课程,可以关注我。第05讲的 PPT、讲义、动画和本文代码练习都可以无偿送给大家。建议收藏本文,课后对着图和代码再走一遍,反向传播就不再是黑盒了。


版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/2 4:56:16

【从0到1构建一个ClaudeAgent】规划与协调-子Agent

在 原作者的Python代码 里,run_subagent 函数就像一个“虫洞”,把任务传送到一个新的平行宇宙(子线程/子上下文)去执行,执行完只带回结果。在 Java 中,我们通常通过创建新的类实例来实现这种隔离。父 Agent…

作者头像 李华
网站建设 2026/7/2 4:55:42

从算卦到具身:一套跨越三千年的“不确定系统建模”抽象

将东方古典象数哲学与现代前沿物理/人工智能架构进行深度互译。从算卦到具身:一套跨越三千年的“不确定系统建模”抽象 在过去的三千年里,人类文明一直在用两种截然不同的语言,追问同一个问题: 在一个充满随机性、非线性和熵增的宇…

作者头像 李华
网站建设 2026/7/2 4:54:39

鸿蒙HarmonyOS应用架构实战 —— Navigation 外壳、悬浮 TabBar 与页面转场全解析

一、前言:应用架构的第一性原理 做鸿蒙应用开发,最容易被忽视但也最重要的事情是:先把应用外壳(AppShell)搭对。 很多开发者上来就写业务页面,结果发现: 标题栏风格不统一,有的手写、有的用系统 页面返回逻辑混乱,Router 和 Navigation 混用 Tab 切换和页面跳转的…

作者头像 李华
网站建设 2026/7/2 4:53:33

Attention Sinks and Compression Valleys in LLMs are Two Sides of the Same Coin

paper: https://arxiv.org/pdf/2510.06477 ICLR 2026 一句话概括 这篇论文想说明:LLM 中的 attention sink 和 compression valley 不是两个孤立现象,而是同一个底层机制的两种表现,这个机制就是 residual stream 中某些 token,尤…

作者头像 李华
网站建设 2026/7/2 4:52:02

射频实验室“三件套“到底怎么分工?别再把VNA当频谱仪用

很多刚入行的射频工程师,第一次进实验室面对矢量网络分析仪、频谱分析仪、信号发生器这三台"长得差不多"的大家伙,常常犯迷糊——都是射频测试,凭啥要三台?能不能省一台?答案是不能。三者的测试边界完全不同…

作者头像 李华
网站建设 2026/7/2 4:51:59

深入学习Redis(1):Redis内存模型

Redis是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说Redis是实现网站高并发不可或缺的一部分。 我们使用Redis时,会接触Redis的5种对象类型(字符串、哈希、列表、集合、有序集合&…

作者头像 李华