共计 1884 个字符,预计需要花费 5 分钟才能阅读完成。
核心概念:前向传播与反向传播
BP 神经网络的核心在于通过误差反向传播来调整权重。我们先来看前向传播的过程:

-
输入层到隐藏层的计算:
$$z^{(2)} = W^{(1)}x + b^{(1)}$$
$$a^{(2)} = f(z^{(2)})$$
其中 $f$ 是激活函数 -
隐藏层到输出层的计算:
$$z^{(3)} = W^{(2)}a^{(2)} + b^{(2)}$$
$$a^{(3)} = f(z^{(3)})$$
反向传播则是通过链式法则计算梯度:
-
输出层误差:
$$\delta^{(3)} = (a^{(3)} – y) \odot f'(z^{(3)})$$ -
隐藏层误差:
$$\delta^{(2)} = (W^{(2)T}\delta^{(3)}) \odot f'(z^{(2)})$$ -
权重更新:
$$\Delta W^{(2)} = \delta^{(3)}a^{(2)T}$$
$$\Delta W^{(1)} = \delta^{(2)}x^T$$
痛点分析与解决方案
在实际训练中,我们经常会遇到以下问题:
- 梯度消失:深层网络中梯度会指数级衰减
- 过拟合:训练误差小但测试误差大
- 训练震荡:loss 曲线波动剧烈
解决方案包括:
- 使用 ReLU 激活函数缓解梯度消失
- 添加 L2 正则化防止过拟合
- 采用合适的学习率策略
Python 实现
以下是使用 NumPy 实现的三层 BP 神经网络核心代码:
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size, output_size):
# 权重初始化
self.W1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros((1, hidden_size))
self.W2 = np.random.randn(hidden_size, output_size) * 0.01
self.b2 = np.zeros((1, output_size))
def sigmoid(self, z):
return 1 / (1 + np.exp(-z))
def forward(self, X):
# 前向传播
self.z2 = np.dot(X, self.W1) + self.b1
self.a2 = self.sigmoid(self.z2)
self.z3 = np.dot(self.a2, self.W2) + self.b2
self.a3 = self.sigmoid(self.z3)
return self.a3
def backward(self, X, y, learning_rate):
# 反向传播
m = X.shape[0]
delta3 = (self.a3 - y) * self.a3 * (1 - self.a3) # 输出层误差
dW2 = np.dot(self.a2.T, delta3)
db2 = np.sum(delta3, axis=0, keepdims=True)
delta2 = np.dot(delta3, self.W2.T) * self.a2 * (1 - self.a2) # 隐藏层误差
dW1 = np.dot(X.T, delta2)
db1 = np.sum(delta2, axis=0)
# 参数更新
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
优化方案
不同的优化器对训练效果有显著影响:
- SGD(随机梯度下降):简单但容易震荡
- Momentum:加入动量项减少震荡
- Adam:自适应学习率,通常效果最好
学习率衰减的实现:
# 指数衰减学习率
initial_learning_rate = 0.1
decay_steps = 1000
decay_rate = 0.96
def get_learning_rate(step):
return initial_learning_rate * (decay_rate ** (step / decay_steps))
避坑指南
- 权重初始化:
-
使用 Xavier 初始化:
W = np.random.randn(fan_in, fan_out) / np.sqrt(fan_in) -
批量归一化:
- 通常放在激活函数之前
-
可以加速训练并缓解梯度消失
-
早停法:
- 监控验证集 loss
- patience 参数通常设为 5 -10
延伸思考
要将 BP 网络扩展为深度神经网络,需要考虑:
- 残差连接(ResNet)解决梯度消失
- 批量归一化加速训练
- 合适的初始化方法
- 更复杂的架构设计
通过这篇文章,我们系统地介绍了 BP 神经网络的原理和实现,希望能帮助开发者更好地理解和应用这一经典算法。
