共计 1502 个字符,预计需要花费 4 分钟才能阅读完成。
为什么需要理解反向传播?
作为神经网络训练的基石,反向传播算法(Backpropagation)是每个机器学习初学者必须跨越的门槛。但第一次接触时,那些链式求导符号和梯度流动方向总让人头晕。本文将通过计算图视角,带你用 Python 从零实现这个过程。

一、前向传播的计算图拆解
假设我们有一个最简单的 3 层网络(输入层 1 个节点、隐藏层 2 个节点、输出层 1 个节点),前向传播就是数据从左到右流动的过程:
-
输入层到隐藏层 :
h1 = w1*x + b1 # 线性变换 a1 = sigmoid(h1) # 激活函数 -
隐藏层到输出层 :
y_pred = w2*a1 + b2 -
损失计算 (以均方误差为例):
loss = 0.5*(y_true - y_pred)**2
二、反向传播的数学本质
反向传播实际上是复合函数的链式求导。以输出层的权重 w2 为例:
-
计算损失对 w2 的梯度:
∂loss/∂w2 = (y_pred - y_true) * a1 -
隐藏层权重 w1 的梯度计算(需跨过 sigmoid 函数):
∂loss/∂w1 = (y_pred - y_true)*w2 * sigmoid_derivative(h1)*x
三、Python 完整实现
import numpy as np
# 定义激活函数及其导数
def sigmoid(x):
return 1/(1+np.exp(-x))
def sigmoid_derivative(x):
return x*(1-x)
# 网络参数初始化
w1 = np.random.randn(2,1)
w2 = np.random.randn(1,2)
b1 = np.zeros((2,1))
b2 = 0
# 前向传播
def forward(x):
h1 = w1.dot(x) + b1
a1 = sigmoid(h1)
y_pred = w2.dot(a1) + b2
return y_pred, a1
# 反向传播
def backward(x, y_true, y_pred, a1):
# 输出层梯度
dy_pred = y_pred - y_true
dw2 = dy_pred * a1.T
db2 = dy_pred
# 隐藏层梯度
da1 = w2.T.dot(dy_pred)
dh1 = da1 * sigmoid_derivative(a1)
dw1 = dh1.dot(x.T)
db1 = dh1
return dw1, dw2, db1, db2
四、可视化梯度流动
通过 matplotlib 可以绘制梯度在层间的传递过程:
- 红色箭头表示前向传播
- 蓝色虚线表示反向梯度
- 线条粗细对应参数更新幅度
五、常见问题解决方案
- 梯度消失 :
- 使用 ReLU 等替代 sigmoid
-
批归一化(BatchNorm)
-
学习率设置 :
- 初始建议 0.001-0.1
- 采用自适应优化器(Adam)
六、MNIST 实战案例
from sklearn.datasets import fetch_openml
mnist = fetch_openml('mnist_784')
X = mnist.data / 255.0
y = mnist.target.astype(int)
# 简单网络结构:784-128-10
model = NeuralNetwork(layers=[784, 128, 10])
# 训练过程可视化
for epoch in range(10):
loss = model.train(X_train, y_train, lr=0.01)
print(f"Epoch {epoch}, Loss: {loss:.4f}")
改进建议 :
1. 尝试增加隐藏层数量
2. 更换不同激活函数
3. 添加 Dropout 层防止过拟合
写在最后
理解反向传播最有效的方式就是动手实现它。建议读者先在小规模网络上(比如 2 - 3 个神经元)用纸笔推导梯度,再扩展到实际应用中。当你能清晰解释每一行代码对应的数学原理时,就真正掌握了这个算法的精髓。
正文完
