共计 2693 个字符,预计需要花费 7 分钟才能阅读完成。
1. 神经网络基础概念
BP 神经网络(Back Propagation Neural Network)是一种多层前馈神经网络,通过误差反向传播算法训练权重。它由输入层、隐藏层和输出层组成,每层包含多个神经元。

- 神经元结构 :每个神经元接收前一层神经元的输出,经过加权求和后通过激活函数产生输出
- 前向传播 :数据从输入层流向输出层
- 反向传播 :误差从输出层反向传播到输入层,用于调整权重
2. BP 算法流程图解
2.1 前向传播阶段
输入层 -> 隐藏层 -> 输出层
| | |
W_ih W_ho y_pred
- 输入数据通过输入层传递
- 计算隐藏层输入:$z_h = W_{ih}^T x + b_h$
- 应用激活函数:$a_h = \sigma(z_h)$
- 计算输出层输入:$z_o = W_{ho}^T a_h + b_o$
- 应用输出层激活函数:$y_{pred} = \sigma(z_o)$
2.2 损失计算
常用损失函数(以二分类为例):
$$ L = -\frac{1}{N}\sum_{i=1}^N [y_i\log(y_{pred}) + (1-y_i)\log(1-y_{pred})] $$
2.3 反向传播阶段
输出层 <- 隐藏层 <- 输入层
| | |
δ_o δ_h W_update
- 计算输出层误差:$\delta_o = y_{pred} – y$
- 计算隐藏层误差:$\delta_h = (W_{ho} \delta_o) \odot \sigma'(z_h)$
- 更新权重:
$$ W_{ho} = W_{ho} – \eta \delta_o a_h^T $$
$$ W_{ih} = W_{ih} – \eta \delta_h x^T $$
3. Python 实现
import numpy as np
from typing import Tuple
class BPNeuralNetwork:
def __init__(self, input_size: int, hidden_size: int, output_size: int):
# 初始化权重
self.W_ih = np.random.randn(input_size, hidden_size) * 0.01
self.W_ho = np.random.randn(hidden_size, output_size) * 0.01
self.b_h = np.zeros((1, hidden_size))
self.b_o = np.zeros((1, output_size))
def sigmoid(self, z: np.ndarray) -> np.ndarray:
return 1 / (1 + np.exp(-z))
def sigmoid_derivative(self, z: np.ndarray) -> np.ndarray:
s = self.sigmoid(z)
return s * (1 - s)
def forward(self, x: np.ndarray) -> Tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
# 前向传播
self.z_h = np.dot(x, self.W_ih) + self.b_h # (batch, hidden)
self.a_h = self.sigmoid(self.z_h) # (batch, hidden)
self.z_o = np.dot(self.a_h, self.W_ho) + self.b_o # (batch, output)
y_pred = self.sigmoid(self.z_o) # (batch, output)
return y_pred, self.z_o, self.a_h, self.z_h
def backward(self, x: np.ndarray, y: np.ndarray, y_pred: np.ndarray,
lr: float = 0.1) -> None:
# 反向传播
batch_size = x.shape[0]
# 输出层误差
delta_o = (y_pred - y) * self.sigmoid_derivative(self.z_o) # (batch, output)
# 隐藏层误差
delta_h = np.dot(delta_o, self.W_ho.T) * self.sigmoid_derivative(self.z_h) # (batch, hidden)
# 更新权重和偏置
self.W_ho -= lr * np.dot(self.a_h.T, delta_o) / batch_size # (hidden, output)
self.W_ih -= lr * np.dot(x.T, delta_h) / batch_size # (input, hidden)
self.b_o -= lr * np.mean(delta_o, axis=0, keepdims=True)
self.b_h -= lr * np.mean(delta_h, axis=0, keepdims=True)
4. 实践建议
4.1 学习率设置
- 初始学习率通常设置为 0.01 到 0.1
- 使用学习率衰减策略:$\eta_t = \frac{\eta_0}{1 + decay\times t}$
- 梯度裁剪防止梯度爆炸:
max_grad_norm = 5.0 total_norm = np.sqrt(sum(np.sum(np.square(grad)) for grad in grads)) clip_coef = max_grad_norm / (total_norm + 1e-6) if clip_coef < 1: for grad in grads: grad *= clip_coef
4.2 隐藏层神经元数量
- 经验公式:$N_h = \frac{N_i + N_o}{2} + \sqrt{N_{sample}}$
- 过少会导致欠拟合,过多会导致过拟合
- 可以通过交叉验证选择最优值
4.3 激活函数选择
| 任务类型 | 输出层激活函数 | 损失函数 |
|---|---|---|
| 二分类 | Sigmoid | 交叉熵 |
| 多分类 | Softmax | 交叉熵 |
| 回归 | 线性 | MSE |
5. 常见问题与解决方案
- 梯度消失问题 :
- 使用 ReLU 等非饱和激活函数
- 使用 Batch Normalization
-
残差连接
-
过拟合问题 :
- 增加 L2 正则化
- Dropout
-
早停法
-
训练集准确率高但验证集差 :
- 检查是否数据划分有问题
- 增加正则化强度
- 获取更多训练数据
6. 扩展思考
- 自动微分 :尝试用 PyTorch 重构代码,利用其自动求导功能
- 动量优化 :实现带动量的梯度下降
- 不同架构 :尝试增加隐藏层数量,观察效果变化
7. 总结
BP 神经网络是深度学习的基础,理解其工作原理对后续学习更复杂模型至关重要。建议读者:
1. 手动实现一遍代码
2. 在不同数据集上测试
3. 尝试调整各种超参数观察效果
4. 进阶学习时可以研究更优化的算法如 Adam
通过这篇文章,你应该已经掌握了 BP 神经网络的核心原理和实现方法。接下来可以尝试在实际项目中应用这些知识,或者学习更高级的神经网络结构。
正文完
