Skip to content

动量法

动量法是梯度下降(及 SGD、小批量 SGD)的 “加速升级包”—— 核心是给登山者加 “惯性”,让顺坡方向冲得更快,震荡方向稳得更牢,专门解决梯度下降在 “狭窄峡谷”(目标函数凹凸不平、不同方向梯度差异大)里的收敛慢、震荡大的问题,是深度学习里常用的优化算法之一。

一、核心逻辑:为啥需要 “惯性登山”?

1. 梯度下降的痛点

梯度下降(包括 SGD、小批量 SGD)在遇到 “狭窄峡谷” 地形时(比如目标函数 方向平缓、 方向陡峭),会陷入两难:

  • 学习率太小: 方向(平缓坡)走得极慢,20 轮迭代还在半山腰;

  • 学习率太大: 方向(陡峭坡)会来回震荡甚至发散,根本下不了山。

alt text

这就像登山者在 “窄峡谷” 里:一侧坡缓、一侧坡陡,每步都要重新判断方向,要么慢得离谱,要么晃得摔倒。

2. 动量法的解决方案

动量法给登山者加了 “惯性”——记住过去的下山方向,积累冲劲

  • 顺坡方向(比如 的平缓坡):过去的梯度方向一致,惯性会不断积累,像顺坡冲下去,速度越来越快;

  • 震荡方向(比如 的陡峭坡):过去的梯度方向来回相反,惯性会抵消反向的梯度,像冲坡时稳住重心,不会来回晃。

简单说:动量法让 “对的方向更顺,错的方向更稳”。

二、动量法的核心原理

1. 核心公式

动量法不直接用当前梯度更新参数,而是先计算 “动量”(过去梯度的加权平均),再用动量更新参数:

其中:

  • :动量,是过去所有梯度的泄漏平均值(越近的梯度权重越大);

  • :动量系数,控制惯性大小, 越大,惯性越强,能记住的过去梯度越多;

  • :当前步的梯度;

  • :学习率,控制步长大小。

2. 公式解读

把动量公式展开可以看到,动量是过去梯度的加权和:

  • 时, ,相当于记住最近 10 步的梯度;

  • 时,动量法退化为普通梯度下降。

3. 惯性的效果

以 “狭窄峡谷” 地形为例:

  • 方向(平缓坡):每次梯度方向一致,动量 会不断积累,20 轮就能冲到山脚;

  • 方向(陡峭坡):梯度方向来回震荡,动量 会抵消反向梯度,最终平稳下降。

三、关键参数:怎么调才不 “冲过头”?

1. 动量系数

  • 常用值: (默认最优选择),兼顾惯性和灵活性;

  • (如 ):惯性不足,解决震荡的效果差,收敛慢;

  • (如 ):惯性太大,容易 “冲过山脚”(参数超调),需要配合更小的学习率。

2. 学习率

动量法的有效步长 ,比普通梯度下降大,所以 要比梯度下降时略小:

  • 比如普通梯度下降用 ,动量法( )可设

  • 太大,即使有动量,也可能在陡峭方向发散。

3. 参数搭配口诀

选 0.9, 往小了调;峡谷越窄, 越大、 越小”。

四、PyTorch 实战:带惯性的登山流程

1. 从零开始实现

手动实现动量法的参数更新逻辑,适合理解原理:

python
import torch
from torch import nn
from d2l import torch as d2l

# 1. 初始化动量状态(和参数同形状的零向量)
def init_momentum_states(feature_dim):
    v_w = torch.zeros((feature_dim, 1))  # 权重的动量
    v_b = torch.zeros(1)                 # 偏置的动量
    return (v_w, v_b)

# 2. 动量法更新函数
def sgd_momentum(params, states, hyperparams):
    for p, v in zip(params, states):
        with torch.no_grad():
            # 计算动量:过去动量*β + 当前梯度
            v[:] = hyperparams['momentum'] * v + p.grad
            # 用动量更新参数
            p[:] -= hyperparams['lr'] * v
        p.grad.data.zero_()  # 清空梯度

# 3. 训练函数
def train_momentum(lr, momentum, num_epochs=2):
    # 加载数据
    data_iter, feature_dim = d2l.get_data_ch11(batch_size=10)
    # 定义模型
    net = nn.Sequential(nn.Linear(feature_dim, 1))
    nn.init.normal_(net[0].weight, std=0.01)
    # 训练
    d2l.train_ch11(
        sgd_momentum,
        init_momentum_states(feature_dim),
        {'lr': lr, 'momentum': momentum},
        data_iter, feature_dim, num_epochs
    )

# 启动训练(lr=0.005,momentum=0.9,经典搭配)
train_momentum(lr=0.005, momentum=0.9)

2. 框架简洁实现

用 PyTorch 内置的optim.SGD直接调用动量法,更简洁:

python
# 直接使用框架内置的动量SGD
trainer = torch.optim.SGD
d2l.train_concise_ch11(
    trainer,
    {'lr': 0.005, 'momentum': 0.9},  # 配置动量参数
    data_iter
)

五、理论分析:动量法的收敛性

在凸二次问题中,动量法的收敛性可以通过特征值分解分析:

  1. 目标函数可以分解为多个独立的一维优化问题,动量法在每个维度上的收敛是独立的;

  2. 动量法的收敛范围是 是目标函数的特征值),比梯度下降的 更大,说明动量法的参数选择更灵活;

  3. 有效梯度数为 越大,能利用的过去梯度越多,收敛越快。

六、常见误区:避开这 3 个坑

  1. 只调学习率,不调 时有效步长更大,若 和普通梯度下降一样大,会冲过山脚;

  2. 设得太大(如 ):惯性太强,参数更新 “刹不住车”,后期震荡;

  3. 忽略动量的状态存储:动量 需要和参数同形状,初始化必须为 0,不能随意设值。

七、核心总结

  1. 动量法本质:带惯性的梯度下降,用过去梯度的加权平均(动量)替代当前梯度,顺坡加速、震荡减速;

  2. 关键参数: (惯性大小,默认 0.9)、 (步长,配合 减小);

  3. 适用场景:所有深度学习任务,尤其适合目标函数 “凹凸不平”(如 CNN、Transformer)的场景;

  4. 优势:收敛更快,震荡更小,能解决梯度下降在狭窄峡谷里的痛点;

  5. 一句话记忆:登山带惯性,顺坡冲得快,晃坡稳得住,下山更高效~

(注:文档部分内容可能由 AI 生成)

京ICP备2024093538号-1