反向传播计算梯度举例
下面通过一个两层全连接神经网络 的完整数值案例,一步步演示反向传播(Backpropagation)计算梯度的全过程,核心思路是利用链式法则,从输出损失向输入层逐层反向传递误差,最终得到所有参数的梯度。
一、示例网络与初始设定
我们构造一个极简的神经网络:
-
输入层:2 个神经元 x1=2, x2=3
-
隐藏层:1 个神经元,参数 w1=0.5, w2=0.3, b1=0.1,激活函数为 Sigmoid: σ(z)=1+e−z1
-
输出层:1 个神经元,参数 w3=0.4, b2=0.2,激活函数为 Sigmoid
-
目标值: t=1
-
损失函数:均方误差 L=21(y−t)2(乘以 21 是为了求导消去系数,不影响梯度方向)
变量之间的依赖关系(链式法则就是沿着这条路径把局部导数乘起来):
隐藏层参数 w1,w2,b1⟶zh σ h w3, b2 zy σ y⟶L
- w3, b2 经过 3 步影响 L: zy→y→L
- w1, w2, b1 经过 5 步影响 L: zh→h→zy→y→L
二、第一步:前向传播(缓存中间结果)
反向传播依赖前向传播的中间值,因此先正向计算每一层的净输入和激活输出,并全部保存下来。
-
隐藏层净输入 zh=w1x1+w2x2+b1=0.5×2+0.3×3+0.1=2.0
-
隐藏层激活输出 h=σ(zh)=1+e−21≈1+0.13531≈0.8808
-
输出层净输入 zy=w3h+b2=0.4×0.8808+0.2≈0.5523
-
输出层最终预测 y=σ(zy)=1+e−0.55231≈1+0.57561≈0.6347
-
计算当前损失 L=21(y−t)2=21(0.6347−1)2≈0.0667
三、第二步:反向传播(逐层求梯度)
我们的目标是求损失 L 对所有参数 w1,w2,b1,w3,b2 的偏导数(梯度)。
定义误差项 δ=∂z∂L:表示损失对该层净输入的偏导,是反向传播的核心载体。
0. 要用到的三个基本导数
① 损失对预测值的导数
L=21(y−t)2⇒∂y∂L=21⋅2(y−t)⋅1=y−t
② Sigmoid 的导数
σ(z)=1+e−z1=(1+e−z)−1
对 z 求导(复合函数求导):
σ′(z)=−1⋅(1+e−z)−2⋅(−e−z)=(1+e−z)2e−z=1+e−z1⋅1+e−ze−z
其中第二个分式可以改写为:
1+e−ze−z=1+e−z(1+e−z)−1=1−1+e−z1=1−σ(z)
所以:
σ′(z)=σ(z)(1−σ(z))
前向传播时 σ(z) 已经存下,反向时可以直接用输出值算导数,不用再算指数:
∂zy∂y=y(1−y),∂zh∂h=h(1−h)
③ 线性部分的导数
对净输入求偏导时,只把要求导的变量看成变量,其他都当常数。
由 zy=w3h+b2:
∂w3∂zy=h,∂b2∂zy=1,∂h∂zy=w3
由 zh=w1x1+w2x2+b1:
∂w1∂zh=x1,∂w2∂zh=x2,∂b1∂zh=1
1. 输出层梯度(w₃, b₂)
输出层误差项由链式法则拆分为「损失对输出的偏导 × 激活函数导数」:
δy=∂zy∂L=∂y∂L⋅∂zy∂y
-
损失对预测值的偏导: ∂y∂L=y−t=0.6347−1=−0.3653
-
Sigmoid 导数性质: σ′(z)=σ(z)(1−σ(z)),因此: ∂zy∂y=σ′(zy)=y(1−y)=0.6347×0.3653≈0.2319
代入得输出层误差项:
δy=−0.3653×0.2319≈−0.0847
∂L/∂w₃ 的完整推导
第 1 步:写出链式法则 (路径 w3→zy→y→L)
∂w3∂L=∂y∂L⋅∂zy∂y⋅∂w3∂zy
第 2 步:代入每一项的局部导数
∂w3∂L=(y−t)⋅y(1−y)⋅h
第 3 步:前两项合并为误差项 δy
∂w3∂L=δy (y−t)y(1−y)⋅h⇒∂w3∂L=δy⋅h
第 4 步:代入数值
权重梯度 = 误差项 × 该层输入(隐藏层输出 h):
∂w3∂L=δy⋅h≈−0.0847×0.8808≈−0.0746
∂L/∂b₂ 的完整推导
路径相同,只是最后一步换成对 b2 求导:
∂b2∂L=∂y∂L⋅∂zy∂y⋅∂b2∂zy=δy⋅∂zy/∂b2 1
偏置梯度 = 误差项(偏置对净输入的导数为 1):
∂b2∂L=δy≈−0.0847
因为 zy=w3h+b2, b2 每增加 1, zy 就增加 1,所以偏置的梯度就是误差项本身,不用再乘任何输入。
2. 误差反向传递到隐藏层
隐藏层误差项需要先把输出层的误差"传回来",再乘以隐藏层的激活导数:
δh=∂zh∂L=∂h∂L⋅∂zh∂h
-
损失对隐藏层输出的偏导(误差从输出层回传): ∂h∂L=∂zy∂L⋅∂h∂zy=δy⋅w3≈−0.0847×0.4=−0.0339
-
隐藏层激活函数导数: ∂zh∂h=σ′(zh)=h(1−h)=0.8808×0.1192≈0.1050
代入得隐藏层误差项:
δh=−0.0339×0.1050≈−0.00356
∂L/∂w₁ 的完整推导
第 1 步:写出完整的链式法则 (路径 w1→zh→h→zy→y→L,共 5 项)
∂w1∂L=∂y∂L⋅∂zy∂y⋅∂h∂zy⋅∂zh∂h⋅∂w1∂zh
第 2 步:代入每一项
| 项 |
来源 |
值 |
| ∂y∂L |
损失求导 |
y−t |
| ∂zy∂y |
输出层 Sigmoid 导数 |
y(1−y) |
| ∂h∂zy |
zy=w3h+b2 对 h 求导 |
w3 |
| ∂zh∂h |
隐藏层 Sigmoid 导数 |
h(1−h) |
| ∂w1∂zh |
zh=w1x1+w2x2+b1 对 w1 求导 |
x1 |
∂w1∂L=(y−t)⋅y(1−y)⋅w3⋅h(1−h)⋅x1
第 3 步:分组,引出 δh
前两项是 δy,前四项合起来就是 δh:
∂w1∂L=δh δy (y−t)y(1−y)⋅w3⋅h(1−h)⋅x1⇒∂w1∂L=δh⋅x1
其中:
δh=∂L/∂h δy⋅w3⋅∂h/∂zh h(1−h)
- δy⋅w3:输出层的误差,按连接权重 w3 传回 到 h
- 再乘 h(1−h):穿过隐藏层的 Sigmoid,得到 δh
第 4 步:代入数值
权重梯度 = 误差项 × 对应输入值:
∂w1∂L=δh⋅x1≈−0.00356×2≈−0.00712
∂L/∂w₂ 的完整推导
前 4 项与 w1 完全相同(都是 δh),只有最后一项变成 ∂w2∂zh=x2:
∂w2∂L=δh ∂y∂L⋅∂zy∂y⋅∂h∂zy⋅∂zh∂h⋅∂w2∂zh=δh⋅x2
∂w2∂L=δh⋅x2≈−0.00356×3≈−0.01068
∂L/∂b₁ 的完整推导
最后一项变成 ∂b1∂zh=1,偏置梯度 = 误差项:
∂b1∂L=δh⋅1=δh≈−0.00356
3. 梯度公式汇总
把 δ 全部代回去,每个梯度都可以写成只含已知量的式子:
δy=(y−t)y(1−y),δh=δyw3h(1−h)
| 参数 |
用 δ 表示 |
完全展开 |
数值 |
| w3 |
δyh |
(y−t)y(1−y)h |
-0.0746 |
| b2 |
δy |
(y−t)y(1−y) |
-0.0847 |
| w1 |
δhx1 |
(y−t)y(1−y)w3h(1−h)x1 |
-0.00712 |
| w2 |
δhx2 |
(y−t)y(1−y)w3h(1−h)x2 |
-0.01068 |
| b1 |
δh |
(y−t)y(1−y)w3h(1−h) |
-0.00356 |
校验:用数值微分 ϵL(w1+ϵ)−L(w1) 计算 ∂w1∂L,结果约为 −0.0071148,与反向传播结果一致(表中 -0.00712 是用四舍五入后的 δh 计算的)。
四、第三步:梯度下降更新参数
得到所有梯度后,用梯度下降法更新参数(学习率 η=0.1 为例):
wnew=w−η⋅∂w∂L
所有参数的更新结果:
| 参数 |
旧值 |
梯度 |
新值 =w−0.1×∂w∂L |
| w3 |
0.4 |
-0.0746 |
0.40746 |
| b2 |
0.2 |
-0.0847 |
0.20847 |
| w1 |
0.5 |
-0.00712 |
0.50071 |
| w2 |
0.3 |
-0.01068 |
0.30107 |
| b1 |
0.1 |
-0.00356 |
0.10036 |
梯度都是负数,说明这些参数增大可以让损失变小,所以全部往上调。
更新后的损失
用新参数重新做一次前向传播:
-
隐藏层净输入 zh=0.50071×2+0.30107×3+0.10036≈2.0050
-
隐藏层激活输出 h=σ(2.0050)≈0.8813
-
输出层净输入 zy=0.40746×0.8813+0.20847≈0.5676
-
输出层最终预测 y=σ(0.5676)≈0.6382
-
更新后的损失 L=21(0.6382−1)2≈0.06545
|
更新前 |
更新后 |
变化 |
| 预测值 y |
0.6347 |
0.6382 |
更接近目标值 1 |
| 损失 L |
0.06673 |
0.06545 |
下降约 1.9% |
所有参数沿梯度反方向更新后,损失值确实下降了。重复「前向 → 反向 → 更新」的循环,就是神经网络的训练过程。
为什么损失只下降了约 2%:梯度消失
对比两层的梯度:
- 输出层: ∂w3∂L≈−0.0746
- 隐藏层: ∂w1∂L≈−0.00712,小了约一个数量级
原因是隐藏层的梯度比输出层多乘了两个小于 1 的因子:
w3×h(1−h)=0.4×0.1050≈0.042
而 Sigmoid 的导数 σ(z)(1−σ(z)) 最大只有 0.25 (在 z=0 时取到),本例中 zh=2,导数只有 0.105。每往回传一层,梯度都要再乘一次这样的小数,网络越深,前面几层的梯度就越接近 0,参数几乎不更新,这就是梯度消失。这也是现代深度网络多用 ReLU 激活函数、并加入残差连接的原因。
五、反向传播核心规律总结
-
前向缓存 :前向传播必须保存每一层的净输入 z 和激活输出 a,反向时直接复用,避免重复计算。
-
误差反向流:误差从输出层向输入层传递,每一层误差 = 后一层误差 × 后一层权重 × 本层激活导数。
-
梯度公式:权重梯度 = 该层误差项 × 该层的输入值;偏置梯度 = 该层误差项。
-
高效性:反向传播的计算量和前向传播同阶,远优于逐个参数做数值求导,是深度网络训练的基础。