BP神经网络反向传播图解:从数学原理到Python实现

1次阅读
没有评论

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

image.webp

计算图视角下的反向传播原理

BP 神经网络的核心在于通过误差反向传播调整权重。我们先从计算图角度理解这个过程:

BP 神经网络反向传播图解:从数学原理到 Python 实现

  1. 前向传播计算
  2. 输入层到隐藏层:$h = \sigma(W_1 x + b_1)$
  3. 隐藏层到输出层:$\hat{y} = \sigma(W_2 h + b_2)$
  4. 其中 $\sigma$ 是 sigmoid 激活函数

  5. 损失函数计算

  6. 采用均方误差:$L = \frac{1}{2}(y – \hat{y})^2$

  7. 反向传播关键步骤

  8. 输出层梯度:$\frac{\partial L}{\partial W_2} = (\hat{y} – y) \cdot \sigma'(z_2) \cdot h^T$
  9. 隐藏层梯度:$\frac{\partial L}{\partial W_1} = \delta_{hidden} \cdot x^T$
  10. 其中 $\delta_{hidden} = (W_2^T \delta_{output}) \odot \sigma'(z_1)$

Python 实现核心代码

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        # 初始化权重
        self.W1 = np.random.randn(input_size, hidden_size)
        self.b1 = np.zeros(hidden_size)
        self.W2 = np.random.randn(hidden_size, output_size)
        self.b2 = np.zeros(output_size)

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def forward(self, x):
        self.z1 = np.dot(x, self.W1) + self.b1
        self.h = self.sigmoid(self.z1)
        self.z2 = np.dot(self.h, self.W2) + self.b2
        return self.sigmoid(self.z2)

    def backward(self, x, y, lr=0.1):
        # 前向传播
        y_pred = self.forward(x)

        # 计算输出层梯度
        dL_dz2 = (y_pred - y) * y_pred * (1 - y_pred)
        dW2 = np.dot(self.h.T, dL_dz2)
        db2 = np.sum(dL_dz2, axis=0)

        # 计算隐藏层梯度
        dL_dh = np.dot(dL_dz2, self.W2.T)
        dL_dz1 = dL_dh * self.h * (1 - self.h)
        dW1 = np.dot(x.T, dL_dz1)
        db1 = np.sum(dL_dz1, axis=0)

        # 更新权重
        self.W2 -= lr * dW2
        self.b2 -= lr * db2
        self.W1 -= lr * dW1
        self.b1 -= lr * db1

可视化梯度流动

使用 matplotlib 可以绘制梯度流动示意图:

  1. 正向传播时数据从左向右流动
  2. 反向传播时红色箭头表示梯度传播方向
  3. 线宽代表梯度大小,越宽表示该连接权重更新幅度越大

常见问题与解决方案

  1. 梯度消失问题
  2. 现象:深层网络训练时梯度逐渐变小
  3. 解决方案:

    • 使用 ReLU 等非饱和激活函数
    • 采用 Batch Normalization
    • 残差连接结构
  4. 学习率设置

  5. 太大:可能导致震荡无法收敛
  6. 太小:训练速度过慢
  7. 自适应方法:Adam、RMSprop 等优化器

  8. 过拟合处理

  9. Dropout 随机失活
  10. L2 正则化
  11. 早停法 (Early Stopping)

MNIST 实战案例

from sklearn.datasets import fetch_openml
from sklearn.model_selection import train_test_split

# 加载数据
mnist = fetch_openml('mnist_784')
X = mnist.data / 255.0
y = np.eye(10)[mnist.target.astype(int)]

# 划分数据集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

# 训练网络
nn = NeuralNetwork(784, 128, 10)
for epoch in range(10):
    for i in range(0, len(X_train), 32):
        batch_x = X_train[i:i+32]
        batch_y = y_train[i:i+32]
        nn.backward(batch_x, batch_y)

    # 评估
    test_pred = nn.forward(X_test)
    accuracy = np.mean(np.argmax(test_pred, axis=1) == np.argmax(y_test, axis=1))
    print(f"Epoch {epoch}, Accuracy: {accuracy:.4f}")

调参建议

  1. 尝试不同隐藏层大小(如 64、256)
  2. 调整学习率(0.01-0.5 范围)
  3. 增加隐藏层数量(需注意梯度消失)
  4. 尝试不同的激活函数

通过本文的数学推导和代码实现,相信你对 BP 神经网络的反向传播机制有了清晰理解。建议动手调整网络参数,观察对模型性能的影响,这是掌握神经网络的最佳方式。

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