共计 2187 个字符,预计需要花费 6 分钟才能阅读完成。
背景介绍
反向传播(Backpropagation)是训练神经网络的核心算法之一,它通过计算损失函数对网络参数的梯度,利用梯度下降法来优化网络权重。没有反向传播,深度学习的快速发展几乎是不可能的。理解反向传播的数学原理,不仅能帮助我们更好地调试模型,还能在遇到问题时快速定位原因。

数学推导
1. 前向传播
假设我们有一个简单的 3 层神经网络(输入层、隐藏层、输出层),前向传播过程可以表示为:
- 输入层到隐藏层:$z^1 = W^1 x + b^1$, $a^1 = \sigma(z^1)$
- 隐藏层到输出层:$z^2 = W^2 a^1 + b^2$, $a^2 = \sigma(z^2)$
其中 $\sigma$ 是激活函数(如 Sigmoid),$W$ 和 $b$ 分别是权重和偏置。
2. 损失函数
我们使用均方误差作为损失函数:
$L = \frac{1}{2}(y – a^2)^2$
3. 反向传播
反向传播的核心是链式法则。我们需要计算损失函数对各层参数的梯度:
- 输出层梯度:
- $\frac{\partial L}{\partial z^2} = \frac{\partial L}{\partial a^2} \cdot \frac{\partial a^2}{\partial z^2} = (a^2 – y) \cdot \sigma'(z^2)$
- $\frac{\partial L}{\partial W^2} = \frac{\partial L}{\partial z^2} \cdot a^1$
-
$\frac{\partial L}{\partial b^2} = \frac{\partial L}{\partial z^2}$
-
隐藏层梯度:
- $\frac{\partial L}{\partial z^1} = \frac{\partial L}{\partial z^2} \cdot W^2 \cdot \sigma'(z^1)$
- $\frac{\partial L}{\partial W^1} = \frac{\partial L}{\partial z^1} \cdot x$
- $\frac{\partial L}{\partial b^1} = \frac{\partial L}{\partial z^1}$
代码实现
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.b1 = np.zeros(hidden_size)
self.W2 = np.random.randn(hidden_size, output_size)
self.b2 = np.zeros(output_size)
def sigmoid(self, x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(self, x):
return self.sigmoid(x) * (1 - self.sigmoid(x))
def forward(self, x):
self.z1 = np.dot(x, self.W1) + self.b1
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.a1, self.W2) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
def backward(self, x, y, learning_rate):
# 计算输出层梯度
error = self.a2 - y
delta2 = error * self.sigmoid_derivative(self.z2)
# 计算隐藏层梯度
error_hidden = np.dot(delta2, self.W2.T)
delta1 = error_hidden * self.sigmoid_derivative(self.z1)
# 更新权重
self.W2 -= learning_rate * np.outer(self.a1, delta2)
self.b2 -= learning_rate * delta2
self.W1 -= learning_rate * np.outer(x, delta1)
self.b1 -= learning_rate * delta1
常见问题
梯度消失 / 爆炸
当网络层数较深时,梯度可能在反向传播过程中变得非常小(消失)或非常大(爆炸)。解决方案包括:
- 使用 ReLU 等非饱和激活函数
- 使用 Batch Normalization
- 合理的权重初始化(如 Xavier 初始化)
性能优化
学习率调整
- 使用学习率衰减策略
- 自适应学习率方法(如 Adam)
动量法
动量法可以加速收敛并减少震荡:
$v = \beta v + (1-\beta)\nabla_\theta J(\theta)$
$\theta = \theta – \alpha v$
避坑指南
- 激活函数选择不当:避免在隐藏层使用 Sigmoid,改用 ReLU
- 学习率设置过大:会导致震荡甚至发散
- 数据未归一化:可能导致训练困难
- 忘记初始化偏置项:应初始化为 0 或小随机数
思考题
如何将算法扩展到批量训练场景?可以考虑以下方向:
- 计算批量数据的平均梯度
- 使用矩阵运算代替循环
- 考虑 GPU 并行计算
理解反向传播的数学原理是掌握神经网络的关键。通过本文的推导和代码实现,希望读者能够更深入地理解这一核心算法,并在实践中灵活应用。
正文完
