BP反向传播案例实战:从数学推导到Python实现

1次阅读
没有评论

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

image.webp

神经网络结构与前向传播

我们以一个单隐藏层的神经网络为例,结构如下:

BP 反向传播案例实战:从数学推导到 Python 实现

  • 输入层:2 个节点(特征维度)
  • 隐藏层:3 个节点(使用 sigmoid 激活)
  • 输出层:1 个节点(二分类任务)

数学表达:

  1. 输入层到隐藏层计算:
    $$ z_1 = W_1X + b_1 $$
    $$ a_1 = \sigma(z_1) $$

  2. 隐藏层到输出层计算:
    $$ z_2 = W_2a_1 + b_2 $$
    $$ \hat{y} = \sigma(z_2) $$

其中 $\sigma(x)=\frac{1}{1+e^{-x}}$,$W_1$ 是 3×2 矩阵,$W_2$ 是 1×3 矩阵。

反向传播推导

使用均方误差损失函数:
$$ L = \frac{1}{2}(y-\hat{y})^2 $$

输出层梯度

  1. 损失对输出的梯度:
    $$ \frac{\partial L}{\partial \hat{y}} = \hat{y} – y $$

  2. 经过 sigmoid 激活的梯度:
    $$ \frac{\partial \hat{y}}{\partial z_2} = \hat{y}(1-\hat{y}) $$

  3. 链式法则合并:
    $$ \delta_2 = \frac{\partial L}{\partial z_2} = (\hat{y}-y)\hat{y}(1-\hat{y}) $$

隐藏层梯度

  1. 输出层权重梯度:
    $$ \frac{\partial z_2}{\partial W_2} = a_1 $$
    $$ \frac{\partial L}{\partial W_2} = \delta_2 a_1^T $$

  2. 继续反向传播:
    $$ \delta_1 = W_2^T \delta_2 \odot a_1 \odot (1-a_1) $$

  3. 输入层权重梯度:
    $$ \frac{\partial L}{\partial W_1} = \delta_1 X^T $$

Python 实现

import numpy as np

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

def forward(X, W1, b1, W2, b2):
    z1 = np.dot(W1, X) + b1  # 3x1
    a1 = sigmoid(z1)          # 3x1
    z2 = np.dot(W2, a1) + b2  # 1x1
    y_hat = sigmoid(z2)       # 1x1
    return a1, y_hat

def backward(X, y, a1, y_hat, W2):
    delta2 = (y_hat - y) * y_hat * (1 - y_hat)  # 1x1
    dW2 = delta2 * a1.T                         # 1x3

    delta1 = np.dot(W2.T, delta2) * a1 * (1 - a1)  # 3x1
    dW1 = np.dot(delta1, X.T)                     # 3x2

    return dW1, dW2

避坑指南

  • 学习率选择:过大学习率会导致梯度爆炸(建议从 0.01 开始尝试)
  • 数据标准化 :输入特征应归一化到[0,1] 或标准化(均值 0 方差 1)
  • 隐藏层节点:通常取输入特征的 1~2 倍,可通过交叉验证调整

思考题

  1. 如何用 ReLU 替代 sigmoid?提示:需要修改激活函数和对应的梯度计算
  2. 批量训练时如何调整代码?提示:注意矩阵维度变化(X 变为 n×2)
  3. L2 正则化应该加在哪里?提示:在损失函数和梯度计算中都需要添加

实践心得

通过这个案例,我深刻理解了反向传播的链式法则本质。最初容易犯的维度错误,通过打印矩阵 shape 可以快速定位。建议初学者先用小学习率确保收敛,再逐步调整参数。

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