深度学习基础:从数学推导到代码实现 BF反向传播算法

1次阅读
没有评论

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

image.webp

为什么需要反向传播算法

在神经网络中,我们需要通过调整权重来最小化损失函数。这个过程类似于教一个孩子学习:每次犯错后,我们需要告诉孩子错在哪里以及如何改正。反向传播算法就是神经网络中的这个 ” 教学 ” 过程。

深度学习基础:从数学推导到代码实现 BF 反向传播算法

  • 前向传播:输入数据通过网络层层传递,最终产生预测结果
  • 反向传播:根据预测结果与真实值的差异,从输出层反向计算各层参数的梯度
  • 权重更新:根据梯度下降算法调整网络参数

BF 反向传播算法数学推导

让我们从一个简单的 3 层神经网络 (输入层、隐藏层、输出层) 开始推导。假设我们使用均方误差 (MSE) 作为损失函数:

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

1. 输出层梯度计算

对于输出层的权重 $w_{ij}$,我们需要计算 $\frac{\partial L}{\partial w_{ij}}$:

  1. 计算损失对输出的偏导:$\frac{\partial L}{\partial \hat{y}} = \hat{y} – y$
  2. 计算输出对激活的偏导:$\frac{\partial \hat{y}}{\partial z} = \sigma'(z)$
  3. 计算激活对权重的偏导:$\frac{\partial z}{\partial w_{ij}} = a_j$

根据链式法则,最终梯度为:

$$ \frac{\partial L}{\partial w_{ij}} = (\hat{y} – y) \cdot \sigma'(z) \cdot a_j $$

2. 隐藏层梯度计算

对于隐藏层的权重 $w_{jk}$,我们需要计算 $\frac{\partial L}{\partial w_{jk}}$。这需要反向传播误差:

  1. 计算隐藏层误差 $\delta_j$:$\delta_j = \sum_i \delta_i w_{ij} \cdot \sigma'(z_j)$
  2. 然后计算权重梯度:$\frac{\partial L}{\partial w_{jk}} = \delta_j \cdot a_k$

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.W2 = np.random.randn(hidden_size, output_size)

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

    def sigmoid_derivative(self, x):
        return x * (1 - x)

    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, output, learning_rate):
        # 反向传播
        error = output - y

        # 输出层梯度
        delta2 = error * self.sigmoid_derivative(output)
        dW2 = np.dot(self.a1.T, delta2)

        # 隐藏层梯度
        error_hidden = np.dot(delta2, self.W2.T)
        delta1 = error_hidden * self.sigmoid_derivative(self.a1)
        dW1 = np.dot(X.T, delta1)

        # 更新权重
        self.W2 -= learning_rate * dW2
        self.W1 -= learning_rate * dW1

复杂度分析

  • 时间复杂度:O(W),其中 W 是网络中权重的总数
  • 空间复杂度:O(W),需要存储所有权重和中间激活值

避坑指南

  • 梯度消失问题:当使用 sigmoid 激活函数时,深层网络容易出现梯度消失
  • 解决方案:使用 ReLU 等激活函数
  • 学习率选择不当:太大导致震荡,太小导致收敛慢
  • 解决方案:使用学习率衰减或自适应优化器
  • 权重初始化问题:全部初始化为 0 会导致对称性问题
  • 解决方案:使用随机初始化
  • 数值不稳定:中间计算结果可能溢出
  • 解决方案:使用数值稳定的实现方式

思考题

  1. 如果我们将激活函数从 sigmoid 改为 ReLU,反向传播的推导会发生什么变化?
  2. 对于分类问题,为什么我们通常不使用 MSE 而使用交叉熵损失函数?
  3. 当网络很深时,除了梯度消失问题,还可能遇到什么问题?如何解决?

总结

通过本文的推导和实现,你应该对反向传播算法有了更深入的理解。理解这些数学原理不仅可以帮助你更好地调试神经网络,还能为后续学习更复杂的模型打下坚实基础。建议你尝试扩展这个简单网络,比如增加更多隐藏层或使用不同的激活函数,观察训练效果的变化。

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