现在我们已经介绍了损失函数、梯度下降和反向传播算法的理念,接下来通过手动计算一个非常小的神经网络的梯度来巩固这些认识。这个练习有助于直观了解链式法则如何运作,以弄清每个参数如何影响总误差。
考虑一个简单的网络,它有一个输入、一个隐藏神经元(使用Sigmoid激活函数)和一个输出神经元(也使用Sigmoid)。我们的目标是计算权重(w1, w2)和偏置(b1, b2)的变化如何影响单个训练样本的最终损失。
一个包含一个输入、一个隐藏神经元和一个输出神经元的简单前馈网络。
网络设置
我们来定义组件和初始值:
- 输入:x=0.5
- 目标输出:y=0.8
- 权重:w1=0.2, w2=0.9
- 偏置:b1=0.1, b2=−0.3
- 激活函数:Sigmoid,σ(z)=1+e−z1。其导数为σ′(z)=σ(z)(1−σ(z))。
- 损失函数:均方误差 (MSE),L=21(y−o)2。其对输出 o 的导数为∂o∂L=o−y。
1. 前向传播
首先,我们计算给定输入(x)和参数下网络的输出(o)。
- 隐藏层预激活值 (z1):
z1=w1x+b1=(0.2×0.5)+0.1=0.1+0.1=0.2
- 隐藏层激活值 (h):
h=σ(z1)=σ(0.2)=1+e−0.21≈1+0.81871≈0.5498
- 输出层预激活值 (z2):
z2=w2h+b2=(0.9×0.5498)+(−0.3)≈0.4948−0.3=0.1948
- 输出层激活值 (o):
o=σ(z2)=σ(0.1948)=1+e−0.19481≈1+0.82301≈0.5486
因此,网络的预测值为 o≈0.5486。
2. 损失计算
现在,使用MSE损失函数计算误差:
L=21(y−o)2=21(0.8−0.5486)2=21(0.2514)2≈21(0.0632)≈0.0316
此样本的损失约为 0.0316。
3. 反向传播 (梯度计算)
我们的目标是求出梯度:∂w2∂L、∂b2∂L、∂w1∂L 和 ∂b1∂L。我们使用链式法则,从损失反向推导。
-
损失对网络输出 (o) 的导数:
∂o∂L=o−y≈0.5486−0.8=−0.2514
-
输出层梯度 (w2,b2):
我们需要输出激活值 o 对其预激活值 z2 的导数。
∂z2∂o=σ′(z2)=o(1−o)≈0.5486×(1−0.5486)≈0.5486×0.4514≈0.2476
现在,应用链式法则求出损失对 z2 的梯度:
∂z2∂L=∂o∂L∂z2∂o≈(−0.2514)×(0.2476)≈−0.0622
w2 和 b2 的梯度取决于 z2 相对于它们的变化方式:
∂w2∂z2=h≈0.5498
∂b2∂z2=1
再次使用链式法则:
∂w2∂L=∂z2∂L∂w2∂z2≈(−0.0622)×(0.5498)≈−0.0342
∂b2∂L=∂z2∂L∂b2∂z2≈(−0.0622)×1=−0.0622
-
隐藏层梯度 (w1,b1):
我们需要将梯度进一步反向传播。首先,求出损失对隐藏激活值 h 的梯度:
∂h∂L=∂z2∂L∂h∂z2
我们需要∂h∂z2:
∂h∂z2=w2=0.9
所以,
∂h∂L≈(−0.0622)×0.9=−0.0560
接下来,我们需要隐藏激活值 h 对其预激活值 z1 的导数:
∂z1∂h=σ′(z1)=h(1−h)≈0.5498×(1−0.5498)≈0.5498×0.4502≈0.2475
现在,应用链式法则求出损失对 z1 的梯度:
∂z1∂L=∂h∂L∂z1∂h≈(−0.0560)×(0.2475)≈−0.0139
最后,w1 和 b1 的梯度取决于 z1 相对于它们的变化方式:
∂w1∂z1=x=0.5
∂b1∂z1=1
最后一次使用链式法则:
∂w1∂L=∂z1∂L∂w1∂z1≈(−0.0139)×0.5=−0.0070
∂b1∂L=∂z1∂L∂b1∂z1≈(−0.0139)×1=−0.0139
梯度总结
我们手动计算了损失函数相对于每个参数的梯度:
- ∂w2∂L≈−0.0342
- ∂b2∂L≈−0.0622
- ∂w1∂L≈−0.0070
- ∂b1∂L≈−0.0139
这些梯度表明每个参数需要改变的方向和大小,以减小损失。例如,像 ∂w2∂L≈−0.0342 这样的负梯度表明,略微增加 w2 会减小损失(因为更新规则涉及减去梯度)。
下一步
在实际训练场景中,这些梯度将与选定的学习率(η)一起使用,通过梯度下降来更新参数:
wnew=wold−η∂wold∂L
bnew=bold−η∂bold∂L
这种手动计算,虽然对于更大的网络会很繁琐,但清楚地展示了反向传播的机制,以及误差信号如何通过网络反向流动来指导参数更新。TensorFlow和PyTorch等框架自动化此过程,但理解其底层计算对于有效地构建模型和调试具有重要意义。