Momentum (Optimization)
动量优化利用过去的梯度加速模型训练、平滑带噪更新,并在平衡学习率的同时改善收敛效果。
动量是一种优化技术,它让基于梯度的训练能够记住之前的更新。通过将当前梯度与衰减的历史梯度相结合,它能沿着一致的方向加速,并减少来回摆动。这有助于机器学习模型更高效地最小化训练目标。搜索引擎优化关注网站的可见度;动量关注模型参数的数值更新。
动量的工作原理#
在梯度下降过程中,模型沿着与梯度相反的方向调整其权重——梯度指向其损失函数增长最快的方向。经典动量也称为 Polyak 动量或重球法。Boris Polyak 在其1964 年关于加速迭代方法的研究中提出了这种方法。
优化器会维护一个速度缓冲区,为每个参数保存一个累积值。每次更新时,先将旧缓冲区乘以动量系数,再加上当前梯度,然后从权重中减去该缓冲区与学习率的乘积。在神经网络中,反向传播会提供这些梯度;优化器则在各次更新之间保留缓冲区。
动量特别适用于狭长的损失曲面:谷底横向的曲率较陡,沿谷底方向的曲率较缓。沿谷底方向反复指向同一方向的梯度会不断累积,而横向交替变化的分量则会部分抵消。使用随机梯度下降时,这种记忆也能平滑不同小批次之间的波动。动量在二次损失上的动态特性解释了它为何既能加速优化,也可能在接近极小值时引入振荡。
动量、学习率及相关方法#
动量系数通常记作 beta 或 mu,一般介于零和一之间。取零时,算法退化为普通梯度下降;取值越接近一,保留旧梯度的时间就越长。0.9 是常见的初始取值。在未归一化的速度缓冲区中,若梯度恒定,系数为 0.9 时累积速度会趋近于该梯度的十倍,而系数为 0.99 时则会趋近于 100 倍。因此,在超参数调优过程中,动量与学习率会产生很强的相互作用。
如果两者的组合过于激进,就会产生过冲:更新反复越过极小值,导致损失振荡或发散。即使目标函数是平滑的二次函数,也会出现这种情况。学习率调度策略会在训练过程中改变更新幅度,而动量则决定方向历史会保留多少。
两种密切相关的优化算法以不同方式利用这种历史信息:
- Nesterov 动量会在前瞻位置计算梯度,该位置由保留的速度确定,因此梯度可以修正预期的移动方向。
- Adam将指数加权的梯度平均值与平方梯度平均值相结合,从而针对每个参数分别缩放更新。它的
beta1控制梯度记忆。
一个精简的 PyTorch 示例#
这个 PyTorch 示例在狭长的二次目标函数上,对比了起点和学习率相同的两种情况。官方 SGD 实现会自动管理动量缓冲区。
import torch
# Curvature is 50 times greater along the second coordinate.
scale = torch.tensor([1.0, 50.0])
for momentum in (0.0, 0.9):
weights = torch.tensor([5.0, 1.0], requires_grad=True)
optimizer = torch.optim.SGD([weights], lr=0.015, momentum=momentum)
for step in range(100):
optimizer.zero_grad()
loss = (scale * weights.square()).sum()
loss.backward()
optimizer.step()
final_loss = (scale * weights.square()).sum().item()
print(f"Momentum {momentum}: loss = {final_loss:.6f}")经过 100 次更新后,不使用动量时的损失约为 0.056531,使用动量时约为 0.000216。累积的方向历史加快了沿较缓坐标方向的优化进度。
在计算机视觉训练中的应用#
动量支持用于图像分类和目标检测的卷积神经网络训练。Ultralytics YOLO 训练在选择 optimizer="SGD" 时会启用 Nesterov 动量,其 momentum 设置则控制保留的更新历史。训练器实现会使用 nesterov=True 将该系数传递给优化器。
一个具有里程碑意义的应用是最初的 ResNet 训练流程,该流程针对 ImageNet。这些模型使用了动量为 0.9 的 SGD、大小为 256 的批次、0.0001 的权重衰减,以及初始值为 0.1 的学习率;当错误率停滞时,学习率会降为原来的十分之一。










