共计 2065 个字符,预计需要花费 6 分钟才能阅读完成。
1. 从单层感知机到多层网络
1.1 单层感知机的梯度下降
单层感知机的输出可表示为:

y = \sigma(w^Tx + b)
其中 σ 为激活函数。采用均方误差损失函数:
L = \frac{1}{2}(y - t)^2
权重更新公式通过梯度下降可得:
w_{new} = w - \eta \frac{\partial L}{\partial w}
1.2 扩展到多层网络的链式法则
对于三层网络(输入层→隐藏层→输出层),需要逐层反向传播误差:
\frac{\partial L}{\partial w_{ij}^{(2)}} = \frac{\partial L}{\partial z_j^{(3)}}\frac{\partial z_j^{(3)}}{\partial w_{ij}^{(2)}}
其中 z 表示未激活的加权和。
2. 完整推导过程
2.1 前向传播计算
定义网络各层计算(以 Sigmoid 激活函数为例):
def forward(x):
z1 = np.dot(x, W1) + b1
a1 = sigmoid(z1)
z2 = np.dot(a1, W2) + b2
a2 = sigmoid(z2)
return a2
2.2 损失函数定义
交叉熵损失函数:
L = -\frac{1}{N}\sum_{i=1}^N [t_i\ln(y_i)+(1-t_i)\ln(1-y_i)]
2.3 反向传播梯度计算
输出层梯度:
\delta^{(3)} = (y - t) \odot \sigma'(z^{(3)})
隐藏层梯度:
\delta^{(2)} = (W^{(2)}\delta^{(3)}) \odot \sigma'(z^{(2)})
2.4 权重更新实现
def backward(x, y, learning_rate):
# 前向传播
z1, a1, z2, a2 = forward(x)
# 输出层梯度
delta2 = (a2 - y) * sigmoid_derivative(z2)
dW2 = np.dot(a1.T, delta2)
# 隐藏层梯度
delta1 = np.dot(delta2, W2.T) * sigmoid_derivative(z1)
dW1 = np.dot(x.T, delta1)
# 更新参数
W1 -= learning_rate * dW1
W2 -= learning_rate * dW2
3. 避坑指南
3.1 梯度消失 / 爆炸问题
- 现象:深层网络训练时梯度指数级减小或增大
- 解决方案:
- 使用 ReLU 等改良激活函数
- 采用 Batch Normalization
- 梯度裁剪(Gradient Clipping)
3.2 学习率设置
- 推荐初始值:0.001-0.1
- 可采用学习率衰减策略:
lr = initial_lr * (1 + decay_rate * epoch)^(-1)
3.3 激活函数选择
| 函数类型 | 适用场景 | 注意事项 |
|---|---|---|
| Sigmoid | 二分类输出层 | 易梯度饱和 |
| ReLU | 隐藏层 | 可能出现神经元死亡 |
| Tanh | 隐藏层 | 输出零中心化 |
4. 思考题
- 如何通过数值梯度检验验证反向传播实现的正确性?
- 批量训练时梯度计算与在线训练有何本质区别?
- Adam 等二阶优化算法在哪些场景下优于 SGD?会带来哪些额外计算开销?
5. 完整代码实现
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(input_size, hidden_size)
self.W2 = np.random.randn(hidden_size, output_size)
def sigmoid(self, x):
return 1/(1+np.exp(-x))
def sigmoid_derivative(self, x):
return self.sigmoid(x)*(1-self.sigmoid(x))
def forward(self, x):
self.z1 = np.dot(x, self.W1)
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2)
self.a2 = self.sigmoid(self.z2)
return self.a2
def backward(self, x, y, learning_rate):
m = x.shape[0]
# 输出层误差
delta2 = (self.a2 - y) * self.sigmoid_derivative(self.z2)
dW2 = np.dot(self.a1.T, delta2)
# 隐藏层误差
delta1 = np.dot(delta2, self.W2.T) * self.sigmoid_derivative(self.z1)
dW1 = np.dot(x.T, delta1)
# 更新参数
self.W1 -= learning_rate * dW1
self.W2 -= learning_rate * dW2
理解反向传播的关键在于掌握链式法则的应用,建议读者通过手动计算一个 3 层网络的导数来加深理解。在实践中,使用自动微分框架(如 PyTorch)可以避免手动推导的复杂性,但理解底层原理对于调试网络和设计新架构至关重要。
正文完
