共计 1959 个字符,预计需要花费 5 分钟才能阅读完成。
数学推导与计算图构建
BP 算法的核心是链式求导法则。设网络有 $L$ 层,第 $l$ 层的输出为:
$$a^{(l)} = f(z^{(l)}),\ z^{(l)}=W^{(l)}a^{(l-1)}+b^{(l)}$$

对于损失函数 $J$,输出层的梯度为:
$$\delta^{(L)} = \frac{\partial J}{\partial z^{(L)}} = \frac{\partial J}{\partial a^{(L)}} \odot f'(z^{(L)})$$
反向传播时的递推公式:
$$\delta^{(l)} = (W^{(l+1)T}\delta^{(l+1)}) \odot f'(z^{(l)})$$
权重梯度计算:
$$\frac{\partial J}{\partial W^{(l)}} = \delta^{(l)}a^{(l-1)T}$$
激活函数对比与选型
-
Sigmoid:
$$f'(z) = f(z)(1-f(z))$$
易导致梯度消失,输出非零中心化 -
Tanh:
$$f'(z) = 1 – f(z)^2$$
缓解了零中心问题,但仍有饱和区 -
ReLU:
$$f'(z) = \begin{cases}
1 & z>0 \
0 & \text{otherwise}
\end{cases}$$
推荐首选,需注意 Dead ReLU 问题
Python 实现(带优化项)
import numpy as np
class BPNetwork:
def __init__(self, layers, lr=0.01, momentum=0.9):
self.weights = [np.random.randn(y, x)*0.01
for x,y in zip(layers[:-1], layers[1:])]
self.biases = [np.zeros((y,1)) for y in layers[1:]]
self.velocity_w = [np.zeros_like(w) for w in self.weights]
self.velocity_b = [np.zeros_like(b) for b in self.biases]
self.lr = lr
self.momentum = momentum
def relu(self, z):
return np.maximum(0, z)
def relu_deriv(self, z):
return (z > 0).astype(float)
def forward(self, x):
# 实现前向传播...
def backward(self, x, y):
# 实现反向传播...
# 带动量项的权重更新
for l in range(len(self.weights)):
self.velocity_w[l] = self.momentum*self.velocity_w[l] + \
(1-self.momentum)*grad_w[l]
self.velocity_b[l] = self.momentum*self.velocity_b[l] + \
(1-self.momentum)*grad_b[l]
self.weights[l] -= self.lr * self.velocity_w[l]
self.biases[l] -= self.lr * self.velocity_b[l]
# 学习率衰减
self.lr *= 0.995
性能优化技巧
- BatchNorm 实现 :
-
在每个全连接层后添加:
gamma = np.ones((hidden_size,1)) beta = np.zeros((hidden_size,1)) batch_mean = np.mean(z, axis=1, keepdims=True) batch_var = np.var(z, axis=1, keepdims=True) z_hat = (z - batch_mean) / np.sqrt(batch_var + 1e-5) z_out = gamma * z_hat + beta -
GPU 加速建议 :
- 使用 CuPy 替换 NumPy
- 将大矩阵运算转为 CUDA kernel
- 注意减少 CPU-GPU 数据传输
常见问题解决方案
- 梯度爆炸 :
- 监控梯度范数
-
采用梯度裁剪(Gradient Clipping):
max_norm = 5 for grad in [grad_w, grad_b]: norm = np.linalg.norm(grad) if norm > max_norm: grad *= max_norm / norm -
隐层神经元数量 :
- 参考公式:$N_h = \frac{N_s}{\alpha(N_i + N_o)}$
- 其中 $N_s$ 为样本数,$\alpha$ 通常取 2~10
拓展思考
如何将 BP 算法与卷积操作结合?可以考虑:
1. 将卷积核权重作为可训练参数
2. 在池化层实现梯度回传
3. 使用 im2col 技巧加速卷积运算
4. 设计特殊的反向传播规则处理 padding 和 stride
在实际项目中,建议先用全连接网络验证算法正确性,再逐步引入卷积结构。
