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

1次阅读
没有评论

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

image.webp

为什么需要多层神经网络?

单层感知机(Perceptron)的局限性在于它只能解决线性可分问题。例如,它无法处理异或(XOR)这样简单的非线性问题。多层神经网络通过引入隐藏层和非线性激活函数,能够学习更复杂的模式。

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

反向传播的数学原理

反向传播的核心是链式法则。我们以均方误差(MSE)作为损失函数,Sigmoid 作为激活函数,推导权重更新的过程。

  1. 定义损失函数 :
    [E = \frac{1}{2} \sum_{k}(y_k – t_k)^2]
    其中,(y_k) 是输出层的第 k 个神经元的输出,(t_k) 是对应的目标值。

  2. 输出层的梯度计算 :
    [\frac{\partial E}{\partial w_{jk}} = \frac{\partial E}{\partial y_k} \cdot \frac{\partial y_k}{\partial z_k} \cdot \frac{\partial z_k}{\partial w_{jk}}]
    其中,(z_k) 是加权输入。

  3. 隐藏层的梯度计算 :
    类似地,隐藏层的梯度需要通过链式法则从输出层反向传播:
    [\frac{\partial E}{\partial w_{ij}} = \frac{\partial E}{\partial h_j} \cdot \frac{\partial h_j}{\partial z_j} \cdot \frac{\partial z_j}{\partial w_{ij}}]

Python 实现

以下是使用 NumPy 实现的一个简单反向传播示例:

import numpy as np

# Sigmoid 激活函数
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# 均方误差损失函数
def mse_loss(y_true, y_pred):
    return np.mean((y_true - y_pred) ** 2)

# 初始化权重
input_size = 2
hidden_size = 3
output_size = 1

W1 = np.random.randn(input_size, hidden_size)
W2 = np.random.randn(hidden_size, output_size)

# 前向传播
def forward(X):
    z1 = np.dot(X, W1)
    h = sigmoid(z1)
    z2 = np.dot(h, W2)
    y = sigmoid(z2)
    return y, h

# 反向传播
def backward(X, y_true, y_pred, h):
    # 输出层梯度
    dE_dy = y_pred - y_true
    dy_dz2 = y_pred * (1 - y_pred)
    dz2_dW2 = h

    # 隐藏层梯度
    dz2_dh = W2
    dh_dz1 = h * (1 - h)
    dz1_dW1 = X

    # 更新权重
    global W1, W2
    W2 -= learning_rate * np.dot(h.T, dE_dy * dy_dz2)
    W1 -= learning_rate * np.dot(X.T, np.dot(dE_dy * dy_dz2, dz2_dh.T) * dh_dz1)

避坑指南

  1. 梯度消失问题 :
    Sigmoid 激活函数在输入值较大或较小时梯度接近于 0,导致梯度消失。可以通过使用 ReLU 激活函数或批归一化(Batch Normalization)来缓解。

  2. 学习率设置 :
    学习率过大可能导致震荡,过小则收敛缓慢。建议从 0.01 开始尝试,逐步调整。

  3. 权重初始化 :
    权重初始化为 0 会导致所有神经元更新相同。通常使用随机初始化,如 Xavier 初始化。

思考题

  1. 如何用 ReLU 激活函数修改本代码?
  2. 批量训练与在线训练的梯度计算差异是什么?

希望这篇内容能帮助你理解反向传播的原理和实现。如果有任何问题,欢迎在评论区讨论!

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