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

1次阅读
没有评论

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

image.webp

1. 从单层感知机到多层网络

1.1 单层感知机的梯度下降

单层感知机的权重更新公式为:

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

$$\Delta w_{ij} = -\eta \frac{\partial E}{\partial w_{ij}}$$

其中 $E$ 是损失函数,$\eta$ 为学习率。对于平方误差损失:

$$E = \frac{1}{2}(y – \hat{y})^2$$

1.2 多层网络的链式法则

在多层网络中,误差需要从输出层逐层反向传播。根据链式法则:

$$\frac{\partial E}{\partial w_{ij}^{(l)}} = \frac{\partial E}{\partial z_j^{(l)}} \cdot \frac{\partial z_j^{(l)}}{\partial w_{ij}^{(l)}}$$

其中 $z_j^{(l)}$ 表示第 $l$ 层第 $j$ 个神经元的加权输入。

2. 反向传播的数学推导

2.1 输出层误差计算

对于输出层 $L$ 的神经元 $j$:

$$\delta_j^{(L)} = \frac{\partial E}{\partial z_j^{(L)}} = (y_j – \hat{y}_j) \cdot f'(z_j^{(L)})$$

2.2 隐藏层误差传播

对于隐藏层 $l$ 的神经元 $j$:

$$\delta_j^{(l)} = \left(\sum_{k} w_{jk}^{(l+1)} \delta_k^{(l+1)} \right) f'(z_j^{(l)})$$

2.3 权重更新公式

最终权重更新量为:

$$\Delta w_{ij}^{(l)} = -\eta \cdot \delta_j^{(l)} \cdot a_i^{(l-1)}$$

3. Python 实现

import numpy as np

class NeuralNetwork:
    def __init__(self, layers):
        self.layers = layers
        self.weights = [np.random.randn(y, x) 
                        for x, y in zip(layers[:-1], layers[1:])]

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

    def sigmoid_derivative(self, z):
        return self.sigmoid(z) * (1 - self.sigmoid(z))

    def forward(self, X):
        self.activations = [X]
        self.z_values = []

        for w in self.weights:
            z = np.dot(self.activations[-1], w.T)
            self.z_values.append(z)
            self.activations.append(self.sigmoid(z))

        return self.activations[-1]

    def backward(self, X, y, learning_rate):
        # 输出层误差
        delta = (self.activations[-1] - y) * \
                self.sigmoid_derivative(self.z_values[-1])

        # 反向传播
        for l in range(len(self.weights)-1, 0, -1):
            # 更新权重
            self.weights[l] -= learning_rate * \
                np.dot(delta.T, self.activations[l])

            # 计算前一层的误差
            delta = np.dot(delta, self.weights[l]) * \
                    self.sigmoid_derivative(self.z_values[l-1])

        # 更新第一层权重
        self.weights[0] -= learning_rate * \
            np.dot(delta.T, self.activations[0])

4. 避坑指南

4.1 梯度消失 / 爆炸

  • 使用 ReLU 等非饱和激活函数
  • 初始化权重时使用 Xavier 或 He 初始化
  • 添加 Batch Normalization 层

4.2 学习率设置

  • 初始值通常设置在 0.01 到 0.1 之间
  • 使用学习率衰减策略
  • 考虑自适应优化器 (Adam, RMSprop)

4.3 激活函数选择

  • 输出层根据任务选择 (sigmoid/softmax 用于分类)
  • 隐藏层推荐 ReLU 及其变种
  • 避免在深度网络中使用 sigmoid

5. 思考题

  1. 如何验证反向传播实现的正确性?
  2. 批量训练与在线训练的梯度计算差异?
  3. 二阶优化算法相比 SGD 的优势与代价?

通过本文的推导和实现,相信读者已经对 BP 神经网络的反向传播机制有了深入理解。建议动手实现代码并尝试不同的网络结构和超参数,这是掌握深度学习的最佳途径。

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