主包是在边实习边学习大模型,会更一些这方面文章,一边记录方便平时翻看一边加深理解,主包是蒟蒻有不对的地方请大佬指正~

一、优化器解决什么问题?

1. 核心目标

优化器是深度学习训练的「核心引擎」,作用是根据损失函数的梯度更新模型参数,最小化损失(如 LLM 中的交叉熵损失)。找到模型参数θ,使得损失函数L(θ)最小化,核心逻辑是「梯度下降」:

\theta_{t+1}=\theta_t-\eta\cdot\nabla L(\theta_t)

  • η:学习率(Learning Rate),控制参数更新步长;
  • ∇L(θt​):损失函数在θt​处的梯度(参数更新方向)。

LLM 训练本质是最小化经验风险(以自回归交叉熵为例):

\min_{\theta}\mathcal{L}(\theta)=\frac{1}{N}\sum_{i=1}^{N}\sum_{t}\mathrm{CE}\left(\mathrm{softmax}(f_{\theta}(x^{(i)})_{t}),y_{t}^{(i)}\right)

用 mini-batch SGD 得到随机梯度 g_t=\nabla_\theta\mathcal{L}_\mathrm{batch}(\theta_t),优化器给出更新:

\theta_{t+1}=\theta_t-\eta_t\cdot\mathrm{Update}(g_t)

2. 梯度下降的三种基础形式

所有优化器都是「小批量梯度下降(MBGD)」的改进,先明确基础概念:

形式 公式 优点 缺点
批量梯度下降(BGD) \theta=\theta-\eta\cdot\frac{1}{N}\sum_{i=1}^N\nabla L(\theta;x_i,y_i) 梯度稳定,收敛到全局最优 计算成本高(需遍历全量数据),无法处理大模型 / 大数据
随机梯度下降(SGD) \theta=\theta-\eta\cdotp\nabla L(\theta;x_i,y_i)(单样本) 计算快,适合在线学习 梯度震荡严重,收敛慢,易陷入局部最优
小批量梯度下降(MBGD) \theta=\theta-\eta\cdotp\frac{1}{B}\sum_{i=1}^{B}\nabla L(\theta;x_i,y_i) 平衡速度与稳定性 仍存在震荡、学习率难调、局部最优问题

→ 工业界(包括 LLM 训练)几乎都用MBGD,后续优化器均基于此改进。

二、经典优化器拆解(按演进顺序)

变量定义:

1. SGD + 动量(Momentum):解决 SGD 震荡问题

(1)核心原理

模拟物理「动量」:积累之前的梯度方向,减少震荡,加速收敛(比如下坡时惯性冲力)。

(2)公式

v_t=\gamma\cdot v_{t-1}+\eta\cdot\nabla L(\theta_t)

\theta_{t+1}=\theta_t-v_t

  • vt​:动量项(累计梯度),初始为 0;
  • γ:动量系数(主流γ=0.9),控制历史梯度的权重;
  • η:基础学习率。
(3)物理意义
  • 若连续多步梯度方向相同(如下坡),动量项会叠加,步长变大,加速收敛;
  • 若梯度方向频繁变化(如震荡),动量项会抵消部分反向梯度,减少震荡。
(4)优缺点
  • 优点:比纯 SGD 收敛更快,减少震荡,更容易跳出局部最优;
  • 缺点:学习率仍需手动调,动量系数敏感,对稀疏数据不友好。

2. AdaGrad:自适应学习率(针对稀疏数据)

(1)核心原理

对「更新频繁的参数」(如高频词 embedding)用小学习率,「更新少的参数」(如低频词)用大学习率,自动适配稀疏数据。

(2)公式

G_t=G_{t-1}+(\nabla L(\theta_t))^2

\theta_{t+1}=\theta_t-\frac{\eta}{\sqrt{G_t+\epsilon}}\cdot\nabla L(\theta_t)

  • Gt​:累计梯度平方和(对角矩阵,记录每个参数的梯度累计);
  • ϵ:防止分母为 0(如1e−8);
  • η:全局学习率(主流η=0.01)。
