混合精度训练全指南:FP16/BF16/FP8 的选择与工程
说明:本篇为综述/无第一手实验数据,采用公开实践与硬件规格路线。
实验目标
混合精度不是"开个 AMP 就行"——FP16 的溢出问题、BF16 的精度取舍、FP8 的新时代(训练+推理)、以及它们与损失缩放/稳定性/检查点的相互作用,都是工程决策。本篇目标:拆解混合精度训练的完整框架——AMP 机制与 loss scaling(为什么需要缩放)→ FP16/BF16/FP8 的精度画像与选择矩阵 → 训练中的精度策略(何时降精度、何时不能降)→ 与检查点/稳定性的衔接。读完能回答:我的训练该用哪种精度、AMP 怎么配、FP8 值不值得上。
代码逐段拆解
第一段:AMP 与 loss scaling
python
# PyTorch AMP(Automatic Mixed Precision)标准用法
scaler = torch.cuda.amp.GradScaler() # 梯度缩放器
for x, y in loader:
with torch.autocast(device_type="cuda", dtype=torch.bfloat16):
loss = model(x, y) # 前向:自动混合精度
scaler.scale(loss).backward() # 缩放后再反传
scaler.step(optimizer) # 反缩放后更新
scaler.update() # 动态调整缩放因子要点:
- AMP 只在前向/反向自动选精度:算子级自动选择(矩阵乘/卷积用低精度,归一化/softmax 保持高精度),权重仍以 FP32 主副本保存——"混合精度"的混合指的是这个。
- loss scaling 解决 FP16 的梯度下溢:FP16 最小正数 ~6e-5,小梯度直接归零;把 loss 乘以缩放因子(如 2¹⁶)再反传,梯度放大后不丢失,更新前再除回。BF16 不需要 loss scaling(指数位与 FP32 相同,无下溢问题)——这是 BF16 在训练中的关键优势。
scaler.update()动态调缩放:出现 inf/NaN 时缩放因子减半并跳过该步更新(step内部处理),稳定后逐步恢复——loss scaling 是 FP16 训练稳定的核心机制。
第二段:三种精度的选择
python
# FP16:老牌,需 loss scaling,动态范围小
# BF16:训练主流,无需 loss scaling,尾数少(精度略降)
# FP8:新一代,训练+推理都能用,需要更细的缩放与特殊处理
# 选择矩阵(经验口径):
# 常规 LLM 预训练/微调 → BF16(简单、稳)
# 需要省显存/提速且能接受微降 → FP16 或 FP8(显存减半)
# 小模型/低动态范围任务 → FP16 可行要点:
- 训练主推 BF16:与 FP32 相同的动态范围(无溢出/下溢),无需 loss scaling,尾数 7 位(比 FP16 的 10 位少)导致精度略降但多数训练任务可接受——"简单+稳"让 BF16 成为大模型训练默认。
- FP16 的优势与代价:显存更小(FP32 一半)、部分算子更快,但动态范围小(大值溢出、小值下溢)必须 loss scaling;适合"明确需要小显存/更快"的场景。
- FP8 是前沿:E4M3(权重/激活)与 E5M2(梯度)两种格式配合,显存再减半、吞吐再提升,但需要逐张量缩放(比 loss scaling 更细)与硬件/框架支持成熟度——新项目评估,生产大规模训练暂以 BF16 为稳妥基线。
原理讲解
精度画像对比
| 精度 | 指数位 | 尾数位 | 动态范围 | 训练要点 |
|---|---|---|---|---|
| FP32 | 8 | 23 | 大 | 主副本/基准 |
| FP16 | 5 | 10 | 小 | 需 loss scaling |
| BF16 | 8 | 7 | 大(同 FP32) | 无需缩放,精度略降 |
| FP8(E4M3) | 4 | 3 | 很小 | 需逐张量缩放 |
| FP8(E5M2) | 5 | 2 | 较小 | 梯度用 |
核心认知:精度选择的本质是"动态范围 vs 尾数精度"的权衡——FP16 输在动态范围(溢出/下溢)、BF16 输在尾数(精度略降)、FP8 两者都紧(需细粒度缩放)。训练(梯度传播敏感)与推理(前向即可)对精度的容忍度不同:推理可以更低精度(12 章量化篇),训练保守(BF16 起步)。
与稳定性/检查点的衔接
- 稳定性:BF16 训练出现 loss spike 时,先排查数据/学习率(10 章 spike 篇),不要先怀疑精度——除非复现实验证明换 FP32 改善。
- 检查点:主权重以 BF16/FP32 保存(11 章 mixed-precision-checkpoint 篇的精度处理),优化器状态(Adam 的一阶/二阶矩)需要更高精度——检查点精度与训练精度是两个决策。
实验结果
(估算口径,非实测;典型 LLM 训练)
| 精度 | 显存(相对 FP32) | 训练吞吐(相对) | 稳定性 |
|---|---|---|---|
| FP16 + scaling | ~0.5× | 1.5-2× | 需缩放管理 |
| BF16 | ~0.5× | 1.5-2× | 好(无需缩放) |
| FP8 | ~0.25× | 2-3× | 需细缩放,成熟度低 |
工程启示
- 默认 BF16:大模型训练从 BF16 起步,简单稳定;FP16/FP8 有明确收益(显存/速度)再换。
- FP16 必须配 loss scaling:GradScaler 三件套(scale/step/update)是标准,别只开 autocast 不配缩放。
- 检查点精度独立决策:主权重低精度、优化器状态高精度——别把"训练精度"和"检查点精度"混为一谈。
- FP8 先小规模验证:评估硬件/框架支持与逐张量缩放实现,收益(显存减半)明确且验证通过再上生产。
下一篇预告:单卡精度与效率讲完,看产业级落地形态——"数字孪生与工业仿真:超算、AI 代理模型与实时数据的闭环"。