共计 2092 个字符,预计需要花费 6 分钟才能阅读完成。
初识 BP 神经网络
BP 神经网络(Backpropagation Neural Network)是深度学习最基础的模型之一,它的核心思想就像教小孩子认字:先看正确答案(前向传播),再根据错误调整学习方法(反向传播)。举个简单例子,当网络把猫图片误判成狗时,它会自动计算每个参数该负多少责任,并通过链式法则逐层调整权重。

数学推导:误差是如何反向传播的
关键公式用 LaTeX 展示如下:
-
前向传播时第 l 层的输出:
$$a^{(l)} = \sigma(z^{(l)}) = \sigma(W^{(l)}a^{(l-1)} + b^{(l)})$$ -
损失函数对权重的偏导(链式法则):
$$\frac{\partial L}{\partial W_{ij}^{(l)}} = \frac{\partial L}{\partial z_{i}^{(l)}} \cdot \frac{\partial z_{i}^{(l)}}{\partial W_{ij}^{(l)}} = \delta_{i}^{(l)} \cdot a_{j}^{(l-1)}$$ -
误差项反向传递:
$$\delta^{(l)} = ((W^{(l+1)})^T \delta^{(l+1)}) \odot \sigma'(z^{(l)})$$
Python 实现:手把手构建 BP 网络
import numpy as np
class NeuralNetwork:
def __init__(self, layers):
self.weights = [np.random.randn(y, x) for x, y in zip(layers[:-1], layers[1:])]
self.biases = [np.random.randn(y, 1) for y in layers[1:]]
def forward(self, x):
# 前向传播计算图
for w, b in zip(self.weights, self.biases):
x = sigmoid(np.dot(w, x) + b)
return x
def backprop(self, x, y):
# 反向传播核心代码
nabla_w = [np.zeros(w.shape) for w in self.weights]
nabla_b = [np.zeros(b.shape) for b in self.biases]
# 前向传播缓存中间值
activation = x
activations = [x]
zs = []
for w, b in zip(self.weights, self.biases):
z = np.dot(w, activation) + b
zs.append(z)
activation = sigmoid(z)
activations.append(activation)
# 输出层误差
delta = (activations[-1] - y) * sigmoid_prime(zs[-1])
nabla_b[-1] = delta
nabla_w[-1] = np.dot(delta, activations[-2].T)
# 反向传播误差
for l in range(2, len(self.weights)+1):
z = zs[-l]
sp = sigmoid_prime(z)
delta = np.dot(self.weights[-l+1].T, delta) * sp
nabla_b[-l] = delta
nabla_w[-l] = np.dot(delta, activations[-l-1].T)
return nabla_w, nabla_b
正反向传播流程图解
标准流程图包含以下要素:
- 前向传播路径 (蓝色箭头):
- 输入层→隐藏层→输出层的计算流向
-
每个神经元展示加权求和与激活过程
-
反向传播路径 (红色虚线箭头):
- 从损失函数开始的反向梯度流动
- 权重矩阵的转置操作可视化
-
局部梯度与上游梯度相乘的链式过程
-
关键计算节点 :
- 用菱形符号标注权重更新公式
- 椭圆节点表示激活函数的导数计算
三大常见陷阱与解决方案
- 梯度消失 / 爆炸 :
- 现象:深层网络训练时损失值突变或长期不变
-
对策:
- 使用 ReLU 等非饱和激活函数
- 权重初始化采用 Xavier 方法
- 添加 Batch Normalization 层
-
学习率设置 :
- 黄金法则:初始值设为 0.01~0.001
- 动态调整:当验证损失连续 3 轮不下降时减半
-
进阶技巧:采用 Adam 等自适应优化器
-
激活函数选择 :
- Sigmoid:导致梯度消失,仅推荐输出层使用
- Tanh:梯度范围优于 Sigmoid
- ReLU:最常用但需注意 ” 死亡神经元 ” 问题
工业级框架实现对比
| 特性 | PyTorch | TensorFlow |
|---|---|---|
| 自动微分实现 | 动态计算图 | 静态计算图 |
| 梯度计算方式 | tape-based | 符号微分 |
| 调试便利性 | 可实时打印中间梯度 | 需要 session.run |
延伸思考
- 二阶导数计算 :
- 在现有网络中插入二次激活函数(如 $\sin(x)$)
-
使用双反向传播技巧
-
批量训练差异 :
- 在线训练:每个样本更新权重,梯度波动大
- 批量训练:梯度更稳定但内存消耗高
实践建议
建议先用小批量数据(如 MNIST 手写数字)测试代码,重点观察:
1. 前向传播的输出是否在合理范围(如 sigmoid 输出应在 0 - 1 之间)
2. 反向传播的梯度值是否与数值微分结果接近(差值 <1e-7)
3. 首次运行时先将学习率设为 0.1,快速验证收敛性