(3)优缺点
  • 优点:自适应学习率,适合稀疏数据(如 NLP 的词向量);
  • 缺点:Gt​单调递增,学习率会逐渐衰减到 0,导致训练后期停止更新。

3. RMSProp:改进 AdaGrad 的学习率衰减问题

(1)核心原理

用「指数移动平均」替代 AdaGrad 的累计平方和,让Gt​只保留近期梯度信息,避免学习率无限衰减。

(2)公式

\begin{aligned} & G_{t}=\beta\cdot G_{t-1}+(1-\beta)\cdot(\nabla L(\theta_t))^2 \\ & \theta_{t+1}=\theta_t-\frac{\eta}{\sqrt{G_t+\epsilon}}\cdot\nabla L(\theta_t) \end{aligned}

  • β:移动平均系数(主流β=0.999);
  • 其他参数同 AdaGrad。
(3)核心改进

Gt​不再无限累加,而是「忘记」早期梯度,只关注最近的梯度变化,学习率能稳定在合理范围。

4. Adam:SGD+Momentum+RMSProp(面试核心)

(1)核心原理

结合「动量(梯度一阶矩)」和「RMSProp(梯度二阶矩)」,同时做:

  • 一阶矩:累计梯度的均值(动量);
  • 二阶矩:累计梯度的方差(自适应学习率);
  • 偏置修正:解决初始阶段均值 / 方差估计偏置的问题。
(2)完整公式(口述核心步骤)
  1. 计算一阶矩(动量):m_t=\beta_1\cdot m_{t-1}+(1-\beta_1)\cdot\nabla L(\theta_t)
  2. 计算二阶矩(梯度平方的移动平均):v_{t}=\beta_{2} \cdot v_{t-1}+\left(1-\beta_{2}\right) \cdot\left(\nabla L\left(\theta_{t}\right)\right)^{2}
  3. 偏置修正(消除初始值为 0 的影响):\hat{m}_{t}=\frac{m_{t}}{1-\beta_{1}^{t}}, \quad \hat{v}_{t}=\frac{v_{t}}{1-\beta_{2}^{t}}
  4. 参数更新:\theta_{t+1} = \theta_t - \frac{\eta \cdot \hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}
(3)默认超参数(LLM 中常用)
  • β1​=0.9(一阶矩系数),β2​=0.95/0.999(二阶矩系数);
  • ϵ=1e−8(防止分母为 0);
  • η:基础学习率(LLM 中初始值通常1e−4~3e−4)。
(4)优缺点
  • 优点:收敛快、自适应学习率、稳定性高,适配绝大多数场景(包括 LLM);
  • 缺点:对学习率和β2​敏感,在极大规模数据下可能不如 AdamW 稳定。

5. AdamW:LLM 的主流优化器(高频)

(1)核心改进:解耦权重衰减(Weight Decay)

Adam 的原始实现中,权重衰减和 L2 正则是「耦合」的(直接加到梯度上),而 AdamW 将其「解耦」,让权重衰减独立于梯度更新,效果更稳定。

(2)Adam vs AdamW 的关键差异
维度 Adam AdamW(解耦权重衰减)
权重衰减方式 衰减项融入梯度更新(耦合) 衰减项直接作用于参数(独立)
公式 \theta = \theta - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} - \eta \cdot \lambda \cdot \theta \theta = \left(\theta - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}\right)\cdot (1 - \eta \cdot \lambda)
效果 衰减效果受梯度影响,不稳定 衰减效果稳定,适合大模型训练
LLM 适配性 一般 最优(Llama/GPT/Qwen 均用 AdamW)
(3)公式

\theta_{t+1} = \theta_t - \frac{\eta \cdot \hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} - \eta \cdot \lambda \cdot \theta_t

  • λ:权重衰减系数(LLM 中主流λ=0.01)。
(4)为什么 LLM 首选 AdamW?
  • 解耦权重衰减后,参数正则化更稳定,避免大模型训练中出现「参数爆炸」;
  • 收敛速度和稳定性平衡最优,适配千亿级参数的 LLM 训练;
  • 对学习率调度的兼容性更好(如余弦退火)。

6. 新兴优化器(LLM 新趋势,面试加分)

