反向传播

让误差从输出一点点传回参数,链式法则在神经网络里的优雅展开。

知识课 · 约 30 分钟 · 更新于 2026-06-06

回顾:单层网络梯度怎么算?

在线性回归里,损失函数关于参数的导数可以直接写出。比如 、 ,那么:

这种"直接求导"之所以可行,是因为 与 直接出现 在 的表达式里。

MLP 训练的难点

但 MLP 不是这样。再看上节课的两层网络——把每一步的计算和它在做什么并排放:

想更新第一层的参数 ,需要 。 但 不直接 出现在 中,它藏在四层嵌套( )背后。

怎么办?

链式法则:把远距离导数拆成近距离连乘

高数中我们学过:复合函数 求导, 其导数等于"外层函数对中间变量的导数"乘以"中间变量对自变量的导数":

把这套机制套用到 MLP 上,就能把 拆开——这是全文最关键的一行:

阅读时先认准公式里每个变量的颜色,再到下方动画中找到同色节点, 沿着光点走一遍,把"公式里的因子"和"节点上的运算"一一对上。

每一项都是 近距离的导数 ,可以用基本求导法则直接算出来。 把它们乘起来,就拿到了远距离的整体梯度。

这就是 反向传播 (Backpropagation)的核心思想—— 没什么神秘,就是 链式法则在神经网络上的工程化应用 。

看见两个方向的"流"

把整张计算管道画成 5 个节点:输入 、 中间表示 、 、 与终点 。 点击下方的「正向」可以看到信号从输入一路计算到 loss; 「反向」则让梯度从 loss 端逐段流回输入。 光点每到达一个新节点,节点上方就会弹出本层的公式, 上一节点的公式同时淡出——正向时显示该层的前向计算式, 反向时显示该处的局部导数。

链式法则的隐患:梯度消失与梯度爆炸

链式法则把远距离梯度变成 近距离导数的连乘 ——这是好消息(可机械化求导), 但同时埋了一颗雷:连乘对每一项都很敏感,一旦每一层的局部导数都 偏小 或 偏大 , 传到深处就会指数级地走向极端。

粗略估一下:假设每一层的局部导数模长大致都是 ,从 loss 反传 层之后,梯度的量级近似为:

关键就在 这一项:只要每层的 稳稳偏离 1,传到深处就会被层数 放大成指数级的差距。

  • → 梯度 指数衰减为 0 ( vanishing gradient ), 深层参数几乎收不到学习信号
  • → 梯度 指数爆炸到无穷 ( exploding gradient ), 一次更新就把权重打飞

给两个直观的数字感:哪怕 只是 0.9 ,传过 50 层之后梯度就只剩 倍; 反过来 同样 50 层就放大到 倍。 每层只稍稍偏离 1,到深处就是几个数量级的差距。

最典型的例子是 sigmoid:它在大多数输入区域的导数 ,叠十几层 就已经接近 0——这正是 80 年代神经网络 "训练不深" 的根本原因。 ReLU 之所以取代 sigmoid 成为主流,关键就在于它在正区导数恒为 1, 从结构上缓解了梯度消失 ; 而梯度爆炸则常用 梯度裁剪 (gradient clipping)把每次反传的梯度模长压在阈值之内。 更彻底的解决方案——残差连接(ResNet)、归一化(BatchNorm / LayerNorm)等——会在后续课程里展开。

实践:手推一个最小 MLP 的前向 / 反向

我们用一个最小的网络做完整的手推。结构:

给定具体的输入和权重,先正向算出每个中间变量的值, 再反向倒推每一层的梯度,最后用代码与 PyTorch 自动求导对照—— 如果手推无误, .backward() 给出的梯度应当与我们一致。

反向传播的优雅之处

反向传播之所以能扩展到亿参数模型,关键有三点:

  1. 结构对称 :反向传播的"管道" 与正向传播完全对称——每一层正向做了什么,反向就走相反方向, 再做一次"乘以本地导数"
  2. 计算复杂度同阶 :反向传播的总计算量 约等于一次正向传播—— 这意味着 训练成本只比推理高一倍多
  3. 可机械化 :每一层的本地导数都是固定的、可程序实现的, 无需人手推导——这是下一课「自动微分」要展开的话题