FP8 只用 8 个二进制位表示浮点数,较 FP16 或 BF16 少一半位宽。它能减少矩阵乘法的数据读取和存储,数值范围与精度也随之收紧。真正的 FP8 训练不会把每个计算都变成 8 位。它通常只让矩阵乘法的输入用 FP8,累加结果和其他敏感操作保留更高精度。

我查了 2022 年 FP8 格式论文里的编码表、缩放策略和语言模型实验。它提出两种格式。E4M3 用 4 位指数和 3 位尾数,精度较高,建议用于权重和激活。E5M2 用 5 位指数和 2 位尾数,可表示范围更大,建议用于波动较大的梯度。

两种 FP8 分担不同数值

E4M3 的最大有限值是 448,最小正规数是 2 的负 6 次方。E5M2 的最大有限值是 57344,最小正规数是 2 的负 14 次方。E4M3 为了多一档范围,不表示无穷大,NaN 也只留一种尾数图样,因而把原本用于特殊值的编码分给 256 到 448 的数值。E5M2 保留了 IEEE 754 的无穷大和 NaN 规则。

同一个格式的可表示范围仍可能装不下网络里所有张量。论文建议在转成 FP8 前给高精度张量乘缩放因子,让其最大绝对值靠近 FP8 上限,计算后再除回去。不同张量需要不同缩放因子。溢出时像 FP16 混合精度那样频繁跳过权重更新,在 FP8 更窄的范围下会跳过太多步,论文因此不建议这样处理。

矩阵乘法也不会用 FP8 完成全部累加。论文预设 FP8 输入产生更高精度输出,这与当时 FP16 和 BF16 矩阵指令的用法相同。非线性函数、归一化和优化器更新先把值转成更宽格式。所以所谓 FP8 模型实际是一组精度分工,不是整个训练过程统一用 8 位数。

论文的实验是模拟 FP8。权重和激活先裁剪并量化到 FP8 可表示值,然后转回 FP16 或 BF16 做算术,用来隔离数值格式与特定硬件实现。所以它验证了训练质量,没有直接给出今天某张卡的实际加速比。

质量对照要带上缩放方法

语言模型表里,GPT 1.3B 的基线困惑度为 10.62,FP8 为 10.66;22B 模型分别为 7.21 和 7.24。175B 模型在训练进度 75% 处的数字为 6.65 和 6.68,因为当时 BF16 基线还没有跑完。WMT16 英德翻译中,Transformer Large 的 BLEU 从 28.43 变为 28.35。这些结果在当时的运行波动范围内接近 16 位基线。

缩放不能被省略。BERT Base 在 SQuAD v1.1 上用 16 位推理的 F1 为 88.19,E4M3 量化后为 88.09,int8 为 76.89。GPT 1.3B 用高精度训练后做 E4M3 量化,配合缩放的困惑度为 10.29,直接转 FP8 而不缩放会升到 11.0。当残差连接也存成 FP8 时,单一全局指数偏移无法保住精度,改用逐张量缩放才把困惑度拉回 10.44。

BERT Large 的后训练量化结果又有所不同,16 位基线 F1 为 90.87,int8 为 89.65,E4M3 为 90.94。GPT 6.7B 在 WikiText-103 上的困惑度分别为 8.51、10.29 和 8.41。两组数据不支持一个固定的 FP8 精度损失,它们反而要求为具体模型和张量选择缩放口径。

部署时要写清哪些张量用 E4M3,哪些用 E5M2,累加和优化器状态保留什么精度,缩放因子又是按张量、通道还是更细粒度更新。只在配置里看到 FP8,还不足以判断速度和训练稳定性。

参考资料