2、深度学习训练基础:模型训练流程、计算图、反向传播、优化器、学习率调度、混合精度训练
在进入 DeepSpeed 的各类优化技术之前,必须先建立对深度学习训练“标准流程”的清晰认知。DeepSpeed 并不是替代训练框架的魔法,而是在这套标准流程的关键环节上做并行化、显存优化和通信压缩。理解每一步在做什么、消耗什么资源,才能判断 DeepSpeed 的优化点究竟落在哪里。
一、模型训练的标准流程
一次完整的训练迭代(iteration)通常包含以下步骤:
- 前向传播(Forward):将一批数据输入模型,逐层计算,得到预测输出。
- 损失计算(Loss):用损失函数比较预测值与真实标签,得到一个标量损失。
- 反向传播(Backward):从损失出发,沿计算图反向求每个参数的梯度。
- 优化器更新(Optimizer Step):根据梯度更新参数,如 SGD、Adam、AdamW。
- 梯度清零(Zero Grad):清空上一轮梯度,准备下一轮。
这五步循环往复,直到损失收敛或达到预设的训练步数。看似简单,但每一步都涉及大量张量运算和显存占用,尤其是反向传播和优化器状态。
前向:
y = f(x; θ)损失:
L = loss(y, y_true)反向:
g = ∂L/∂θ更新:
θ = θ - lr · update(g)
二、计算图与反向传播
计算图(Computational Graph)是理解反向传播的关键。它把前向计算中的每个操作记录为节点,张量作为边,形成一个有向无环图。PyTorch 采用动态图机制,每次前向都会重新构建计算图,这为调试和灵活控制提供了便利,但也带来额外的构建开销。
反向传播本质上是链式法则在计算图上的应用:从损失节点出发,沿图反向传播梯度,每个节点根据局部导数计算上游梯度。对于包含数亿参数的模型,反向传播的计算量约为前向的两倍,显存占用也显著增加,因为需要保存中间激活值用于梯度计算。
三、优化器与学习率调度
优化器决定如何利用梯度更新参数。常见优化器包括:
- SGD:最基础,仅按梯度方向更新,收敛稳定但速度慢。
- Momentum:引入动量项,加速收敛并抑制震荡。
- Adam / AdamW:自适应学习率,为每个参数维护一阶和二阶矩估计,适合稀疏梯度和大规模模型。
Adam 类优化器需要为每个参数保存动量(m)和方差(v),因此优化器状态显存约为参数量的 2 倍。对于 10 亿参数的模型,仅优化器状态就可能占用数 GB 显存,这正是 DeepSpeed ZeRO 要解决的核心问题之一。
学习率调度(LR Scheduler)控制训练过程中学习率的变化。常见策略包括:
| 调度策略 | 特点 | 适用场景 |
|---|---|---|
| Step Decay | 每隔固定步数衰减为原来的 γ 倍 | 传统 CNN 训练 |
| Cosine Annealing | 按余弦曲线平滑衰减到最小值 | Transformer 预训练 |
| Warmup + Decay | 先线性升温再衰减,避免早期震荡 | 大模型训练标配 |
| Linear Decay | 线性递减,简单可控 | 微调阶段 |
四、混合精度训练
混合精度训练(Mixed Precision Training)是 DeepSpeed 和现代训练框架的默认配置。其核心思想是:前向和反向使用 FP16/BF16 加速计算并减少显存,而参数更新和优化器状态保留 FP32 以保证数值稳定性。
典型流程如下:
- 维护一份 FP32 主权重(master weights)。
- 每次迭代将主权重转换为 FP16/BF16 副本用于前向和反向。
- 反向得到 FP16 梯度后,转换为 FP32 并做梯度缩放(loss scaling)防止下溢。
- 用 FP32 梯度更新 FP32 主权重。
# 混合精度训练核心逻辑(伪代码)
master_weights = fp32(params)
for x, y in dataloader:
with autocast(dtype=torch.float16):
y_hat = model(x)
loss = criterion(y_hat, y)
scaled_loss = loss * scaler.get_scale()
scaled_loss.backward()
scaler.unscale_(optimizer)
scaler.step(optimizer)
scaler.update()
BF16 相比 FP16 有更大的动态范围,通常不需要 loss scaling,在 A100/H100 等硬件上更受青睐。DeepSpeed 支持 FP16 和 BF16 两种模式,并可与 ZeRO 优化器状态分区结合使用。
五、复盘:训练流程中的资源瓶颈
把上述流程串起来看,显存主要消耗在四块:模型参数、梯度、优化器状态、中间激活值。以 Adam + FP16 混合精度为例,一个 10 亿参数模型的显存占用大致如下:
- FP16 参数副本:约 2 GB
- FP32 主权重:约 4 GB
- FP32 梯度:约 4 GB
- Adam 动量与方差:约 8 GB
- 激活值:随 batch size 和序列长度变化,可能数 GB 到数十 GB
可以看到,优化器状态和梯度占据了大部分显存,而它们并不直接参与前向计算。DeepSpeed 的 ZeRO 技术正是通过分区(partition)这些状态,让每张卡只保存一部分,从而在不改变模型代码的前提下大幅降低单卡显存需求。理解这一点,就理解了 DeepSpeed 优化技术的出发点。