FP8
FP8 是一种 8 位浮点格式,包含 E4M3 和 E5M2 两种变体;与 16 位格式相比,它能将内存占用减半,并在受支持的 GPU 上将矩阵吞吐量翻倍。
FP8 是一种 8 位浮点数格式,可用 16 位格式一半的内存和数据传输量来训练和运行神经网络。和任何浮点类型一样,每个值都有一个符号位、决定取值范围的指数位,以及决定精度的尾数位;但总共只有 8 位,因此它在范围和精度上都做出了较大取舍。NVIDIA、Arm 和 Intel 的工程师在 2022 年 9 月发表的论文 FP8 Formats for Deep Learning中定义了两种标准变体 E4M3 和 E5M2,并验证了使用它们训练最多 1,750 亿参数的语言模型。在配备 FP8 Tensor Core 的 GPU上,例如 2022 年推出的 NVIDIA Hopper H100,FP8 矩阵乘法的吞吐量是 FP16 或 BF16的两倍。
E4M3 和 E5M2#
两种变体以不同方式划分 7 个非符号位:
- E4M3: 4 个指数位和 3 个尾数位。它舍弃无穷大表示,仅保留一种 NaN 模式,使最大值达到 448,适用于前向传播中的权重和激活值。
- E5M2: 5 个指数位和 2 个尾数位,特殊值遵循 IEEE 754 约定。它的最大值可达 57,344,但步长更粗,适用于幅值变化范围更大的梯度。
两种格式都会将较小的值直接置零,并截断较大的值,因此 FP8 张量通常会携带一个缩放因子,将数值调整到可表示的范围内。对类似梯度大小的数值进行带缩放和不带缩放的转换,就能看出原因:
import torch
torch.manual_seed(0)
grads = torch.randn(10_000) * 1e-4 # gradient-sized values, far below 1
e4m3, e5m2 = torch.float8_e4m3fn, torch.float8_e5m2
print(f"E4M3 max {torch.finfo(e4m3).max:g}, E5M2 max {torch.finfo(e5m2).max:g}")
# Per-tensor scaling maps the largest magnitude onto the E4M3 maximum before casting
scale = torch.finfo(e4m3).max / grads.abs().max()
results = {
"E4M3 direct": grads.to(e4m3).float(),
"E5M2 direct": grads.to(e5m2).float(),
"E4M3 scaled": (grads * scale).to(e4m3).float() / scale,
}
for name, restored in results.items():
zeros = (restored == 0).float().mean()
error = ((restored - grads).abs() / grads.abs()).median()
print(f"{name}: {zeros:.0%} rounded to zero, median relative error {error:.1%}")直接转换为 E4M3 会将这些值中的 100% 四舍五入为零;E5M2 的范围更大,能保留大多数值,其中位相对误差为 6.4%,丢失的值占 7%;先进行缩放则能让 E4M3 保留所有值,中位误差为 2.2%。PyTorch还提供 float8_e4m3fnuz 和 float8_e5m2fnuz,这是 AMD MI300 加速器使用的变体;它们会舍弃负零并调整指数偏置,使 E4M3 的上限降至 240。因此,FP8 模型并不能自动在不同厂商的硬件之间移植。
缩放策略#
如果少数离群值决定了最大值,并将其他所有值压向零,那么对整个张量使用一个缩放因子就会失效;这在Transformer激活值中很常见。不同方案在缩放粒度上有所不同:
- 逐张量延迟缩放: NVIDIA 的 Transformer Engine 根据近期训练步骤中观察到的最大值,为每个张量选择缩放因子,因此无需额外遍历数据。
- 块缩放: DeepSeek-V3 按每个包含 1 × 128 个值的块缩放激活值,并按每个 128 × 128 块缩放权重。其团队报告称,这是首次在超大模型(6710 亿参数)上验证 FP8 训练。
- MXFP8: Open Compute Project 的微缩放格式让每 32 个值共用一个 2 的幂次缩放因子,NVIDIA Blackwell GPU 可通过硬件运行该格式。
矩阵乘法会以更高精度累加结果;而对精度敏感或计算成本较低的层,例如归一化、softmax以及优化器的主权重,则继续使用 BF16 或 FP32。因此,FP8 只是混合精度方案的一部分。
FP8 在训练和推理中的应用#
训练时,NVIDIA 的 Transformer Engine和 TorchAO会将线性层替换为 FP8 版本,同时以更高精度保留主权重。推理时,推理服务引擎会以 FP8 存储大型语言模型的模型权重和 KV 缓存,与 16 位格式相比可将内存占用减半,从而容纳更多并发请求。TensorRT也会为配备 FP8 Tensor Core 的 GPU 构建 FP8 引擎。FP8 必须获得硬件支持才能发挥优势:NVIDIA A100 的 Tensor Core 支持 FP16、BF16 和 INT8,但没有 FP8 单元;Ada Lovelace、Hopper 和 Blackwell GPU,以及 AMD MI300 系列则都支持 FP8。
FP8 介于相邻格式之间:
- FP16 或半精度: 位数是 FP8 的两倍,包含 10 个尾数位;对于大多数推理任务,其范围足够,且无需逐张量缩放。
- FP4: 位数再次减半,需要依赖细粒度块缩放来保持精度。
- INT8: 另一种 8 位格式,具有 256 个均匀间隔的级别,而不是像 FP8 那样根据指数间隔排列,因此需要校准缩放因子,但能运行在更多硬件上,包括大多数 CPU 和 NPU。
Ultralytics YOLO26采用 INT8 路线实现 8 位推理:在导出模式下,使用 quantize=8 导出为 TensorRT和 OpenVINO等格式时,会运行训练后模型量化,并使用 data 数据集中的图像校准缩放因子;而使用 quantize=8 进行量化感知训练微调的模型,则会将学到的取值范围导出到 TensorRT,无需校准。