(1)Lion(EvoLved Sign Momentum)
  • 核心:只用梯度的符号(sign)做动量更新,无需二阶矩,计算量减少 30%;
  • 公式:\theta_{t+1} = \theta_t - \eta \cdot \operatorname{sign}\!\bigl(\beta_1 \cdot m_{t-1} + (1-\beta_1)\cdot \nabla L(\theta_t)\bigr) - \eta \cdot \lambda \cdot \theta_t;
  • 优势:显存占用更低,适合超大模型(如 GPT-4、Llama 3),收敛速度与 AdamW 相当。
(2)Adafactor
  • 核心:低精度计算 + 自适应学习率,减少显存占用;
  • 优势:适配 TPU 训练,适合超大规模 LLM(如 PaLM)。

三、LLM 训练中的优化器实践(面试加分)

1. 主流配置(Llama/Qwen/GPT 通用)

优化器 超参数 配套策略
AdamW β1=0.9,β2=0.95,ε=1e-8 学习率:线性预热 + 余弦退火
权重衰减 λ=0.01 梯度裁剪:max_norm=1.0
基础学习率:1e-4(批量 32/64) 混合精度训练(FP16/BF16)

2. 关键配套策略(面试常问)

(1)学习率调度(Learning Rate Scheduling)

LLM 不用固定学习率,而是「预热 + 退火」:

  • 线性预热:前k步(如 1000 步)学习率从 0 线性升到初始值,避免初始梯度爆炸;
  • 余弦退火:预热后学习率按余弦函数递减,公式:\eta_t = \eta_{\min} + 0.5 \cdot (\eta_{\max} - \eta_{\min}) \cdot \left(1 + \cos\left(\frac{t}{T}\pi\right)\right);
  • 原因:LLM 参数多,固定学习率易过拟合或收敛慢,余弦退火能平稳降低学习率,找到更优解。
(2)梯度裁剪(Gradient Clipping)
  • 作用:防止梯度爆炸(LLM 序列长时,梯度易累积过大);
  • 实现:计算梯度的 L2 范数,若超过阈值(如 1.0),则缩放梯度:

\|\nabla\|_2 = \sqrt{\sum_i \nabla_i^2} ,\text{if }\|\nabla\|_2 > \text{max\_norm},\quad \nabla \leftarrow \nabla \cdot \frac{\text{max\_norm}}{\|\nabla\|_2}.

  • PyTorch 代码:torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0)
(3)混合精度训练
  • 结合 FP16(半精度)和 FP32(单精度):梯度和参数更新用 FP32,前向传播用 FP16;
  • 优势:减少显存占用(LLM 训练需千亿参数,FP16 显存减半),加速训练;
  • 配套:梯度缩放(Gradient Scaling),避免 FP16 梯度下溢。

3. PyTorch 实现示例(LLM 中 AdamW 的典型用法)

import torch
import torch.nn as nn
from torch.optim import AdamW
from torch.optim.lr_scheduler import CosineAnnealingLR, LinearLR

# 假设model是LLM模型(如Llama)
model = nn.Transformer()
# 初始化AdamW优化器
optimizer = AdamW(
    model.parameters(),
    lr=1e-4,          # 基础学习率
    betas=(0.9, 0.95),# 一阶/二阶矩系数
    eps=1e-8,         # 防止分母为0
    weight_decay=0.01 # 权重衰减
)

# 学习率调度:先线性预热1000步,再余弦退火
warmup_scheduler = LinearLR(
    optimizer,
    start_factor=0.01,
    total_iters=1000
)
main_scheduler = CosineAnnealingLR(
    optimizer,
    T_max=100000,     # 总训练步数
    eta_min=1e-5      # 最小学习率
)

# 训练循环
for step in range(100000):
    loss = model(input_ids, labels).loss # 交叉熵损失
    loss.backward()                      # 反向传播计算梯度
    torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm=1.0) # 梯度裁剪
    optimizer.step()                     # 参数更新
    optimizer.zero_grad()                # 清空梯度
    
    # 学习率调度
    if step < 1000:
        warmup_scheduler.step()
    else:
        main_scheduler.step()

四、优化器对比表(记忆)

