反向传播:神经网络如何更新权重
文章目录
- 反向传播:神经网络如何更新权重
-
- [1. 和梯度下降的关系](#1. 和梯度下降的关系)
- [2. 链式法则:为什么能「往回传」](#2. 链式法则:为什么能「往回传」)
- [3. 微型网络手算](#3. 微型网络手算)
-
- [3.1 前向](#3.1 前向)
- [3.2 前向( y = 0 y=0 y=0)](#3.2 前向( y = 0 y=0 y=0))
- [3.3 反向](#3.3 反向)
- [3.4 若 ReLU 关掉了通道](#3.4 若 ReLU 关掉了通道)
- [4. 一次完整训练迭代](#4. 一次完整训练迭代)
- [5. 训练时常见的三种故障](#5. 训练时常见的三种故障)
-
- [5.1 梯度消失(Vanishing gradients)](#5.1 梯度消失(Vanishing gradients))
- [5.2 梯度爆炸(Exploding gradients)](#5.2 梯度爆炸(Exploding gradients))
- [5.3 死 ReLU(Dead ReLU)](#5.3 死 ReLU(Dead ReLU))
- [6. Dropout:专门给网络用的正则](#6. Dropout:专门给网络用的正则)
- [7. 动手:NumPy 走通一轮反向](#7. 动手:NumPy 走通一轮反向)
- [8. 和专栏前文关系](#8. 和专栏前文关系)
- [9. 能力边界与常见误区](#9. 能力边界与常见误区)
-
- [9.1 适用边界](#9.1 适用边界)
- [9.2 常见误区](#9.2 常见误区)
- [10. 关键术语速查](#10. 关键术语速查)
- [11. 延伸阅读](#11. 延伸阅读)
- [12. 小结](#12. 小结)
摘要 :第 23、24 篇把网络的前向路径搭好了:加权和、激活、得到预测。训练还缺半边------损失怎样告诉每一层的 w , b w,b w,b「往哪改」。反向传播(Backpropagation) 用链式法则,把输出端的误差一层层传回输入端附近的参数,让第 03 篇的梯度下降在多层网络里也能跑。本文讲清前向 / 反向两趟、微型网络手算、梯度消失与死 ReLU 等常见坑,以及 Dropout。适合已理解激活函数的读者。
1. 和梯度下降的关系
第 3 篇的更新公式没有变:
w ← w − η ∂ L ∂ w w \leftarrow w - \eta \frac{\partial L}{\partial w} w←w−η∂w∂L
难的是:网络很深时, ∂ L / ∂ w \partial L/\partial w ∂L/∂w 不再是「一眼能写完」的式子。中间隔着好几层乘加和激活,要对靠输入的那批权重求导,必须把复合函数拆开。
反向传播 干的就是这件事:按计算图从损失往回走,用链式法则乘上每一段的局部导数,高效得到所有参数的梯度。框架(如常见的自动微分库)通常替你算完;专栏仍要搞清它在干什么,否则学习率、激活、层数出问题时会无从下手。
可以把它想成工厂质检:前向是成品装配,反向是根据不合格报告逐站追查该拧哪颗螺丝。螺丝很多时,不能每颗都从头拆整机------沿装配顺序的逆序传误差,才是可扩展的做法。

| 趟 | 方向 | 产出 |
|---|---|---|
| 前向 | 输入 → 输出 | 预测 y ′ y' y′、损失 L L L |
| 反向 | 损失 → 各层参数 | ∂ L / ∂ w \partial L/\partial w ∂L/∂w、 ∂ L / ∂ b \partial L/\partial b ∂L/∂b |
| 更新 | --- | 用学习率 η \eta η 改参数 |

2. 链式法则:为什么能「往回传」
设一条极简路径:
z = w x , a = ReLU ( z ) , y ′ = v a , L = 1 2 ( y ′ − y ) 2 z = w x,\quad a = \operatorname{ReLU}(z),\quad y' = v a,\quad L = \tfrac{1}{2}(y'-y)^2 z=wx,a=ReLU(z),y′=va,L=21(y′−y)2
要求 ∂ L / ∂ w \partial L/\partial w ∂L/∂w。链式法则:
∂ L ∂ w = ∂ L ∂ y ′ ⋅ ∂ y ′ ∂ a ⋅ ∂ a ∂ z ⋅ ∂ z ∂ w \frac{\partial L}{\partial w} = \frac{\partial L}{\partial y'} \cdot \frac{\partial y'}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w} ∂w∂L=∂y′∂L⋅∂a∂y′⋅∂z∂a⋅∂w∂z

每一段只依赖局部运算:
| 局部导数 | 含义 |
|---|---|
| ∂ L / ∂ y ′ = y ′ − y \partial L/\partial y' = y'-y ∂L/∂y′=y′−y | 预测偏高还是偏低 |
| ∂ y ′ / ∂ a = v \partial y'/\partial a = v ∂y′/∂a=v | 输出层权重 |
| ∂ a / ∂ z \partial a/\partial z ∂a/∂z | ReLU: z > 0 z>0 z>0 为 1,否则 0 |
| ∂ z / ∂ w = x \partial z/\partial w = x ∂z/∂w=x | 该权重对应的输入 |
反向传播按层复用中间结果,避免对每个权重从头展开整棵式子------层数一多,这种复用才关键。
数值上不必自己推到纸面极限:把「局部导数连乘」记熟,再对照框架里某层 grad 是否接近 0 或异常大,就能把第 5 节的三类故障对上号。
3. 微型网络手算
沿用汽车风格的小数:输入 x = 2.0 x=2.0 x=2.0(可理解为已缩放的重量),标签 y = 1.0 y=1.0 y=1.0(示意)。
隐藏一个神经元 + ReLU,再接到输出:
| 参数 | 初值 |
|---|---|
| w w w(输入→隐藏) | 0.5 0.5 0.5 |
| b b b | 0.0 0.0 0.0 |
| v v v(隐藏→输出) | 1.0 1.0 1.0 |
| c c c(输出偏置) | 0.0 0.0 0.0 |
3.1 前向
z = 0.5 × 2.0 + 0 = 1.0 a = ReLU ( 1.0 ) = 1.0 y ′ = 1.0 × 1.0 + 0 = 1.0 L = 1 2 ( 1.0 − 1.0 ) 2 = 0 \begin{aligned} z &= 0.5\times 2.0 + 0 = 1.0 \\ a &= \operatorname{ReLU}(1.0) = 1.0 \\ y' &= 1.0\times 1.0 + 0 = 1.0 \\ L &= \tfrac{1}{2}(1.0-1.0)^2 = 0 \end{aligned} zay′L=0.5×2.0+0=1.0=ReLU(1.0)=1.0=1.0×1.0+0=1.0=21(1.0−1.0)2=0
这次碰巧预测对了,梯度全 0,参数不动。把标签改成 y = 0 y=0 y=0,再走一遍。
3.2 前向( y = 0 y=0 y=0)
y ′ y' y′ 仍是 1.0 1.0 1.0, L = 1 2 ( 1 − 0 ) 2 = 0.5 L=\tfrac{1}{2}(1-0)^2=0.5 L=21(1−0)2=0.5。
3.3 反向
∂ L ∂ y ′ = 1.0 ∂ L ∂ v = ∂ L ∂ y ′ ⋅ a = 1.0 ∂ L ∂ a = ∂ L ∂ y ′ ⋅ v = 1.0 ∂ L ∂ z = ∂ L ∂ a ⋅ 1 z \> 0 = 1.0 ∂ L ∂ w = ∂ L ∂ z ⋅ x = 2.0 ∂ L ∂ b = ∂ L ∂ z = 1.0 \begin{aligned} \frac{\partial L}{\partial y'} &= 1.0 \\ \frac{\partial L}{\partial v} &= \frac{\partial L}{\partial y'}\cdot a = 1.0 \\ \frac{\partial L}{\partial a} &= \frac{\partial L}{\partial y'}\cdot v = 1.0 \\ \frac{\partial L}{\partial z} &= \frac{\partial L}{\partial a}\cdot 1_{z\>0} = 1.0 \\ \frac{\partial L}{\partial w} &= \frac{\partial L}{\partial z}\cdot x = 2.0 \\ \frac{\partial L}{\partial b} &= \frac{\partial L}{\partial z} = 1.0 \end{aligned} ∂y′∂L∂v∂L∂a∂L∂z∂L∂w∂L∂b∂L=1.0=∂y′∂L⋅a=1.0=∂y′∂L⋅v=1.0=∂a∂L⋅1z\>0=1.0=∂z∂L⋅x=2.0=∂z∂L=1.0
取 η = 0.1 \eta=0.1 η=0.1:
v ← 1.0 − 0.1 × 1.0 = 0.9 w ← 0.5 − 0.1 × 2.0 = 0.3 b ← 0.0 − 0.1 × 1.0 = − 0.1 \begin{aligned} v &\leftarrow 1.0 - 0.1\times 1.0 = 0.9 \\ w &\leftarrow 0.5 - 0.1\times 2.0 = 0.3 \\ b &\leftarrow 0.0 - 0.1\times 1.0 = -0.1 \end{aligned} vwb←1.0−0.1×1.0=0.9←0.5−0.1×2.0=0.3←0.0−0.1×1.0=−0.1
下一轮前向, y ′ y' y′ 会变小,朝 y = 0 y=0 y=0 靠近。多层网络只是把「 ∂ L / ∂ a \partial L/\partial a ∂L/∂a」继续拆到更前面的层,算法结构相同。
3.4 若 ReLU 关掉了通道
假设某次前向算出 z = − 0.3 z=-0.3 z=−0.3,则 a = 0 a=0 a=0,且 ∂ a / ∂ z = 0 \partial a/\partial z=0 ∂a/∂z=0,于是 ∂ L / ∂ w = 0 \partial L/\partial w=0 ∂L/∂w=0、 ∂ L / ∂ b = 0 \partial L/\partial b=0 ∂L/∂b=0。这一步里,输入侧权重收不到误差信号------这就是死 ReLU 的雏形。输出侧的 v v v 仍可能有梯度(若后面还有通路),但该隐藏单元本身暂时「听不见」损失在喊什么。
这也解释了为何初始化与学习率不能乱拧:一步把大量单元打进负区,等于空手练其中一半网络。
4. 一次完整训练迭代

text
取一个 batch
→ 前向得到 y' 与 L
→ 反向得到各层梯度
→ w,b 按学习率更新
→ 重复;用验证集做早停(第 21 篇)
损失仍可选 MSE(回归)或 Log Loss(分类,第 07 篇)。反向传播不绑定某一种损失,它只负责「在给定 L L L 时求梯度」。
批量训练时,先对 batch 内样本的梯度取平均(或求和再按约定缩放),再更新一次参数------与第 03、04 篇的 batch 思想一致。网络更深时,同一 η \eta η 可能显得过大,需要重新在验证集上搜。
5. 训练时常见的三种故障

5.1 梯度消失(Vanishing gradients)
靠近输入的层,梯度是很多「小于 1 的因子」连乘,可能变得极小,那些层几乎不更新。深层网络 + Sigmoid/tanh 饱和时更明显。第 24 篇推荐隐藏层用 ReLU,正是为了减轻这个问题。
5.2 梯度爆炸(Exploding gradients)
权重很大时,连乘结果过大,参数一步跳飞,损失尖峰(第 21 篇曲线)。可降低学习率;实践中也常用梯度裁剪、更好的初始化,以及后续会接触的归一化手段。
5.3 死 ReLU(Dead ReLU)
某单元长期 z < 0 z<0 z<0,输出恒为 0,反向时 ∂ a / ∂ z = 0 \partial a/\partial z=0 ∂a/∂z=0,梯度过不去,它可能一直醒不过来。学习率过大、初始化不当会加重。可减小 η \eta η,或改用 Leaky ReLU 等变体。
排查时可看:有多少比例的隐藏激活长期为 0?若接近「半边网络熄火」,先降学习率,再考虑换激活或检查输入是否未标准化(第 14 篇)------量纲奇怪时, z z z 更容易大面积掉进负区。
6. Dropout:专门给网络用的正则
第 07、21 篇讲过 L2。神经网络里还有常用的 Dropout:训练时按概率随机把一些神经元的激活置零,相当于每步都在训练一个略有缺失的子网络,减轻共适应、抑制过拟合。

| 丢弃率 | 含义 |
|---|---|
| 0 0 0 | 不用 Dropout |
| 接近 1 1 1 | 几乎全丢,学不动 |
| 中间值(如 0.2 0.2 0.2~ 0.5 0.5 0.5) | 常见试验区间,当超参用验证集选 |
推理时一般关闭 Dropout,并用合适的缩放保证输出期望一致(框架会处理)。Dropout 与 L2、早停可以一起用,但仍解决不了数据泄漏与划分错误(第 19 篇)。
直觉上,Dropout 强迫网络不能把宝押在某几个神经元上;这对参数很多的全连接层尤其有用。宽度很小的玩具网络上,Dropout 收益有限,甚至干扰拟合------仍以验证集为准。
7. 动手:NumPy 走通一轮反向
python
import numpy as np
# 单样本:x=重量示意, y=目标
x, y = 2.0, 0.0
w, b, v, c = 0.5, 0.0, 1.0, 0.0
eta = 0.1
# 前向
z = w * x + b
a = max(z, 0.0) # ReLU
y_pred = v * a + c
L = 0.5 * (y_pred - y) ** 2
print("forward:", dict(z=z, a=a, y_pred=y_pred, L=L))
# 反向
dL_dy = y_pred - y
dL_dv = dL_dy * a
dL_dc = dL_dy
dL_da = dL_dy * v
dL_dz = dL_da * (1.0 if z > 0 else 0.0)
dL_dw = dL_dz * x
dL_db = dL_dz
print("grads:", dict(dw=dL_dw, db=dL_db, dv=dL_dv, dc=dL_dc))
# 更新
w -= eta * dL_dw
b -= eta * dL_db
v -= eta * dL_dv
c -= eta * dL_dc
print("updated:", dict(w=w, b=b, v=v, c=c))
# 再前向看损失是否下降
z2 = w * x + b
a2 = max(z2, 0.0)
y2 = v * a2 + c
L2 = 0.5 * (y2 - y) ** 2
print("loss after one step:", L, "->", L2)
预期:一步之后 L L L 下降, y ′ y' y′ 向 0 0 0 靠近。真实项目用框架的 loss.backward() 即可,但亲手乘一遍链式法则,遇到「某层不学」时更好定位是消失、爆炸还是死 ReLU。
若把上面脚本放进循环跑几十步,并打印每步 L L L,就能看到与第 03 篇类似的下降曲线;加上验证集后,也能复现第 18、21 篇「训练还在降、验证已抬头」的分叉------那时该早停或加 Dropout,而不是继续猛降学习率到学不动为止。
8. 和专栏前文关系
| 篇章 | 在反向传播里的位置 |
|---|---|
| 第 3 篇 | 梯度下降更新公式 |
| 第 7 篇 | 分类用 Log Loss; + + + L2 |
| 第 23~24 篇 | 前向结构与激活,决定局部导数长什么样 |
| 第 18~21 篇 | 验证曲线、早停、复杂度,训练外环不变 |
自动微分让你很少手写 ∂ L / ∂ w \partial L/\partial w ∂L/∂w,但学习率、深度、激活、Dropout 仍要人来定。反向传播把「能训多层」变成日常,并不取消第 22 篇的检查清单。
汽车例子里:若用浅层网络预测 MPG 或是否高效,训练循环与逻辑回归相同------只是梯度来自更长的计算链。验证损失抬头时,优先查过拟合与学习率,而不是怀疑「反向传播公式写错了」(在框架里那极少是根因)。
9. 能力边界与常见误区
9.1 适用边界
- 本篇建立直觉与手算;卷积、注意力等结构的反向由框架完成,道理仍是链式法则。
- Batch Norm、进阶初始化等可缓解爆炸 / 消失,后续实践篇再展开。
- 小表格数据上,浅层网络 + 强基线往往够用,不必一上来很深。
9.2 常见误区
| 误区 | 正解 |
|---|---|
| 反向传播是另一种优化算法 | 它是算梯度的方法;优化仍是 GD / Adam 等 |
| 有框架就不用懂反向 | 不懂则难排查消失、死 ReLU、lr 过大 |
| 层越深一定越好训 | 更深更易消失 / 过拟合 |
| Dropout 推理时也开着 | 训练开、推理关(按框架默认) |
| 损失不降只怪反向传错了 | 先查数据、学习率、激活与标签 |
| 一次手算就会训生产模型 | 手算建立直觉;规模化靠框架与验证集 |
把反向传播学到手的标志,不是能默写长公式,而是能解释:这一步梯度从哪来、为何某层可能收不到、学习率该往大还是往小拧。
10. 关键术语速查
| 术语 | 含义 |
|---|---|
| 反向传播 | 用链式法则从损失回传各参数梯度 |
| 链式法则 | 复合函数求导:局部导数连乘 |
| 梯度消失 / 爆炸 | 靠前层梯度过小 / 过大 |
| 死 ReLU | 单元卡在负区,梯度长期为 0 |
| Dropout | 训练时随机丢弃激活以正则化 |
| 自动微分 | 框架按计算图自动求梯度 |
11. 延伸阅读
| 资源 | 适合看什么 |
|---|---|
| 专栏第 03 篇 | 梯度下降四步循环 |
| 专栏第 24 篇 | ReLU 与梯度消失直觉 |
| 专栏第 21 篇 | 训练曲线与早停 |
| NumPy | 手写微型反向时的数组运算 |
12. 小结
反向传播让多层网络也能做梯度下降:前向算损失,反向用链式法则得到 ∂ L / ∂ w \partial L/\partial w ∂L/∂w,再按学习率更新。手算微型例子是为了看清 ReLU 的局部导数如何切断或放行梯度;训练时还要提防消失、爆炸与死 ReLU,并用 Dropout、L2、早停控制过拟合。
text
前向:x → ... → y' → L
反向:L → ... → ∂L/∂w
更新:w ← w − η ∂L/∂w
下一篇做神经网络单元的练习向收束:用浅层网络去拟合非线性分隔,并把学习率、网络宽度、激活函数放在一起对照着调。
系列导航:
- 上一篇:【机器学习】(24)------ 神经网络激活函数
- 下一篇(预告):神经网络实践------浅层网络拟合非线性
如果本篇对你有帮助,欢迎点赞、收藏、关注博主,机器学习专栏持续更新中,下次更新不迷路。