共计 1981 个字符,预计需要花费 5 分钟才能阅读完成。
神经网络与反向传播基础
要理解反向传播(backpropagation),我们得先从神经网络的前向传播说起。假设我们有一个最简单的三层网络(输入层、隐藏层、输出层),前向传播就是数据从输入层流向输出层的过程。

- 前向传播公式 :
- 隐藏层输入:$z_h = w_{ih}^T x + b_h$
- 隐藏层输出:$a_h = \sigma(z_h)$(σ 表示激活函数)
- 输出层输入:$z_o = w_{ho}^T a_h + b_o$
-
最终输出:$a_o = \sigma(z_o)$
-
损失函数 :
我们用均方误差(MSE)衡量预测值与真实值的差距:
$$ L = \frac{1}{2}(y – a_o)^2 $$
反向传播的数学推导
反向传播的核心是链式法则。我们需要计算损失函数对每个权重($w_{ho}$ 和 $w_{ih}$)的偏导数。
输出层权重更新
-
计算损失对输出层输入的梯度:
$$ \frac{\partial L}{\partial z_o} = \frac{\partial L}{\partial a_o} \cdot \frac{\partial a_o}{\partial z_o} = -(y – a_o) \cdot \sigma'(z_o) $$ -
由此得到输出层权重梯度:
$$ \frac{\partial L}{\partial w_{ho}} = \frac{\partial L}{\partial z_o} \cdot a_h $$
隐藏层权重更新
-
损失对隐藏层输出的梯度:
$$ \frac{\partial L}{\partial a_h} = \frac{\partial L}{\partial z_o} \cdot w_{ho} $$ -
通过激活函数传递到隐藏层输入:
$$ \frac{\partial L}{\partial z_h} = \frac{\partial L}{\partial a_h} \cdot \sigma'(z_h) $$ -
最终得到输入层权重梯度:
$$ \frac{\partial L}{\partial w_{ih}} = \frac{\partial L}{\partial z_h} \cdot x $$
Python 实现代码
import numpy as np
# Sigmoid 激活函数及其导数
def sigmoid(x):
return 1 / (1 + np.exp(-x))
def sigmoid_derivative(x):
return x * (1 - x)
# 网络初始化
input_size = 3
hidden_size = 4
output_size = 1
learning_rate = 0.1
# 随机初始化权重(-0.5 到 0.5 之间)weights_ih = np.random.rand(input_size, hidden_size) - 0.5
weights_ho = np.random.rand(hidden_size, output_size) - 0.5
# 前向传播
def forward(x):
hidden_input = np.dot(x, weights_ih)
hidden_output = sigmoid(hidden_input)
output_input = np.dot(hidden_output, weights_ho)
output = sigmoid(output_input)
return hidden_output, output
# 反向传播
def train(x, y):
hidden_output, output = forward(x)
# 输出层误差
output_error = y - output
output_delta = output_error * sigmoid_derivative(output)
# 隐藏层误差
hidden_error = output_delta.dot(weights_ho.T)
hidden_delta = hidden_error * sigmoid_derivative(hidden_output)
# 更新权重
weights_ho += hidden_output.T.dot(output_delta) * learning_rate
weights_ih += x.T.dot(hidden_delta) * learning_rate
避坑指南
- 梯度消失问题 :
- 当使用 sigmoid 激活函数时,其导数最大值为 0.25,多层连乘会导致梯度指数级减小
-
解决方案:使用 ReLU 等激活函数,或采用残差连接
-
学习率选择 :
- 太大:震荡无法收敛
- 太小:训练速度过慢
-
建议:从 0.01 开始尝试,配合学习率衰减策略
-
权重初始化 :
- 全零初始化会导致神经元对称性问题
- 推荐:Xavier 初始化(权重范围±1/√n)
思考题
- 如何修改代码实现 ReLU 激活函数?需要注意什么?
- 批量训练(batch)与在线训练(online)在实现上有哪些差异?
- 相比梯度下降,Adam 等二阶优化算法有哪些优势?
希望这篇指南能帮你打通反向传播的任督二脉。记住,推导时多画计算图,写代码时多 print 中间结果,实践出真知!
