← 返回题目列表

反向传播(Backpropagation)是什么?它是怎么算梯度的?

高频 困难 第 12 / 25 题 更新于 2026/07/28
深度学习反向传播链式法则梯度

简化版

反向传播(Backpropagation) 是神经网络高效计算「损失对每个参数的梯度」的算法,是训练网络的核心。它的本质是链式法则:损失是一层层复合函数算出来的,要知道某个权重对损失的影响(梯度),就把损失的误差从输出层沿着网络一层层往回传,每经过一层用链式法则把梯度乘上该层的局部导数。关键在于**「从后往前」复用中间结果**——先算出输出层的误差,再逐层往前推算每层的梯度,避免了对每个参数单独求导的巨大重复计算。算出所有梯度后,优化器(SGD/Adam)就用它们更新权重。抓住主线:反向传播用链式法则从输出往输入复用中间梯度,算出每个参数的梯度。

详细版

要解决的问题: 网络有成千上万个参数,要算损失 L 对每个参数 w 的偏导 ∂L/∂w 来做梯度下降。逐个数值求导太慢,反向传播用链式法则一次高效算全部。

核心:链式法则

L 是复合函数:L = f(激活) = f(z) = f(Wa+b)
∂L/∂w = ∂L/∂a · ∂a/∂z · ∂z/∂w    ← 链式法则逐层相乘

两个阶段:

① 前向传播:输入→输出,逐层算 z、a,并缓存这些中间值
② 反向传播:从输出层的误差开始,逐层往前:
     - 算本层误差 δ(损失对该层 z 的梯度)
     - 用 δ 算本层权重梯度 ∂L/∂W、偏置梯度 ∂L/∂b
     - 把误差传给前一层

关键思想: 从后往前,复用后一层已算好的梯度(δ),避免重复计算——这让梯度计算复杂度和前向传播一个量级。

完整版教学

一、问题:几百万参数,怎么高效算梯度

训练神经网络用梯度下降:w ← w - η·∂L/∂w。这要求算出损失 L 对每一个参数 w 的偏导数(梯度)。现代网络动辄几百万、上亿个参数,如果对每个参数单独做数值求导(微扰一下看损失变化),计算量是天文数字,根本不可行。

反向传播就是高效计算所有参数梯度的算法——它利用网络「层层复合」的结构和链式法则,通常用一次前向建立计算图并缓存 + 一次反向遍历,就能算出全部参数的梯度,算术代价通常是前向传播的常数倍,同时要承担保存或重算中间激活的内存代价。它是深度学习能训练起来的基石。

二、核心工具:链式法则

神经网络的损失是一个层层嵌套的复合函数:损失依赖输出层激活,输出层激活依赖它的加权和 z,z 依赖权重 W 和上一层激活,上一层激活又依赖更前面的……

要算「某个权重 w 对损失 L 的影响 ∂L/∂w」,就要沿着这条依赖链,用链式法则把一路的导数连乘起来:

∂L/∂w = ∂L/∂a · ∂a/∂z · ∂z/∂w
        └损失对激活┘ └激活对z┘ └z对权重┘

链式法则是反向传播的全部数学基础——复合函数求导 = 各段局部导数相乘。反向传播只是把这个原理系统地、高效地应用到整个网络。

三、两个阶段:前向缓存 + 反向回传

反向传播配合前向传播分两步:

阶段一:前向传播。 输入从第一层算到输出层,得到预测和损失。过程中缓存每一层的中间值(z 和激活 a)——这些值在反向传播算梯度时要用到。

阶段二:反向传播。 从输出层开始,往输入方向逐层回传误差

  1. 先算输出层的误差:损失对输出层加权和 z 的梯度(记作 δ)。
  2. 用这个 δ,算出输出层的权重梯度 ∂L/∂W 和偏置梯度 ∂L/∂b
  3. 把误差传播到前一层:前一层的误差 δ 由后一层的 δ、连接权重、以及本层激活函数的导数算出。
  4. 逐层重复 2、3,直到第一层——每层都算出自己的权重和偏置梯度。

四、为什么叫「反向」+ 为什么高效

