共计 1623 个字符,预计需要花费 5 分钟才能阅读完成。
1. 单层感知机的梯度计算
我们先从最简单的单层感知机开始理解梯度计算。假设我们有一个线性神经元,其输出为:

$$ y = \sigma(wx + b) $$
其中 $\sigma$ 是激活函数,$w$ 是权重,$b$ 是偏置。损失函数 $L$ 通常采用均方误差:
$$ L = \frac{1}{2}(y – t)^2 $$
其中 $t$ 是目标值。根据链式法则,权重 $w$ 的梯度为:
$$ \frac{\partial L}{\partial w} = \frac{\partial L}{\partial y} \cdot \frac{\partial y}{\partial (wx+b)} \cdot \frac{\partial (wx+b)}{\partial w} $$
2. 多层神经网络的反向传播
对于多层神经网络,误差需要从输出层反向传播到输入层。以两层网络为例,前向传播过程为:
- 第一层:$ z_1 = W_1x + b_1 $
- 第一层激活:$ a_1 = \sigma(z_1) $
- 第二层:$ z_2 = W_2a_1 + b_2 $
- 输出:$ y = \sigma(z_2) $
反向传播时,我们需要计算各层的梯度:
- 输出层误差:$ \delta_2 = (y-t) \cdot \sigma'(z_2) $
- 隐藏层误差:$ \delta_1 = (W_2^T \delta_2) \cdot \sigma'(z_1) $
- 权重梯度:$ \nabla W_2 = \delta_2 a_1^T $,$ \nabla W_1 = \delta_1 x^T $
3. Python 实现示例
import numpy as np
# 定义激活函数及其导数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
s = sigmoid(x)
return s * (1 - s)
# 网络参数
input_size = 3
hidden_size = 4
output_size = 1
learning_rate = 0.1
# 初始化权重
W1 = np.random.randn(hidden_size, input_size)
W2 = np.random.randn(output_size, hidden_size)
# 前向传播
def forward(x):
z1 = np.dot(W1, x)
a1 = sigmoid(z1)
z2 = np.dot(W2, a1)
y = sigmoid(z2)
return y, a1, z1
# 反向传播
def backward(x, t, y, a1, z1):
# 计算输出层误差
delta2 = (y - t) * sigmoid_derivative(y)
# 计算隐藏层误差
delta1 = np.dot(W2.T, delta2) * sigmoid_derivative(a1)
# 更新权重
global W1, W2
W2 -= learning_rate * np.outer(delta2, a1)
W1 -= learning_rate * np.outer(delta1, x)
# 训练过程
for epoch in range(1000):
# 这里应该使用实际的数据集
x = np.random.randn(input_size)
t = np.random.randn(output_size)
y, a1, z1 = forward(x)
backward(x, t, y, a1, z1)
4. 避坑指南
学习率选择
- 太大:可能导致震荡或发散
- 太小:训练过程缓慢
- 建议:从 0.01 开始尝试,使用学习率衰减策略
梯度消失 / 爆炸
- 深层网络容易出现梯度指数级减小或增大
- 解决方案:
- 使用 ReLU 等激活函数
- 批归一化
- 残差连接
激活函数选择
- Sigmoid:容易导致梯度消失
- ReLU:计算简单,缓解梯度消失
- LeakyReLU:解决 ReLU 的 ” 死亡 ” 问题
5. 思考题
- 如何修改代码实现批量梯度下降?
- 不同优化器 (如 Adam) 如何改变反向传播过程?
- 为什么 ReLU 能缓解梯度消失问题?
通过本文的讲解和代码实现,希望读者能够深入理解 bp 反向传播的核心机制。在实际应用中,还需要考虑正则化、优化器选择等更多因素。建议读者尝试扩展代码,实现更复杂的网络结构。
正文完
