Chapter 52
FP32
模型的大小由其参数量及其精度决定,精度通常为 float32、float16 或 bfloat16 之一


FP32
Float32 (FP32) 是标准的 IEEE 32 位浮点表示。使用该数据类型,可以表示大范围的浮点数。 在 FP32 中,为“指数”保留了 8 位,为“尾数”保留了 23 位,为符号保留了 1 位。因为是标准数据类型,所以大部分硬件都支持 FP32 运算指令。
FP16
而在 Float16 (FP16) 数据类型中,指数保留 5 位,尾数保留 10 位。 这使得 FP16 数字的数值范围远低于 FP32。因此 FP16 存在上溢 (当用于表示非常大的数时) 和下溢 (当用于表示非常小的数时) 的风险。
例如,当你执行 10k * 10k 时,最终结果应为 100M,FP16 无法表示该数,因为 FP16 能表示的最大数是 64k。 因此你最终会得到 NaN (Not a Number,不是数字),在神经网络的计算中,因为计算是按层和 batch 顺序进行的,因此一旦出现 NaN,之前的所有计算就全毁了。 一般情况下,我们可以通过缩放损失 (loss scaling) 来缓解这个问题,但该方法并非总能奏效。
BF16
于是我们发明了一种新格式 Bfloat16 (BF16) 来规避这些限制。 BF16 为指数保留了 8 位 (与 FP32 相同),为小数保留了 7 位。 这意味着使用 BF16 我们可以保留与 FP32 相同的动态范围。 但是相对于 FP16,我们损失了 3 位精度。因此,在使用 BF16 精度时,大数值绝对没有问题,但是精度会比 FP16 差。
TF32
在 Ampere 架构中,NVIDIA 还引入了 TensorFloat-32(TF32) 精度格式,它使用 19 位表示, 结合了 BF16 的范围和 FP16 的精度。目前,它仅在某些操作的内部使用 [即 TF32 是一个计算数据类型而不是存储数据类型]。
INT8
除此以外,还有 Int8 (INT8) 数据类型,它是一个 8 位的整型数据表示,可以存储 个不同的值 (对于有符号整数,区间为 [-128, 127], 而对于无符号整数,区间为 [0, 255])。
FP4
NF4
在机器学习术语中,FP32 称为全精度 (4 字节),而 BF16 和 FP16 称为半精度 (2 字节)。
虽然理想情况下训练和推理都应该在 FP32 中完成,但 FP32 比 FP16/BF16 慢两倍, 因此实践中常常使用混合精度方法,其中,使用 FP32 权重作为精确的 “主权重 (master weight)”, 而使用 FP16/BF16 权重进行前向和后向传播计算以提高训练速度,最后在梯度更新阶段再使用 FP16/BF16 梯度更新 FP32 主权重。
在训练期间,主权重始终为 FP32。而在实践中,在推理时,半精度权重通常能提供与 FP32 相似的精度 —— 因为只有在模型梯度更新时才需要精确的 FP32 权重。 这意味着在推理时我们可以使用半精度权重,这样我们仅需一半 GPU 显存就能获得相同的结果。
