BP神经网络算法流程图详解:从数学原理到Python实现

1次阅读
没有评论

共计 2693 个字符,预计需要花费 7 分钟才能阅读完成。

image.webp

1. 神经网络基础概念

BP 神经网络(Back Propagation Neural Network)是一种多层前馈神经网络,通过误差反向传播算法训练权重。它由输入层、隐藏层和输出层组成,每层包含多个神经元。

BP 神经网络算法流程图详解:从数学原理到 Python 实现

  • 神经元结构 :每个神经元接收前一层神经元的输出,经过加权求和后通过激活函数产生输出
  • 前向传播 :数据从输入层流向输出层
  • 反向传播 :误差从输出层反向传播到输入层,用于调整权重

2. BP 算法流程图解

2.1 前向传播阶段

 输入层 -> 隐藏层 -> 输出层
    |         |         |
    W_ih     W_ho     y_pred
  1. 输入数据通过输入层传递
  2. 计算隐藏层输入:$z_h = W_{ih}^T x + b_h$
  3. 应用激活函数:$a_h = \sigma(z_h)$
  4. 计算输出层输入:$z_o = W_{ho}^T a_h + b_o$
  5. 应用输出层激活函数:$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
  1. 计算输出层误差:$\delta_o = y_{pred} – y$
  2. 计算隐藏层误差:$\delta_h = (W_{ho} \delta_o) \odot \sigma'(z_h)$
  3. 更新权重:
    $$ 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. 常见问题与解决方案

  1. 梯度消失问题
  2. 使用 ReLU 等非饱和激活函数
  3. 使用 Batch Normalization
  4. 残差连接

  5. 过拟合问题

  6. 增加 L2 正则化
  7. Dropout
  8. 早停法

  9. 训练集准确率高但验证集差

  10. 检查是否数据划分有问题
  11. 增加正则化强度
  12. 获取更多训练数据

6. 扩展思考

  • 自动微分 :尝试用 PyTorch 重构代码,利用其自动求导功能
  • 动量优化 :实现带动量的梯度下降
  • 不同架构 :尝试增加隐藏层数量,观察效果变化

7. 总结

BP 神经网络是深度学习的基础,理解其工作原理对后续学习更复杂模型至关重要。建议读者:
1. 手动实现一遍代码
2. 在不同数据集上测试
3. 尝试调整各种超参数观察效果
4. 进阶学习时可以研究更优化的算法如 Adam

通过这篇文章,你应该已经掌握了 BP 神经网络的核心原理和实现方法。接下来可以尝试在实际项目中应用这些知识,或者学习更高级的神经网络结构。

正文完
 0
评论(没有评论)