关键在于计算方向是从输出往输入(反向),而且复用后一层的结果

  • 某一层的误差 δ,可以由它后面一层已经算好的 δ 递推得到(乘上权重和激活导数)。所以只要从最后一层开始、一层层往前推,每层的梯度都能借用后一层的中间结果,不必从头重新算。
  • 如果反过来「从前往后」或对每个参数独立求导,会产生大量重复计算(同一段导数被反复算)。反向传播通过从后往前、缓存复用,把总计算量压到和前向传播一个量级——这就是它高效的本质(本质是动态规划式地复用子结果)。

核心心法:「反向」让同一中间节点的伴随量只需汇总一次,再复用于所有上游路径。

计算图必须先前向得到中间值,反向时才能从损失节点沿依赖关系逆序应用链式法则。同一中间节点被多条下游路径使用时,各路径贡献的梯度要相加后再继续传播。反向传播的算术成本通常是前向传播的常数倍,但为了保存激活会消耗额外内存,也可用梯度检查点以重计算换内存。

五、和梯度消失/爆炸的联系

反向传播里,梯度是一路连乘过来的(每经过一层乘上该层激活函数的导数和权重)。这个「连乘」结构直接导致了两个著名问题:

  • 如果每层导数都小于 1,连乘很多层后梯度指数级衰减→梯度消失(前面的层几乎学不到东西)。
  • 如果每层导数都大于 1,连乘后梯度指数级放大→梯度爆炸

所以激活函数的选择(ReLU 缓解消失)、权重初始化、BatchNorm、残差连接等,很多都是为了让反向传播的梯度连乘不至于消失或爆炸(详见梯度消失专题)。理解反向传播的连乘结构,就理解了这些技巧的动机。

六、用一个标量网络手算梯度并做有限差分核验

设单个样本 x=2,模型 ŷ=wx+b,初值 w=3,b=1,标签 y=5,损失 L=0.5(ŷ-y)²。前向得到 ŷ=7L=2;反向先算 ∂L/∂ŷ=ŷ-y=2,再得 ∂L/∂w=2×x=4∂L/∂b=2

x=2 --×w=3--> +b=1 --> ŷ=7 --> L=0.5(7-5)²=2
反向:1 -> ∂L/∂ŷ=2 -> ∂L/∂w=2×2=4,∂L/∂b=2

用中心差分检查 w:取 ε=10⁻⁴[L(w+ε)-L(w-ε)]/(2ε) 约等于 4,与反向结果一致。梯度检查适合验证自定义算子,但数值误差、非光滑点和浮点精度会影响结果,不能替代正常训练。

记忆钩子:前向保存“值”,反向传播“值对损失的敏感度”;算梯度和用梯度更新是两件事。

七、常见误区与追问

  • 误区:反向传播就是梯度下降。 反向传播负责求导,SGD、Adam 等优化器才负责使用梯度更新参数。
  • 误区:反向传播必须为每个参数重新走一遍网络。 反向模式自动微分会在计算图上复用中间伴随量,一次反向可得到标量损失对全部参数的梯度。
  • 追问:为什么前向激活占显存? 许多局部导数依赖输入或输出,反向前必须保存;梯度检查点用重算换显存。
  • 追问:分支计算图的梯度怎么处理? 同一节点从多条下游路径收到的梯度按链式法则相加。
  • 追问:什么时候选前向模式自动微分? 输入维度很小、输出维度很大时更合适;标量损失对海量参数通常用反向模式。

八、加强记忆

反向传播是高效计算损失对每个参数梯度的算法,本质是链式法则:损失是层层复合函数,∂L/∂w = ∂L/∂a·∂a/∂z·∂z/∂w 逐段导数连乘。分两阶段:前向传播算预测并缓存各层中间值 → 反向传播从输出层误差开始、逐层往前用链式法则算每层权重/偏置梯度并把误差传给前层。「反向」是为了复用后一层已算好的梯度、避免重复计算,使复杂度和前向同量级(动态规划思想)。梯度逐层连乘的结构直接导致梯度消失(导数<1连乘衰减)/爆炸(>1放大),这也是 ReLU、权重初始化、BatchNorm、残差连接的动机。算完梯度后由优化器(SGD/Adam)更新权重