共计 2000 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要反向传播?
前向传播通过层层加权求和与非线性变换完成预测,但面临一个根本问题:当输出结果与真实值存在误差时,如何确定网络中每个参数的具体责任?反向传播通过将误差从输出层向输入层逐层分配,用微积分中的链式法则实现了这一过程。

计算图中的链式法则示例:
假设网络输出为 $\hat{y} = f(wx+b)$,损失函数为 $L = \frac{1}{2}(y-\hat{y})^2$,则权重 $w$ 的梯度可表示为:
$$
\frac{\partial L}{\partial w} = \frac{\partial L}{\partial \hat{y}} \cdot \frac{\partial \hat{y}}{\partial z} \cdot \frac{\partial z}{\partial w} = -(y-\hat{y}) \cdot f'(z) \cdot x
$$
其中 $z=wx+b$,这就是误差从输出端流向权重的完整路径。
梯度下降的几何本质
-
参数空间可视化 :将损失函数看作三维曲面,z 轴表示损失值,x/ y 轴代表两个权重参数。梯度向量指向该点处曲面最陡峭的上升方向,负梯度即最优下降方向。
-
学习率的作用 :过大的学习率会导致在谷底震荡,过小则收敛缓慢。实践中可采用以下策略:
# 学习率衰减示例
def adjust_learning_rate(epoch):
initial_lr = 0.1
lr = initial_lr * (0.5 ** (epoch // 10))
return lr
标准 BP 算法实现
算法伪代码流程:
- 前向传播计算各层输出
- 计算输出层误差 δ
- 反向传播误差至各隐藏层
- 利用误差计算梯度
- 更新权重参数
Python 关键代码实现:
import numpy as np
def sigmoid(x):
return 1/(1+np.exp(-x))
def backward(X, y, y_pred, W1, W2, b1, b2):
# 输出层误差
delta2 = (y_pred - y) * sigmoid(y_pred) * (1 - sigmoid(y_pred))
# 隐藏层误差(反向传播)delta1 = np.dot(delta2, W2.T) * sigmoid(hidden_output) * (1 - sigmoid(hidden_output))
# 计算梯度
dW2 = np.dot(hidden_output.T, delta2)
dW1 = np.dot(X.T, delta1)
# 参数更新
W1 -= learning_rate * dW1
W2 -= learning_rate * dW2
激活函数对比实验
不同激活函数对梯度流动的影响:
- Sigmoid:当输入绝对值较大时梯度接近 0,导致梯度消失
- Tanh:梯度范围 (0,1),缓解但不解决梯度消失
- ReLU:正区间梯度恒为 1,但负区间完全关闭(可能引发神经元死亡)
实验数据表明:使用 ReLU 的网络在 MNIST 上比 Sigmoid 快 3 倍达到相同精度。
实战 MNIST 分类
完整训练流程包含:
- 数据预处理(归一化 /one-hot 编码)
- 网络初始化(He 初始化更适合 ReLU)
- 小批量训练(batch_size=64)
- 损失曲线可视化
关键代码片段:
# 权重初始化
W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2./input_size)
# 训练循环
for epoch in range(epochs):
for i in range(0, X_train.shape[0], batch_size):
# 小批量数据
X_batch = X_train[i:i+batch_size]
y_batch = y_train[i:i+batch_size]
# 前向传播
hidden = relu(np.dot(X_batch, W1) + b1)
output = softmax(np.dot(hidden, W2) + b2)
# 反向传播与参数更新...
常见问题解决方案
-
梯度爆炸 :设定阈值进行裁剪
grad_norm = np.linalg.norm(grad) if grad_norm > max_norm: grad = grad * max_norm / grad_norm -
内部协变量偏移 :在非线性层前加入 Batch Normalization
mu = np.mean(batch, axis=0) sigma = np.std(batch, axis=0) normalized = (batch - mu) / np.sqrt(sigma**2 + eps) -
局部最优 :使用带动量的梯度下降
velocity = momentum * velocity - lr * grad param += velocity
思考题分析
当出现高训练精度但低验证精度时,可能原因包括:
- 权重更新过度拟合训练样本(可通过 L2 正则约束)
- 网络层间梯度传递受阻(检查激活函数选择)
- 学习率后期未衰减(验证损失不再下降时应减小步长)
理解 BP 算法让我们能精准定位问题:例如若某层权重更新幅度始终很小,可能是梯度消失导致的特征学习不足。