优化器 核心特点 优点 缺点 适用场景
SGD+Momentum 动量 + 固定学习率 简单、泛化性好 学习率难调、收敛慢 小模型、数据量小
AdaGrad 自适应学习率(累计平方) 适配稀疏数据 学习率衰减到 0 稀疏数据(如词向量)
RMSProp 自适应学习率(移动平均) 学习率稳定 无动量,收敛速度一般 计算机视觉
Adam 动量 + 自适应学习率 收敛快、稳定 权重衰减耦合,大模型不稳定 中等规模模型
AdamW 解耦权重衰减的 Adam 稳定、适配大模型 超参数需调优 LLM(首选)
Lion 符号动量 + 低计算量 显存占用低、速度快 对学习率敏感 超大模型(千亿参数)

五、高频问题与答案

1. 请简述 Adam 和 AdamW 的核心区别?为什么 LLM 用 AdamW?

  • 核心区别:权重衰减的「解耦」;
    • Adam:权重衰减融入梯度更新(耦合),衰减效果受梯度大小影响,不稳定;
    • AdamW:权重衰减独立于梯度更新(解耦),直接对参数做衰减,效果稳定;
  • LLM 选择 AdamW 的原因:
    1. LLM 参数规模大(亿 / 千亿级),耦合的权重衰减易导致参数震荡或过拟合;
    2. 解耦后正则化效果更可控,避免大模型训练中出现「参数爆炸」;
    3. 与学习率调度(余弦退火)兼容性更好,收敛到更优的局部最优。

面试问题:为什么 LLM 训练都用 AdamW 而不是 Adam?

答案: Adam 在处理 L2 正则化(L2 Regularization) 和 权重衰减(Weight Decay) 时存在混淆。

  • 在 SGD 中: L2 正则化和权重衰减在数学上是等价的。
  • 在 Adam 中: 传统的 L2 正则化是将正则项加到梯度 gt 中。由于 Adam 会对梯度进行归一化(除以 vt),这导致正则化项也被归一化了,使得权重衰减的力度变得不可控(参数幅度大时衰减小,幅度小时衰减大)。

AdamW 的做法(Decoupled Weight Decay):
将权重衰减从梯度更新中剥离出来,直接作用在参数上。

AdamW 更新公式:
\theta_t = \theta_{t-1} - \eta \left(\frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} + \lambda \theta_{t-1}\right)

其中 λ 是权重衰减系数。注意\lambda \theta_{t-1}这一项是直接减去的,没有经过\sqrt{\hat{v}_t}的缩放。

2. SGD 和 Adam 的优缺点对比?各自适用场景?

维度 SGD+Momentum Adam
收敛速度
泛化能力 强(易找到更优的局部最优) 弱(易过拟合,需正则化)
超参数调优 难(学习率 / 动量敏感) 易(默认参数适配多数场景)
适用场景 小模型、数据量小、追求泛化 大模型、数据量大、追求收敛速度
  • 补充:LLM 虽用 AdamW,但训练后期可切换到 SGD 微调,提升泛化性(面试加分)。

3. LLM 训练中为什么要做学习率预热和余弦退火?

  • 学习率预热:
    1. 初始阶段模型参数随机初始化,梯度值大,直接用大学习率易导致梯度爆炸;
    2. 前 1000~10000 步线性提升学习率,让模型参数平稳进入合理区间;
  • 余弦退火:
    1. 避免固定学习率导致的后期震荡,平稳降低学习率,让模型收敛到更优解;
    2. 相比阶梯式衰减(StepLR),余弦退火的学习率变化更平滑,适配 LLM 的长训练周期。

4. 梯度裁剪的作用和实现方式?

  • 作用:防止 LLM 训练中因序列过长、参数过多导致的「梯度爆炸」(梯度范数过大,参数更新步长失控);
  • 实现方式:
    1. 计算所有参数梯度的 L2 范数:\|\nabla\|_2 = \sqrt{\sum_i \nabla_i^2}​;
    2. \text{if }\|\nabla\|_2 > \text{max\_norm},\quad \nabla \leftarrow \nabla \cdot \frac{\text{max\_norm}}{\|\nabla\|_2}.
  • 工程代码:PyTorch 的torch.nn.utils.clip_grad_norm_

