Skip to content

Adagrad算法

音译为"阿达格拉德", 全称为 Adaptive Gradient Algorithm

Adagrad 是一种自适应步长的优化算法,专门解决 “稀疏特征”(比如 NLP 里的低频词、推荐系统里的小众物品)的学习率问题 —— 就像登山时给不同的路况定制不同的步长:崎岖的陡坡走小步,平坦的缓坡走大步,让每个参数都能以合适的速度收敛,是稀疏数据优化的 “利器”。

一、核心逻辑:为啥需要 “定制步长”?

1. 普通梯度下降的痛点

在稀疏数据场景(比如训练语言模型),不同参数的更新频率差异极大:

  • 高频特征(比如 “学习” 这个词)的参数经常更新,普通梯度下降的学习率对它们来说可能降得太慢,容易震荡;

  • 低频特征(比如 “预先条件” 这个词)的参数很少更新,普通梯度下降的学习率对它们来说可能降得太快,还没学到足够的信息就停止更新了。

这就像登山时不管是陡坡还是平路都用同样的步长:陡坡走大步容易摔,平路走小步太慢,效率极低。

2. Adagrad 的解决方案

Adagrad 给每个参数单独定制学习率

  • 对于梯度大的参数(相当于崎岖陡坡):过去的梯度平方和大,学习率自动变小,走小步,避免震荡;

  • 对于梯度小的参数(相当于平坦缓坡):过去的梯度平方和小,学习率自动保持较大,走大步,保证足够的更新。

简单说:Adagrad 让 “难走的路慢走,好走的路快走”,每个参数都能找到自己的最优步长。

二、Adagrad 的核心原理

1. 核心公式

Adagrad 通过累加每个参数过去的梯度平方和来调整学习率,公式如下:

其中:

  • :每个参数的梯度平方累加和,相当于这个参数的 “路况复杂度记录”;

  • :全局学习率,控制整体的步长大小;

  • :一个极小的常数(比如 ),防止除以 0;

  • :每个参数的自适应学习率,梯度大的参数 大,学习率小,反之亦然。

2. 公式解读

把自适应学习率展开看,每个参数的步长是全局学习率除以 “过去梯度的均方根”:

  • 对于高频特征(梯度频繁更新, 大):学习率 小,步长小,避免震荡;

  • 对于低频特征(梯度很少更新, 小):学习率 大,步长大,保证足够的更新。

3. 直观效果

以二维函数 为例:

  • 的梯度大(相当于陡坡), 增长快,学习率快速变小,步长越来越小,震荡很快被抑制;

  • 的梯度小(相当于缓坡), 增长慢,学习率保持较大,步长足够大,能快速收敛到最小值。

最终 Adagrad 的收敛轨迹比普通梯度下降更平滑,两个参数都能稳定收敛到最小值。

三、关键参数:怎么调才合适?

1. 全局学习率

  • 常用值: ,Adagrad 的自适应学习率是 ,所以 可以比普通梯度下降大一些;

  • 比如在二维函数的例子里,普通梯度下降用 ,Adagrad 可以用 甚至 ,收敛效果更好。

2. 数值稳定性常数

  • 常用值: ,防止当 时除以 0,一般不用调整。

四、PyTorch 实战:定制步长的登山流程

1. 从零开始实现

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

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

# 1. 初始化Adagrad状态(每个参数对应一个梯度平方累加和,初始为0)
def init_adagrad_states(feature_dim):
    s_w = torch.zeros((feature_dim, 1))  # 权重的梯度平方累加和
    s_b = torch.zeros(1)                 # 偏置的梯度平方累加和
    return (s_w, s_b)

# 2. Adagrad更新函数
def adagrad(params, states, hyperparams):
    eps = 1e-6  # 防止除以0
    for p, s in zip(params, states):
        with torch.no_grad():
            # 累加当前梯度的平方
            s[:] += torch.square(p.grad)
            # 自适应步长更新参数
            p[:] -= hyperparams['lr'] * p.grad / torch.sqrt(s + eps)
        p.grad.data.zero_()  # 清空梯度

# 3. 训练函数
def train_adagrad(lr, 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(
        adagrad,
        init_adagrad_states(feature_dim),
        {'lr': lr},
        data_iter, feature_dim, num_epochs
    )

# 启动训练(lr=0.1,比普通梯度下降大)
train_adagrad(lr=0.1)

2. 框架简洁实现

用 PyTorch 内置的optim.Adagrad直接调用,更简洁:

python
# 直接使用框架内置的Adagrad
trainer = torch.optim.Adagrad
d2l.train_concise_ch11(
    trainer,
    {'lr': 0.1},  # 配置全局学习率
    data_iter
)

五、优缺点:什么时候用 Adagrad?

1. 优点

  • 自适应步长:自动给每个参数定制学习率,不用手动调整;

  • 对稀疏数据友好:特别适合 NLP、推荐系统、计算广告学等有大量稀疏特征的场景,低频特征能得到足够的更新;

  • 收敛更平滑:梯度大的参数步长自动变小,减少震荡,收敛更稳定。

2. 缺点

  • 学习率衰减太快:因为 是累加的,学习率会不断降低,后期可能学习率太小,导致收敛停滞;

  • 不适合非凸问题:深度学习的非凸问题中,Adagrad 的学习率衰减太快,可能无法跳出局部最小值,所以深度学习里一般用它的改进版(比如 RMSProp、Adam)。

3. 适用场景

  • 稀疏数据的优化:比如 NLP 的词嵌入训练、推荐系统的协同过滤、计算广告学的点击率预测;

  • 凸优化问题:Adagrad 在凸问题里有很好的收敛保证。

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

  1. 全局学习率设置太大:虽然 Adagrad 是自适应步长,但全局学习率太大的话,前期的步长会太大,导致震荡;

  2. 在深度学习里滥用 Adagrad:深度学习的非凸问题中,Adagrad 的学习率衰减太快,后期容易停滞,一般用 RMSProp 或 Adam 替代。

七、核心总结

  1. Adagrad 本质:给每个参数定制自适应步长,根据过去的梯度平方和调整学习率,梯度大的步长小,梯度小的步长大;

  2. 关键优势:对稀疏数据特别友好,解决了普通梯度下降对稀疏特征学习率不合适的问题;

  3. 适用场景:稀疏数据的凸优化问题,比如 NLP、推荐系统、计算广告学;

  4. 一句话记忆:登山时看路况调步长,陡坡小步走,平路大步走,每个参数都能高效下山~

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

京ICP备2024093538号-1