直觉理解

想象在浓雾中下山,看不见山脚,只能感觉脚下哪边最陡。梯度下降就是:每一步都朝着最陡的下坡方向走一小步,重复很多次,最终走到谷底附近。「最陡的方向」由梯度给出,「一小步」有多大由学习率决定。

定义与公式

基本形式

参数 沿损失梯度的反方向更新:

其中 是学习率。学习率太大会来回震荡甚至发散,太小则收敛很慢,它通常是最重要的超参数。

批量、随机与小批量

  • 批量梯度下降:每步用全部数据算梯度,准确但太慢。
  • 随机梯度下降(SGD):每步只用一个样本,快但噪声大。
  • 小批量梯度下降:每步用一个批次(如 32、1024 个样本)估计梯度,兼顾效率和稳定性,能充分利用 GPU 的并行能力。现在说「SGD」通常指的就是小批量版本。

梯度中的随机噪声并不全是坏事,它有助于跳出不好的局部区域。

动量

普通 SGD 在狭长的山谷里容易来回震荡。动量法累积历史梯度,像滚下山的小球一样保持惯性:

通常取 0.9。

Adam 与 AdamW

Adam 为每个参数维护两个滑动平均:梯度的一阶矩 (相当于动量)和二阶矩 (梯度平方的平均),用后者给每个参数自适应地缩放步长:

其中 、 是修正了初期偏差后的估计。 按历史梯度尺度归一化更新,但实际步长还取决于一阶矩 ;不能只凭某个参数的梯度大或小判断最终步长。

AdamW 把权重衰减从梯度中解耦出来,直接对参数做衰减,是训练大模型的常见优化器。Adam 通常为每个参数保存 和 两份状态:若状态和参数精度相同,两份状态共占参数存储的两倍;若参数为 BF16、状态为 FP32,则共占四倍。梯度、可能存在的 FP32 主权重和中间激活还需另计,分片或量化优化器又会改变实际占用。

学习率调度

学习率通常不是固定值:训练初期先预热(warmup),从很小的值线性增长,避免一开始就把模型「打坏」;之后按余弦退火等方式逐渐减小,让模型在后期精细收敛。

梯度裁剪

当梯度的范数超过阈值时按比例缩小,防止偶发的超大梯度破坏训练,是训练大模型的标准做法。

代码示例

import torch
 
# 用梯度下降最小化 f(w) = (w - 3)^2,最优解是 w = 3
w = torch.tensor(0.0, requires_grad=True)
opt = torch.optim.SGD([w], lr=0.1)
for step in range(50):
    loss = (w - 3).pow(2)
    opt.zero_grad()      # 清空上一步的梯度
    loss.backward()      # 计算梯度
    opt.step()           # w ← w - lr * grad
print(round(w.item(), 4))   # ≈ 3.0
 
# 换成 AdamW 只需改一行
w2 = torch.tensor(0.0, requires_grad=True)
opt2 = torch.optim.AdamW([w2], lr=0.1, weight_decay=0.0)
for step in range(200):
    loss = (w2 - 3).pow(2)
    opt2.zero_grad(); loss.backward(); opt2.step()
print(round(w2.item(), 2))  # ≈ 3.0

在 AI 中的作用

参考资料

相关