深度学习入门:从零理解bp误差反向传播算法

1次阅读
没有评论

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

image.webp

神经网络基础与反向传播的必要性

神经网络通过多层感知器堆叠实现复杂函数拟合,其核心训练依赖两个过程:

深度学习入门:从零理解 bp 误差反向传播算法

  • 前向传播 :输入数据逐层计算直至输出层,产生预测结果
  • 反向传播 :根据预测误差,从输出层反向计算各层参数的梯度

传统手工计算梯度在深层网络中几乎不可行。反向传播算法通过链式法则实现高效梯度计算,解决了这一核心问题。

数学原理与链式法则

考虑单隐藏层网络,损失函数 $L$ 对权重 $w_{ij}^{(l)}$ 的梯度计算过程:

$$
\frac{\partial L}{\partial w_{ij}^{(l)}} = \frac{\partial L}{\partial z_j^{(l+1)}} \cdot \frac{\partial z_j^{(l+1)}}{\partial w_{ij}^{(l)}} = \delta_j^{(l+1)} \cdot a_i^{(l)}
$$

其中关键项 $\delta_j^{(l)}$(第 $l$ 层第 $j$ 个节点的误差项)通过反向递归计算:

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

Python 实现详解

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        # 初始化权重(使用 Xavier 初始化)self.W1 = np.random.randn(input_size, hidden_size) / np.sqrt(input_size)
        self.W2 = np.random.randn(hidden_size, output_size) / np.sqrt(hidden_size)

    def forward(self, X):
        # 前向传播计算图
        self.z1 = np.dot(X, self.W1)
        self.a1 = self.sigmoid(self.z1)
        self.z2 = np.dot(self.a1, self.W2)
        self.a2 = self.sigmoid(self.z2)
        return self.a2

    def backward(self, X, y, learning_rate):
        # 反向传播计算梯度
        m = X.shape[0]
        delta2 = (self.a2 - y) * self.sigmoid_deriv(self.z2)  # 输出层误差
        dW2 = np.dot(self.a1.T, delta2) / m

        delta1 = np.dot(delta2, self.W2.T) * self.sigmoid_deriv(self.z1)  # 隐藏层误差
        dW1 = np.dot(X.T, delta1) / m

        # 参数更新
        self.W2 -= learning_rate * dW2
        self.W1 -= learning_rate * dW1

    # 梯度检查实现(数值梯度 vs 解析梯度)def gradient_check(self, X, y, epsilon=1e-7):
        grad_approx = np.zeros_like(self.W1)
        for i in range(self.W1.shape[0]):
            for j in range(self.W1.shape[1]):
                # 计算数值梯度
                original = self.W1[i,j]
                self.W1[i,j] = original + epsilon
                loss1 = self.compute_loss(X, y)
                self.W1[i,j] = original - epsilon
                loss2 = self.compute_loss(X, y)
                grad_approx[i,j] = (loss1 - loss2) / (2*epsilon)
                self.W1[i,j] = original

        # 与解析梯度对比
        _, dW1 = self.backward(X, y, 0)  # 不更新权重
        difference = np.linalg.norm(grad_approx - dW1) / np.linalg.norm(grad_approx + dW1)
        return difference < 1e-7

关键问题分析

1. 梯度消失 / 爆炸

  • 成因 :链式法则导致梯度呈指数级变化(特别是使用 sigmoid/tanh 时)
  • 解决方案 :
  • 使用 ReLU 及其变体激活函数
  • 批归一化(BatchNorm)
  • 残差连接(ResNet)

2. 学习率选择

  • 策略对比 :
  • 固定学习率:简单但需要精细调参
  • 自适应方法:Adam/RMSProp 等自动调整
  • 学习率衰减:随训练过程逐步降低

3. 激活函数影响

函数类型 梯度特性 适用场景
Sigmoid 容易饱和(≈0) 二分类输出层
ReLU 正向梯度恒定 隐藏层首选
LeakyReLU 解决 ” 死亡 ReLU” 问题 深层网络

实践避坑指南

  1. 初始化陷阱 :避免全零初始化导致对称性问题,推荐 Xavier/He 初始化
  2. 梯度检查 :实现新网络时务必验证反向传播正确性
  3. 数值稳定性 :对 softmax 等运算使用 log-sum-exp 技巧

扩展思考

如何将反向传播扩展到卷积神经网络?考虑以下方向:
– 卷积核的梯度计算
– 池化层的梯度传递
– 感受野与参数共享机制

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