共计 2220 个字符,预计需要花费 6 分钟才能阅读完成。
几何视角下的反向传播
让我们跟随 3Blue1Brown 的经典视角,将神经网络想象成一个多维空间中的地形图。损失函数构成的高度曲面中,每个点的海拔代表当前参数的误差值。梯度向量就是站在这个点上时,脚下最陡峭的下山方向。反向传播的本质,就是通过计算图(Computational Graph)逐层回溯,找到让所有参数同步下山的优化路径。

数学推导:链式法则的舞蹈
- 符号定义
- $L$:损失函数值
- $W^{[l]}$:第 $l$ 层的权重矩阵
- $z^{[l]}$:第 $l$ 层的线性输出
-
$a^{[l]}$:第 $l$ 层的激活输出($a^{[0]}=X$)
-
关键步骤分解
以 Sigmoid 激活的双层网络为例: -
前向传播流程:
$$z^{[1]} = W^{[1]}X + b^{[1]}$$
$$a^{[1]} = \sigma(z^{[1]})$$
$$z^{[2]} = W^{[2]}a^{[1]} + b^{[2]}$$
$$\hat{y} = a^{[2]} = \sigma(z^{[2]})$$ -
反向传播链式:
$$\frac{\partial L}{\partial W^{[2]}} = \frac{\partial L}{\partial a^{[2]}} \frac{\partial a^{[2]}}{\partial z^{[2]}} \frac{\partial z^{[2]}}{\partial W^{[2]}}$$
其中每个分项可具体化为:- $\frac{\partial L}{\partial a^{[2]}} = \frac{a^{[2]} – y}{a^{[2]}(1-a^{[2]})}$(交叉熵损失推导)
- $\frac{\partial a^{[2]}}{\partial z^{[2]}} = a^{[2]}(1-a^{[2]})$(Sigmoid 导数特性)
- $\frac{\partial z^{[2]}}{\partial W^{[2]}} = a^{[1]T}$
NumPy 实战:从公式到代码
import numpy as np
class TwoLayerNet:
def __init__(self, input_size, hidden_size, output_size):
self.W1 = np.random.randn(hidden_size, input_size) * 0.01
self.b1 = np.zeros((hidden_size, 1))
self.W2 = np.random.randn(output_size, hidden_size) * 0.01
self.b2 = np.zeros((output_size, 1))
def sigmoid(self, z):
return 1/(1+np.exp(-z))
def forward(self, X):
self.z1 = np.dot(self.W1, X) + self.b1
self.a1 = self.sigmoid(self.z1)
self.z2 = np.dot(self.W2, self.a1) + self.b2
self.a2 = self.sigmoid(self.z2)
return self.a2
def backward(self, X, y, learning_rate=0.1):
m = X.shape[1]
# 输出层梯度
dz2 = (self.a2 - y) * self.a2 * (1 - self.a2) # ∂L/∂z2
dW2 = np.dot(dz2, self.a1.T) / m # ∂L/∂W2
db2 = np.sum(dz2, axis=1, keepdims=True) / m # ∂L/∂b2
# 隐藏层梯度
dz1 = np.dot(self.W2.T, dz2) * self.a1 * (1 - self.a1) # ∂L/∂z1
dW1 = np.dot(dz1, X.T) / m # ∂L/∂W1
db1 = np.sum(dz1, axis=1, keepdims=True) / m # ∂L/∂b1
# 参数更新
self.W2 -= learning_rate * dW2
self.b2 -= learning_rate * db2
self.W1 -= learning_rate * dW1
self.b1 -= learning_rate * db1
避坑实践指南
- 梯度消失 / 爆炸检测
- 监控各层梯度范数:
np.linalg.norm(dW1) -
解决方案:
- 改用 ReLU 激活函数
- 权重初始化使用 He/Xavier 方法
- 添加梯度裁剪(Gradient Clipping)
-
学习率调优
- 初始尝试范围:0.001~0.1
- 使用学习率衰减策略:
lr = initial_lr * (1 / (1 + decay_rate * epoch))
延伸思考
- PyTorch 重构挑战
尝试用torch.autograd实现相同网络,比较: - 代码简洁度差异
-
计算效率对比
-
梯度验证实验
实现数值梯度检查:def numerical_gradient(f, x, eps=1e-4): grad = np.zeros_like(x) for idx in range(x.size): tmp_val = x.flat[idx] x.flat[idx] = tmp_val + eps fxh1 = f(x) x.flat[idx] = tmp_val - eps fxh2 = f(x) grad.flat[idx] = (fxh1 - fxh2) / (2*eps) x.flat[idx] = tmp_val return grad
通过这个完整的实现链路,你会发现 3Blue1Brown 将数学直觉可视化的魔力——那些看似复杂的偏导计算,本质上都是在多维空间中寻找最优路径的导航过程。
正文完
