共计 1973 个字符,预计需要花费 5 分钟才能阅读完成。
1. 从链式法则理解反向传播
反向传播 (BP) 算法的核心是链式法则——这个我们在高数课本里就熟悉的概念。想象我们要计算一个复合函数的导数,比如 f(g(x)),链式法则告诉我们:df/dx = (df/dg)*(dg/dx)。在神经网络中,这个思想被扩展到了成千上万个参数的计算上。

让我们从一个最简单的三层网络开始推导(输入层→隐藏层→输出层):
- 前向传播时,数据从输入层流向输出层,每一层的计算可以表示为:
- z = w·x + b(加权求和)
-
a = σ(z)(激活函数)
-
当得到输出层的预测值后,我们计算损失函数 L(比如 MSE)。反向传播的目标就是计算∂L/∂w 和∂L/∂b,这样我们才能用梯度下降更新参数。
-
根据链式法则,输出层的梯度计算分为三步:
- ∂L/∂a(损失函数对输出的导数)
- ∂a/∂z(激活函数的导数)
-
∂z/∂w(就是输入值 x)
最终∂L/∂w = (∂L/∂a)(∂a/∂z)(∂z/∂w) -
对于隐藏层,梯度计算需要继续向前传递,这就是 ” 反向 ” 传播的含义。每个神经元的误差信号 δ = (下游 δ·权重)*σ'(z),然后用 δ 计算当前层的梯度。
2. Python 实现细节
下面我们用 numpy 实现一个完整的全连接网络,包含以下关键组件:
import numpy as np
class FullyConnectedLayer:
def __init__(self, input_size, output_size):
self.weights = np.random.randn(input_size, output_size) * 0.1
self.bias = np.zeros(output_size)
def forward(self, x):
self.x = x # 保存输入用于反向传播
return x @ self.weights + self.bias
def backward(self, grad):
# grad 是损失函数对该层输出的梯度
self.dw = self.x.T @ grad # 计算权重梯度
self.db = np.sum(grad, axis=0) # 计算偏置梯度
return grad @ self.weights.T # 返回对输入的梯度
class SigmoidLayer:
def forward(self, x):
self.output = 1 / (1 + np.exp(-x))
return self.output
def backward(self, grad):
return grad * (self.output * (1 - self.output))
完整的训练循环还包括:
- 定义网络结构(比如[输入层→全连接→Sigmoid→全连接→MSE])
- 前向传播计算损失
- 反向传播计算梯度
- 用 SGD 更新参数:
learning_rate = 0.1
for epoch in range(100):
# 前向传播
loss = network.forward(X_train, y_train)
# 反向传播
network.backward()
# 更新参数
for layer in network.layers:
if hasattr(layer, 'weights'):
layer.weights -= learning_rate * layer.dw
layer.bias -= learning_rate * layer.db
3. 梯度检查与调试
实现反向传播最难的就是保证梯度计算的正确性。我们可以用数值梯度来验证:
def numerical_gradient(f, x, eps=1e-4):
grad = np.zeros_like(x)
for i in range(x.size):
tmp = x[i]
x[i] = tmp + eps
f1 = f(x)
x[i] = tmp - eps
f2 = f(x)
grad[i] = (f1 - f2) / (2 * eps)
x[i] = tmp
return grad
比较数值梯度和反向传播计算的梯度,两者应该非常接近(通常误差 <1e-7)。
4. 常见问题与优化
梯度消失 / 爆炸
当网络较深时,梯度可能在反向传播过程中指数级减小(消失)或增大(爆炸)。解决方案:
- 使用 ReLU 等激活函数替代 Sigmoid
- 权重初始化采用 He 或 Xavier 方法
- 添加 Batch Normalization 层
激活函数选择
- Sigmoid:容易导致梯度消失,输出不是零中心
- ReLU:计算简单但可能有 ” 死亡神经元 ” 问题
- LeakyReLU:解决了 ReLU 的死亡问题
学习率设置
- 太大:震荡无法收敛
- 太小:收敛速度慢
- 建议:使用学习率衰减或自适应优化器(Adam)
5. 延伸思考
- 扩展到 CNN:卷积层的反向传播需要处理局部连接和参数共享,梯度计算会更复杂但原理相同
- BatchNorm 的影响:在反向传播时需要额外考虑归一化带来的缩放因子
- 二阶优化:如何利用 Hessian 矩阵信息加速收敛?
实现一个正确的 BP 网络是理解深度学习的基础。虽然现在有自动微分框架,但手动推导和实现一次会让你对神经网络的工作机制有更深刻的认识。
正文完
