共计 2503 个字符,预计需要花费 7 分钟才能阅读完成。
背景介绍
BP 神经网络(Backpropagation Neural Network)是深度学习的基础,广泛应用于图像识别、语音处理等领域。它通过模拟人脑神经元的工作方式,能够学习复杂的非线性关系。理解 BP 神经网络的原理对于掌握深度学习至关重要。

数学原理
前向传播
前向传播是神经网络预测的过程。以一个简单的三层网络为例:
-
输入层到隐藏层:
$$h_j = f(\sum_{i} w_{ij}x_i + b_j)$$
其中,$f$ 是激活函数,$w_{ij}$ 是权重,$b_j$ 是偏置。 -
隐藏层到输出层:
$$y_k = f(\sum_{j} w_{jk}h_j + b_k)$$
反向传播
反向传播通过计算损失函数的梯度来更新权重:
-
计算输出层误差:
$$\delta_k = (y_k – t_k) \cdot f'(z_k)$$
其中,$t_k$ 是真实值,$z_k$ 是加权输入。 -
计算隐藏层误差:
$$\delta_j = f'(z_j) \sum_{k} w_{jk}\delta_k$$ -
更新权重:
$$w_{ij} = w_{ij} – \eta \delta_j x_i$$
$$w_{jk} = w_{jk} – \eta \delta_k h_j$$
激活函数
常用激活函数包括:
- Sigmoid:$\sigma(x) = \frac{1}{1 + e^{-x}}$
- ReLU:$f(x) = max(0, x)$
- Tanh:$tanh(x) = \frac{e^x – e^{-x}}{e^x + e^{-x}}$
Python 实现
import numpy as np
from typing import List, Tuple
class BPNeuralNetwork:
def __init__(self, layer_sizes: List[int]):
"""
初始化神经网络
:param layer_sizes: 每层的神经元数量,如 [784, 128, 10]
"""
self.weights = [np.random.randn(y, x) * 0.1
for x, y in zip(layer_sizes[:-1], layer_sizes[1:])]
self.biases = [np.random.randn(y, 1) * 0.1
for y in layer_sizes[1:]]
def forward(self, x: np.ndarray) -> np.ndarray:
"""前向传播"""
for w, b in zip(self.weights, self.biases):
x = sigmoid(np.dot(w, x) + b)
return x
def train(self, x: np.ndarray, y: np.ndarray, lr: float = 0.1):
"""训练网络"""
# 前向传播
activations = [x]
zs = []
for w, b in zip(self.weights, self.biases):
z = np.dot(w, activations[-1]) + b
zs.append(z)
activations.append(sigmoid(z))
# 反向传播
delta = (activations[-1] - y) * sigmoid_prime(zs[-1])
nabla_w = [np.zeros_like(w) for w in self.weights]
nabla_b = [np.zeros_like(b) for b in self.biases]
nabla_w[-1] = np.dot(delta, activations[-2].T)
nabla_b[-1] = delta
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_w[-l] = np.dot(delta, activations[-l-1].T)
nabla_b[-l] = delta
# 更新权重
self.weights = [w - lr * nw
for w, nw in zip(self.weights, nabla_w)]
self.biases = [b - lr * nb
for b, nb in zip(self.biases, nabla_b)]
def sigmoid(x: np.ndarray) -> np.ndarray:
return 1.0 / (1.0 + np.exp(-x))
def sigmoid_prime(x: np.ndarray) -> np.ndarray:
return sigmoid(x) * (1 - sigmoid(x))
常见问题与解决方案
梯度消失
梯度消失是由于深层网络中梯度不断相乘导致的值变小。解决方案:
- 使用 ReLU 等非饱和激活函数
- 使用 Batch Normalization
- 残差连接(ResNet)
过拟合
防止过拟合的方法:
- L2 正则化:在损失函数中加入权重平方和
- Dropout:随机丢弃部分神经元
- 早停(Early Stopping)
学习率调整
学习率太大导致震荡,太小收敛慢。策略:
- 学习率衰减
- 自适应优化器(Adam, RMSprop)
性能优化建议
批量归一化
在每层激活前进行归一化:
class BatchNorm:
def __init__(self, dim):
self.gamma = np.ones(dim)
self.beta = np.zeros(dim)
def forward(self, x):
self.mu = np.mean(x, axis=0)
self.sigma = np.var(x, axis=0)
x_norm = (x - self.mu) / np.sqrt(self.sigma + 1e-8)
return self.gamma * x_norm + self.beta
优化器比较
- SGD:简单但容易陷入局部最优
- Momentum:加入动量项加速收敛
- Adam:结合 Momentum 和 RMSprop
生产环境注意事项
- 数据预处理:标准化(均值 0,方差 1)、数据增强
- 模型保存:保存权重和架构
- 推理优化:量化、剪枝、TensorRT 加速
延伸阅读
- 《神经网络与深度学习》
- CS231n 课程资料
练习题
- 实现一个 5 层的 BP 神经网络
- 比较 Sigmoid 和 ReLU 在不同层数下的表现
- 在 CIFAR-10 数据集上测试模型性能
正文完
