共计 2076 个字符,预计需要花费 6 分钟才能阅读完成。
数学原理篇
前向传播的三层计算链
-
输入层到隐层:
$$h_j = \sigma(\sum_{i=1}^n w_{ij}x_i + b_j)$$
其中 $\sigma(z)=1/(1+e^{-z})$ 是 Sigmoid 函数
-
隐层到输出层:
$$y_k = \sigma(\sum_{j=1}^m v_{jk}h_j + c_k)$$ -
损失函数计算(交叉熵):
$$E = -\frac{1}{N}\sum_{t=1}^N\sum_{k=1}^K [d_k^t\ln y_k^t + (1-d_k^t)\ln(1-y_k^t)]$$
反向传播的梯度推导
-
输出层梯度:
$$\frac{\partial E}{\partial v_{jk}} = (y_k – d_k)h_j$$
$$\frac{\partial E}{\partial c_k} = y_k – d_k$$ -
隐层梯度:
$$\frac{\partial E}{\partial w_{ij}} = [\sum_{k=1}^K (y_k – d_k)v_{jk}]h_j(1-h_j)x_i$$
$$\frac{\partial E}{\partial b_j} = [\sum_{k=1}^K (y_k – d_k)v_{jk}]h_j(1-h_j)$$
Python 实现篇
import numpy as np
class BPNetwork:
def __init__(self, input_size, hidden_size, output_size):
# He 初始化权重
self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2/input_size)
self.b1 = np.zeros(hidden_size)
self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2/hidden_size)
self.b2 = np.zeros(output_size)
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def forward(self, X):
self.hidden = self.sigmoid(np.dot(X, self.W1) + self.b1)
return self.sigmoid(np.dot(self.hidden, self.W2) + self.b2)
def train(self, X, y, epochs=1000, lr=0.1, batch_size=32):
for epoch in range(epochs):
# 随机选择 mini-batch
indices = np.random.choice(len(X), batch_size)
X_batch, y_batch = X[indices], y[indices]
# 前向传播
output = self.forward(X_batch)
# 反向传播
output_error = (output - y_batch) * output * (1 - output)
hidden_error = np.dot(output_error, self.W2.T) * self.hidden * (1 - self.hidden)
# 更新参数
self.W2 -= lr * np.dot(self.hidden.T, output_error) / batch_size
self.b2 -= lr * np.mean(output_error, axis=0)
self.W1 -= lr * np.dot(X_batch.T, hidden_error) / batch_size
self.b1 -= lr * np.mean(hidden_error, axis=0)
MNIST 实战篇
数据预处理关键步骤
- 像素值归一化到 [0,1] 区间
X_train = X_train.astype('float32') / 255 - 标签 one-hot 编码
y_train = np.eye(10)[y_train.astype('int32')]
超参数调优记录表
| 参数组合 | 验证集准确率 |
|---|---|
| lr=0.1, hidden=64 | 89.2% |
| lr=0.05, hidden=128 | 91.7% |
| lr=0.01, hidden=256 | 92.4% |
避坑指南
梯度消失对策
- 使用 ReLU 替代 Sigmoid 作为隐层激活函数
- 采用 Xavier/Glorot 初始化权重
- 添加 Batch Normalization 层
过拟合预防
- 添加 L2 正则化项
loss += 0.001 * (np.sum(self.W1**2) + np.sum(self.W2**2)) - 实现 Early Stopping
- Dropout 层实现(训练时随机丢弃神经元)
学习率衰减实现
lr = initial_lr * (1. / (1. + decay_rate * epoch))
进阶思考
- 残差连接是否能提升深层 BP 网络的训练效果?
- 对比 Sigmoid、Tanh、ReLU 在不同网络深度下的表现差异
- 当训练数据达到百万级时,应该如何优化批量训练策略?
通过这个完整的实现案例,我们可以看到 BP 神经网络虽然原理简单,但在实际应用中需要考虑众多工程细节。建议读者先运行基础代码理解核心机制,再逐步尝试各个优化方案。
正文完

