共计 2142 个字符,预计需要花费 6 分钟才能阅读完成。
模式识别是人工智能的核心任务之一,而 BP 神经网络作为最基础的多层感知机实现,通过误差反向传播机制为现代深度学习奠定了基础。本文将从数学推导到代码实现完整拆解其工作流程。

一、前向传播的矩阵表示
神经网络的前向传播本质是加权求和与非线性变换的堆叠。以单隐层网络为例:
$$
\begin{aligned}
z^{[1]} &= W^{[1]}X + b^{[1]} \
a^{[1]} &= \sigma(z^{[1]}) \
z^{[2]} &= W^{[2]}a^{[1]} + b^{[2]} \
\hat{y} &= a^{[2]} = \text{softmax}(z^{[2]})
\end{aligned}
$$
其中 $\sigma(\cdot)$ 代表激活函数,输入层到隐层的权重矩阵 $W^{[1]}$ 维度为 $(n_{hidden}, n_{input})$,运算时需注意矩阵乘法的维度匹配。
二、反向传播的数学推导
核心是通过链式法则计算损失函数对各参数的梯度。以交叉熵损失 $L$ 为例:
-
输出层梯度:
$$ \frac{\partial L}{\partial z^{[2]}} = \hat{y} – y $$ -
隐层参数梯度:
$$ \frac{\partial L}{\partial W^{[2]}} = \frac{\partial L}{\partial z^{[2]}} \cdot a^{[1]T} $$ -
继续反向传播至前一层:
$$ \frac{\partial L}{\partial z^{[1]}} = W^{[2]T} \frac{\partial L}{\partial z^{[2]}} \odot \sigma'(z^{[1]}) $$
其中 $\odot$ 表示逐元素相乘,$\sigma’$ 为激活函数导数。完整推导需展开计算图的所有路径。
三、Python 实现关键代码
import numpy as np
class BPNetwork:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(hidden_size, input_size) * 0.01
self.b1 = np.zeros((hidden_size, 1))
self.W2 = np.random.randn(output_size, hidden_size) * 0.01
self.b2 = np.zeros((output_size, 1))
def forward(self, X):
self.Z1 = np.dot(self.W1, X) + self.b1
self.A1 = 1/(1+np.exp(-self.Z1)) # Sigmoid
self.Z2 = np.dot(self.W2, self.A1) + self.b2
self.A2 = np.exp(self.Z2) / np.sum(np.exp(self.Z2), axis=0) # Softmax
return self.A2
def backward(self, X, y, lr=0.1):
m = X.shape[1]
dZ2 = self.A2 - y
dW2 = np.dot(dZ2, self.A1.T) / m
db2 = np.sum(dZ2, axis=1, keepdims=True) / m
dZ1 = np.dot(self.W2.T, dZ2) * self.A1*(1-self.A1) # Sigmoid 导数
dW1 = np.dot(dZ1, X.T) / m
db1 = np.sum(dZ1, axis=1, keepdims=True) / m
# 参数更新
self.W2 -= lr * dW2
self.b2 -= lr * db2
self.W1 -= lr * dW1
self.b1 -= lr * db1
四、实践避坑指南
梯度消失问题
当使用 Sigmoid 激活函数时,其导数最大值为 0.25,多层连乘会导致梯度指数级衰减:
- 解决方案:改用 ReLU 激活函数,其正区间导数为 1
- 辅助措施:Xavier/Glorot 初始化权重
过拟合应对
# Early Stopping 实现
def train_with_early_stop(model, X_train, y_train, X_val, y_val, patience=5):
best_val_acc = 0
counter = 0
for epoch in range(1000):
model.train(X_train, y_train)
val_acc = model.evaluate(X_val, y_val)
if val_acc > best_val_acc:
best_val_acc = val_acc
counter = 0
else:
counter += 1
if counter >= patience:
break
学习率衰减策略
# 指数衰减
lr = initial_lr * (0.95 ** epoch)
# 阶梯衰减
if epoch % 30 == 0:
lr *= 0.5
五、延伸思考
- 交叉熵损失相比 MSE 更适合分类任务,因其对错误预测的惩罚更大
- 隐层节点数可按 $n_{hidden} = \sqrt{n_{input} \cdot n_{output}}}$ 初始设定
- Batch Normalization 可进一步加速训练收敛
通过这个从理论到实践的完整梳理,读者应能建立起对 BP 网络的直观理解。建议尝试在 MNIST 数据集上实现 90%+ 的识别准确率作为练习目标。
