共计 1795 个字符,预计需要花费 5 分钟才能阅读完成。
为什么需要梯度下降?
神经网络的核心是通过调整权重参数来最小化损失函数。想象你在山上蒙眼找下山路,梯度下降就是靠感知脚下坡度(梯度)来决定移动方向。每次迭代时,我们计算损失函数对每个参数的偏导数(梯度),然后沿着负梯度方向更新参数。

数学表达为:
$$
w_{new} = w_{old} – \eta \cdot \frac{\partial L}{\partial w}
$$
其中 $\eta$ 是学习率,控制步长大小。
BP 梯度下降的数学推导
反向传播 (BP) 本质是链式法则的递归应用。以单隐藏层网络为例:
-
前向传播 计算预测值:
$$
z = w^Tx + b,\quad a = \sigma(z)
$$
$\sigma$ 是激活函数(如 Sigmoid) -
反向传播 时从输出层开始:
- 输出层梯度:
$$
\frac{\partial L}{\partial a} = a – y
$$ - 通过链式法则逐层回传:
$$
\frac{\partial L}{\partial w} = \frac{\partial L}{\partial a} \cdot \frac{\partial a}{\partial z} \cdot \frac{\partial z}{\partial w}
$$
主流优化算法对比
- SGD(随机梯度下降):
- 优点:实现简单,内存占用小
-
缺点:容易陷入局部最优,收敛震荡
-
Momentum:
- 引入动量项积累历史梯度:
$$
v_t = \gamma v_{t-1} + \eta \nabla L
$$ -
有效缓解震荡,加速收敛
-
Adam:
- 结合动量与自适应学习率
- 实际工程中最常用的选择
Python 实现代码
import numpy as np
class NeuralNetwork:
def __init__(self, input_size, hidden_size):
self.w1 = np.random.randn(input_size, hidden_size) * 0.01
self.b1 = np.zeros(hidden_size)
self.w2 = np.random.randn(hidden_size, 1) * 0.01
self.b2 = np.zeros(1)
def sigmoid(self, x):
return 1 / (1 + np.exp(-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
return self.sigmoid(self.z2)
def backward(self, X, y, lr=0.1):
m = X.shape[0]
# 输出层梯度
dz2 = self.forward(X) - y
dw2 = np.dot(self.a1.T, dz2) / m
db2 = np.sum(dz2, axis=0) / m
# 隐藏层梯度
dz1 = np.dot(dz2, self.w2.T) * (self.a1 * (1 - self.a1))
dw1 = np.dot(X.T, dz1) / m
db1 = np.sum(dz1, axis=0) / m
# 参数更新
self.w2 -= lr * dw2
self.b2 -= lr * db2
self.w1 -= lr * dw1
self.b1 -= lr * db1
实战注意事项
- 学习率选择:
- 常用策略:从 0.1 开始尝试,每 10 轮乘以 0.5
-
高级技巧:使用学习率预热 (warmup) 或周期性调整
-
梯度消失 / 爆炸:
- 现象:深层网络训练时梯度指数级缩小 / 增大
-
解决方案:
- 使用 ReLU 等激活函数
- 梯度裁剪(gradient clipping)
- 残差连接(residual connection)
-
批量大小:
- 太小:训练不稳定,收敛慢
- 太大:内存不足,可能陷入局部最优
- 经验值:32-256 之间
性能优化建议
- 使用向量化操作替代循环
- 对输入数据进行归一化
- 定期保存模型检查点(checkpoint)
- 监控训练过程中的 loss 和 accuracy 曲线
常见错误排查
- 现象:Loss 不下降
- 检查梯度计算是否正确
- 验证数据标签是否匹配
- 现象:Loss 出现 NaN
- 降低学习率
- 检查数据中是否存在异常值
思考题延伸
如何将 BP 梯度下降应用到 CNN 中?关键点在于:
1. 卷积核权重同样通过梯度下降更新
2. 需要处理池化层的梯度传递
3. 利用 im2col 技巧加速卷积运算
希望这篇笔记帮你打通 BP 算法的任督二脉!在实际项目中,建议先用现成框架(如 PyTorch)验证想法,再考虑自定义实现。
正文完