5. 权重衰减(Weight Decay)和 L2 正则的区别?

  • 本质:权重衰减是 L2 正则的「工程实现」,但 AdamW 中解耦后有差异;
  • L2 正则:损失函数中加\frac{\lambda}{2}\lVert\theta\rVert^2,梯度变为\nabla L + \lambda\theta,间接影响参数;
  • 权重衰减:直接对参数做\theta = \theta \cdot (1 - \eta \lambda),独立于梯度,效果更直接;
  • 面试结论:AdamW 中用「权重衰减」而非 L2 正则,因为解耦后对大模型更稳定。

6. 为什么 LLM 训练不用纯 SGD?

  • 纯 SGD 收敛慢:LLM 训练数据量达万亿 token,SGD 需更多步数才能收敛;
  • 梯度震荡:SGD 无自适应学习率,对不同参数的更新步长相同,易导致震荡;
  • 稀疏数据适配差:LLM 的词表稀疏(低频词少更新),SGD 无法自适应调整学习率;
  • 显存 / 计算成本:SGD 需更大批量才能稳定,而 LLM 受限于显存,小批量 SGD 效果极差。

在训练几十亿参数的模型时,优化器不仅是数学问题,更是资源管理问题。

7.1 显存占用分析(Memory Footprint)

这是面试大模型岗位的必算题。假设模型参数量为 ΦΦ。

组件 数据类型 占用字节 说明
模型参数 FP32 / FP16 4Φ4Φ 或 2Φ2Φ 静态占用
梯度 FP32 / FP16 4Φ4Φ 或 2Φ2Φ 反向传播产生
优化器状态 (Adam) FP32 8Φ8Φ 大头!

为什么优化器状态是 8Φ8Φ?
因为 Adam 需要维护两个状态:

  1. 一阶矩 mtmt​ (FP32, 44 字节)
  2. 二阶矩 vtvt​ (FP32, 44 字节)
    总共:4+4=84+4=8 字节/参数。

示例: 训练一个 7B (70亿) 参数的模型,使用 AdamW 优化器。
仅优化器状态就需要:
7×109×8 Bytes≈56 GB7×109×8 Bytes≈56 GB
这通常超过了单张显卡(如 A100 40GB)的显存。

7.2 节省显存的技术

  1. 混合精度训练 (Mixed Precision):

    • 参数和梯度用 FP16/BF16,但优化器状态通常保持 FP32 以保证精度。
  2. ZeRO (Zero Redundancy Optimizer) - DeepSpeed:

    • ZeRO-1: 对优化器状态(Optimizer States)进行分片,分布到不同的 GPU 上。如果用 8 张卡,单卡显存占用降为原来的 1/81/8。
    • ZeRO-2: 对梯度(Gradients)也分片。
    • ZeRO-3: 对模型参数(Parameters)也分片。
  3. 8-bit Optimizers (Bitsandbytes):

    • 将 mtmt​ 和 vtvt​ 量化为 8-bit 存储。
    • 效果: 显存占用从 8Φ8Φ 降至 2Φ2Φ。
    • 代价: 精度极微小的损失,但几乎不影响大模型效果。

8:Adam 和 SGD+Momentum 本质区别?

  • SGD+Momentum:全局学习率 + 一阶动量,不能按维度自适应。
  • Adam:一阶动量 + 二阶矩估计,按维度归一化,收敛更稳,适合梯度尺度差异大的深网/LLM。

9:为什么 LLM 更常用 AdamW 而不是 Adam?

  • Adam 中把 L2 正则并入梯度会被 vv​ 归一化,导致“非均匀衰减”;
  • AdamW 解耦 weight decay,泛化/稳定性更好,已成事实标准。

9: 解释一下梯度累积(Gradient Accumulation)?

  • 回答:
    • 当显存不足以支撑大的 Batch Size 时,我们可以将一个小 Batch 前向反向传播多次,将梯度累加起来,但不更新参数。
    • 累加 NN 次后,用平均梯度更新一次参数,并清零梯度。
    • 数学等价: 相当于扩大了 NN 倍的 Batch Size。
Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