共计 1781 个字符,预计需要花费 5 分钟才能阅读完成。
从链式法则理解反向传播
反向传播 (BP) 算法的核心是链式法则的递归应用。考虑一个简单三层网络(输入层、隐藏层、输出层),前向传播时:

- 隐藏层输出:$h = \sigma(W_1x + b_1)$
- 最终输出:$y = W_2h + b_2$
- 损失函数:$L = \frac{1}{2}(y – t)^2$(MSE 损失)
反向传播时,我们需要计算损失对每个参数的梯度:
- $\frac{\partial L}{\partial W_2} = (y-t) \cdot h^T$
- $\frac{\partial L}{\partial b_2} = (y-t)$
- $\frac{\partial L}{\partial W_1} = (W_2^T(y-t)) \odot \sigma'(z) \cdot x^T$
- $\frac{\partial L}{\partial b_1} = (W_2^T(y-t)) \odot \sigma'(z)$
其中 $\odot$ 表示逐元素相乘,$\sigma’$ 是激活函数的导数。
Python 实现细节
1. 网络层实现
import numpy as np
class DenseLayer:
def __init__(self, input_size, output_size):
self.W = np.random.randn(output_size, input_size) * 0.01
self.b = np.zeros((output_size, 1))
def forward(self, x):
self.x = x # 缓存输入用于反向传播
return np.dot(self.W, self.x) + self.b
def backward(self, dout):
self.dW = np.dot(dout, self.x.T)
self.db = np.sum(dout, axis=1, keepdims=True)
return np.dot(self.W.T, dout)
class ReLU:
def forward(self, x):
self.mask = (x <= 0)
return np.maximum(0, x)
def backward(self, dout):
dout[self.mask] = 0
return dout
2. 损失函数与训练循环
class MSE:
def __call__(self, y_pred, y_true):
self.y_pred, self.y_true = y_pred, y_true
return 0.5 * np.mean((y_pred - y_true)**2)
def backward(self):
return (self.y_pred - self.y_true) / len(self.y_true)
# 训练示例
for epoch in range(epochs):
# 前向传播
h1 = relu1(dense1(x))
y = dense2(h1)
loss = mse(y, t)
# 反向传播
dy = mse.backward()
dh1 = dense2.backward(dy)
dx = relu1.backward(dh1)
_ = dense1.backward(dx)
# 参数更新
dense1.W -= lr * dense1.dW
dense2.W -= lr * dense2.dW
关键问题讨论
梯度消失 / 爆炸
- 成因:当网络较深时,梯度在反向传播过程中会连乘多个权重矩阵。如果权重初始化不当(如值过大或过小),会导致梯度指数级变化
- 解决方案:
- 使用 Xavier/He 初始化
- 加入 BatchNorm 层
- 使用 ResNet 中的跳跃连接
激活函数选择
| 函数 | 梯度特性 | 适用场景 |
|---|---|---|
| Sigmoid | 最大 0.25 | 二分类输出层 |
| Tanh | 最大 1.0 | RNN 隐藏层 |
| ReLU | 0 或 1 | 大多数前馈网络 |
| LeakyReLU | 0 或 α | 解决神经元死亡 |
学习率调优
- 初始值通常设在 0.001-0.1 之间
- 使用学习率衰减:
lr = initial_lr * (1 + decay * epoch)^(-1) - 高级优化器(Adam)自动调整学习率
延伸思考
- 扩展到 CNN:需要实现卷积层的局部连接和参数共享特性,主要改动在:
- 前向传播使用 im2col 技巧
-
反向传播计算卷积核的梯度时需考虑感受野
-
BatchNorm 影响:
- 在反向传播时需要额外计算对均值和方差的梯度
- 使得各层输入的分布稳定,缓解梯度问题
-
实际实现时需维护 running_mean/running_var
-
二阶优化:
- 牛顿法等需要计算 Hessian 矩阵
- 实际中常使用拟牛顿法(如 L -BFGS)
- 适合小批量数据场景
正文完
