大模型训练从 FP16 转向 BF16 是一个关键的技术演进,其核心原因在于 BF16 在动态范围和精度之间取得了更优的平衡,从而极大地提升了训练(尤其是大模型训练)的稳定性和有效性。

1. 背景

  1. 为什么需要半精度浮点数 (FP16)?

在深度学习训练中,尤其是Transformer架构的大模型,参数量和计算量极其巨大。使用单精度浮点数 (FP32) 进行训练会消耗大量的显存和计算资源。因此,混合精度训练 成为标准做法:

• FP16 存储和计算:在前向传播和反向传播中,使用 FP16 来存储张量和进行计算。这可以显著减少显存占用(约一半),并提升计算速度(现代GPU如NVIDIA Tensor Core对FP16有专门优化)。

• FP32 主权重和梯度累加:在优化器中,保留一份 FP32 格式的“主权重”(Master Weights)。在计算梯度时,也使用 FP32 进行累加,以避免下溢和精度损失。

FP16 的数据格式是:1 个符号位 + 5 个指数位 + 10 个小数位。

  1. FP16 的核心痛点:狭窄的动态范围

FP16 的最大问题在于其动态范围(Dynamic Range)非常窄。

• 可表示的最大值:约 65,504

• 可表示的最小正值(接近0):约 5.96 × 10⁻⁸ (2⁻²⁴)

在训练大模型时,尤其是在训练的初期或者使用某些优化器(如 Adam)时,梯度值可能非常小。当这些微小的梯度值小于 FP16 能表示的最小值时,它们会被舍入为 0。这种现象称为梯度下溢(Gradient Underflow)

一旦梯度变为 0,对应的权重就无法更新,这部分神经元就“死亡”了。对于拥有数十亿甚至万亿参数的大模型来说,广泛的梯度下溢会导致训练不稳定、无法收敛,或者最终模型性能不佳。

简单比喻:FP16 就像一把刻度非常精细但量程很小的尺子(例如 0-10cm),能量得很细,但一旦物体长度超过10cm或小于1mm,你就无法准确测量了。

  1. BF16 的解决方案:牺牲精度,换取范围

BF16 (Brain Floating Point) 是由 Google Brain 团队设计的一种浮点格式,旨在更好地满足深度学习的需求。

它的数据格式是:1 个符号位 + 8 个指数位 + 7 个小数位。

让我们对比一下 FP16 和 BF16:

特性 FP16 BF16 说明
总位数 16 bits 16 bits 两者占用内存完全相同
符号位 1 bit 1 bit 相同
指数位 5 bits 8 bits 这是最关键的差异
小数位/尾数位 10 bits 7 bits 这是做出的牺牲
动态范围 ~5.96e-8 ~ 65504 ~1.18e-38 ~ 3.39e38 BF16 范围极大拓宽
精度(小数部分) 相对较高 (2⁻¹⁰) 相对较低 (2⁻⁷) BF16 精度更低

BF16 的巨大优势:

  1. 极其宽广的动态范围
    BF16 的指数位和 FP32(8位指数)完全一样。这意味着它的动态范围与 FP32 几乎一致。最大值和最小值都与 FP32 处于同一数量级。
    好处:几乎不可能出现梯度下溢或权重下溢的问题。那些在 FP16 中会变成 0 的微小梯度,在 BF16 中依然可以正常表示和参与计算。这直接解决了大模型训练不稳定的核心痛点。

  2. 与 FP32 的无缝转换
    由于指数位宽度相同,BF16 和 FP32 之间的转换非常直接和高效,几乎只是截断或填充尾数位。这在混合精度训练中(BF16计算,FP32主权重)开销更小。

BF16 的“劣势”与为何它无关紧要:

BF16 的尾数位更少(7位 vs 10位),这意味着它的精度更低。它无法像 FP16 那样精确地表示一个数的小数部分。

然而,深度学习模型对数值的精度(小数点后多精确)相对不敏感,但对数值的范围(不能是0或无穷大)极其敏感。

• 权重和梯度值本身具有噪声鲁棒性:模型参数的更新本身就是一个带有噪声的优化过程。梯度值本身就不需要非常高的精度,只要方向大致正确,优化器(如Adam)就能很好地工作。

• 范围比精度更重要:一个不精确但非零的梯度仍然可以有效地更新权重,而一个精确但值为 0 的梯度则对训练毫无贡献。“有”远胜于“无”。

回到比喻:BF16 就像一把量程巨大(0-100米)但刻度相对粗糙的尺子。测量1米左右的物体时,FP16可能更准,但BF16既能测细胞大小(小梯度)又能测大楼高度(大梯度),虽然都不是特别精确,但绝不会测不了。对于训练模型来说,确保所有值都能被测量到,比测量得极度精确更重要。

  1. 硬件支持:Ampere架构及以后的GPU

BF16 的成功推广离不开硬件支持。NVIDIA 从 Ampere 架构(如 A100, A6000, 30系)开始,在其 Tensor Cores 中原生支持了 BF16 计算。

• 新的计算指令:例如,HMMA (Half-precision Matrix Multiply Accumulate) 指令同时支持 FP16 和 BF16 操作。

• 同等性能:在 Ampere 及以后的 GPU 上,使用 BF16 进行矩阵乘法和卷积运算与使用 FP16 具有完全相同的速度性能。

这意味着开发者可以在不损失任何计算速度或内存占用的前提下,获得 FP32 级别的动态范围,从而稳定地训练大模型。这是一种“免费的午餐”,因此BF16迅速成为大模型训练的首选格式。

总结:BF16 的好处

  1. 稳定训练,避免下溢:核心优势。其宽广的动态范围(与FP32一致)彻底解决了FP16在训练大模型时容易出现的梯度下溢问题,使训练过程更加稳定可靠。
  2. 保持性能,无损速度:在现代GPU(Ampere及以后)上,BF16与FP16具有完全相同的计算速度和内存效率。
  3. 简化混合精度训练:与FP32的转换更加简单高效,因为指数位对齐。
  4. 对深度学习任务更友好:牺牲了无关紧要的小数精度,换来了至关重要的动态范围,完美匹配了深度学习的数值特性。

2. 精度对比

BF16、FP16 和 FP32 是深度学习中最常用的三种浮点数格式。

核心概念:浮点数的构成

所有浮点数都由三部分组成:

  1. 符号位 (Sign bit):决定正负。
  2. 指数位 (Exponent bits):决定数值的范围(能表示多大和多小的数)。
  3. 尾数位/小数位 (Mantissa bits):决定数值的精度(表示的细节有多精细)。
格式 总位数 符号位 指数位 尾数位 主要特点
FP32 32 bits 1 bit 8 bits 23 bits 高精度、高范围,传统标准
FP16 16 bits 1 bit 5 bits 10 bits 省内存、速度快,但范围窄
BF16 16 bits 1 bit 8 bits 7 bits 范围广(同FP32),精度低

详细对比

特性维度 FP32 (Single Precision) FP16 (Half Precision) BF16 (Brain Float16) 说明与影响
内存占用 4 Bytes 2 Bytes 2 Bytes FP16/BF16 内存减半,能训练更大模型或使用更大批次。
计算速度 标准速度 更快 (Tensor Cores) 更快 (Tensor Cores) 现代GPU(如NVIDIA V100/A100)对 FP16/BF16 有专用硬件加速。
动态范围 ~1.18e-38 to ~3.40e38 ~5.96e-8 to 65504 ~1.18e-38 to ~3.39e38 核心差异。BF16 范围与 FP32 相同,远大于 FP16。FP16 极易出现下溢
表示精度 非常高 (2⁻²³) 较高 (2⁻¹⁰) 较低 (2⁻⁷) BF16 精度最低,但对深度学习影响不大。FP32 精度最高。
训练稳定性 非常稳定 不稳定 稳定 FP16 的狭窄范围导致梯度容易变成0(下溢),使训练崩溃。BF16 因其宽广范围而非常稳定。
主要用途 传统科研计算、CPU计算、部分网络层 模型推理、对精度敏感的小模型训练 大规模模型训练 (尤其是LLM) 训练用 BF16,推理用 FP16,传统用 FP32 已成为一种趋势。
硬件支持 所有CPU/GPU Pascal架构及以后的NVIDIA GPU Ampere架构及以后的NVIDIA GPU (如A100, 3090, H100) BF16 需要较新的硬件支持。

通俗比喻

你可以把这三种格式想象成三种不同的尺子:

• FP32:高精度工程尺

◦   量程极大(从显微镜到天文望远镜),刻度极其精细(精确到微米)。

◦   优点:什么都能量,量得很准。

◦   缺点:做得太重太大(占内存),操作起来有点慢。

• FP16:便携小尺子

◦   量程很小(只有0-15厘米),但刻度很精细(精确到毫米)。

◦   优点:轻便小巧(省内存),操作快。

◦   缺点:量不了太小的东西(如细胞,会下溢)和太大的东西(如桌子,会上溢),很容易就量不准了。

• BF16:大量程估算尺

◦   量程和工程尺一样大(从显微镜到天文望远镜),但刻度很粗糙(精确到厘米)。

◦   优点:轻便小巧(省内存),操作快,最重要的是什么都能量到(绝不会量不了)。

◦   缺点:量得没那么精细,但对于“估算房间面积”这种任务来说,厘米级的精度足够了。

在深度学习中,我们更关心梯度、权重这些值是否存在(范围),而不是它到底有多精确(精度)。一个不精确但非零的梯度远胜于一个精确但为零的梯度。这就是BF16成功的关键。

3. 总结与选择建议

  1. 训练大型模型(尤其是LLM):
    首选 BF16,它在保持FP16的速度和内存优势的同时,提供了FP32级的动态范围,保证了训练的稳定性。这是当前工业界训练大模型的事实标准。

  2. 模型推理与部署:
    首选 FP16,推理时没有梯度计算,数值范围相对稳定,不会出现下溢问题。更高的精度有时能带来更好的输出质量,且兼容性更广(支持FP16的硬件更多)。

  3. 通用计算、小型模型或兼容性考虑:
    使用 FP32,当硬件不支持BF16/FP16,或模型非常小、对数值精度极其敏感时,FP32仍然是最安全可靠的选择。

  4. 混合精度训练:
    无论是 FP16 还是 BF16,通常都会与 FP32 结合使用,即混合精度训练。计算用 BF16/FP16,但主权重副本和梯度累加等关键操作保留在 FP32 中,以进一步提升数值稳定性。

对于现代大规模深度学习模型(尤其是LLM),BF16 已经全面取代 FP16,成为混合精度训练中首选的半精度浮点数格式。FP16 通常只在推理部署或一些对精度有特殊要求的旧模型中继续使用。

Logo

更多推荐