大语言模型中的低精度数据格式
如果只用一句话概括过去三年大模型训练与推理的硬件趋势 — 训练在从 BF16 走向 FP8,推理在从 FP8 走向 FP4。每一次精度下移一档,同样的硅片面积就能多塞一倍的 MAC 单元,LLM 训练吞吐与推理 token/s 直接翻倍。这条主线背后是一整张数据格式的谱系:FP32 / TF32 / FP16 / BF16 / FP8(两个变体) / FP6(两个变体) / FP4(MX 与 NV 两个版本) / INT8 / INT4。
但「精度下移」从来不是「整个模型换一种格式」这么简单。同一个 Transformer block 里,矩阵乘法可能跑 FP8、Softmax 在 FP32 下做、KV cache 又压到 INT8 — 精度是按运算类型混用的,不是按层混用。要看清这件事,得把每种格式的位结构、动态范围、硬件支持、和在 Transformer 里的实际位置全部铺开。
这篇文章的目的就是把这张谱系图一次性铺开,只覆盖有硬件原生 Tensor Core / 矩阵引擎支持的格式 — 纯软件模拟、研究阶段、或者只在论文里出现的格式(INT2、二值化、posit 等)略过不谈。
引子 — 低精度不只是省显存
很多人对低精度的第一反应是「省显存」。这只对了一半 — 真正决定为什么 NVIDIA / AMD / Google 都在卷低精度的,是另一个事实:每一代 Tensor Core 在更低精度下的吞吐量大致翻倍。
| 架构 | 旗舰卡 | 同 SM 算力(主精度) | 同 SM 算力(最低精度) |
|---|---|---|---|
| Ampere (2020) | A100 | 312 TF (FP16) | 624 TOPS (INT8) |
| Hopper (2022) | H100 | 990 TF (FP16) | 1979 TF (FP8) |
| Blackwell (2024) | B200 | 2250 TF (FP16) | 9000 TF (FP4) |
| Rubin (2026) | R100 | ~8000 TF (FP16) | 50,000 TF (FP4) |
把这张表放在一起看 — 位宽每减半,同代硅片上 MAC 单元数量翻倍,算力直接翻倍。所以低精度不只是「同样模型显存占用更小」,更是「同样硅片可以跑更大的模型」。这是 NVIDIA / AMD / Intel 这三年集体扑向 FP8 / FP4 的根本动力。
省显存当然也重要 — BF16 的模型权重比 FP32 小一半,INT4 量化的权重比 FP16 小四倍。但如果只有显存红利,没有算力红利,这条路根本走不远。
浮点数的通用表示 — 一个公式套所有格式
任何一个 IEEE 754 风格的浮点数都由三部分组成:
- S(sign,符号位) — 1 位,决定正负
- E(exponent,指数位) — 共 位,存的是「偏移后」的指数;真实指数 = ,其中
- M(mantissa / fraction,尾数位) — 共 位,前面隐含一个「1.」(normal 数情况下)
所以一个浮点格式的关键参数就是「总位数 + + 」。决定动态范围的是 ,决定精度的是 。下文所有格式都按这个模板套。
整数格式则是另一种 — 完全没有指数位,只有有符号 / 无符号的整数表示。它的范围线性、精度均匀,但表达范围受位宽硬性限制,实际使用时永远要搭一个外部的 scale factor 把整数「拉伸」或「收缩」到目标数值区间。这一点放到后面整数那一节细说。
浮点格式逐一拆解 — FP32 → FP4 同尺度对比
先一张图把九种浮点格式按同尺度铺开 — 每一格就是一个比特位。指数位宽决定动态范围、尾数位宽决定精度,这两个数轴的取舍是所有格式设计的核心:
FP32 / TF32 — 基准与一个工程巧思 — 同 8 位指数 · 不同尾数
FP32(1 + 8 + 23 = 32 位)是所有现代 CPU / GPU 的基准格式。指数 8 位、bias = 127、动态范围约 到 ,精度约 7 位十进制有效数字。
TF32(1 + 8 + 10 = 19 位,存在 32 位寄存器里)是 NVIDIA 在 A100 上引入的一个工程巧思 — 指数位和 FP32 完全一样(8 位),尾数砍到和 FP16 一样(10 位)。它名字里带「32」,但有效宽度只有 19 位。这么做的好处是:动态范围跟 FP32 完全相同 → 训练时不需要 loss scaling;精度只剩 ~3 位十进制 → 算得快很多。A100 / H100 / Blackwell 上 TF32 是 FP32 GEMM 的默认替代,不改一行代码就能加速。
FP16 / BF16 — 训练时代的两个 16 位 — 一个重精度 · 一个重范围
FP16(1 + 5 + 10 = 16 位)是 IEEE 754 半精度,指数 5 位、bias = 15、动态范围约 到 ,精度约 3-4 位十进制。这个动态范围对训练来说非常窄 — 梯度一旦小到 量级就会下溢成零。所以 FP16 训练必须配合 loss scaling(把 loss 放大到不会下溢的量级再反向传播)。
BF16(1 + 8 + 7 = 16 位)是 Google Brain 在 TPU v2 时代提出的格式,设计思想很直接 — 把 FP32 的尾数砍掉 16 位,保留全部 8 位指数。这样:
- 动态范围跟 FP32 几乎相同 → 训练时不再需要 loss scaling,几乎可以「无痛」替换 FP32
- 精度只剩 2-3 位十进制 → 比 FP16 还低
- FP32 ↔ BF16 的转换只是截断 / 补零 → 硬件代价几乎为零
这就是为什么 2020 年之后,大模型训练几乎清一色地选 BF16 而不是 FP16 — 大模型训练对动态范围远比对精度敏感。这条经验是后面 FP8 设计的直接原型。
FP8 — 两个变体的分工 — E4M3 走前向 · E5M2 走反向
FP8 由 NVIDIA / Arm / Intel 在 2022 年联合提出(arxiv 2209.05433),H100 / MI300 / Gaudi 2/3 都原生支持。它同时定义了两个变体:
| 变体 | 位结构 | 动态范围 | 精度 | 用途 |
|---|---|---|---|---|
| E4M3 | 1+4+3 | (最大值)· 最小 normal 数 | 较高 | 前向:权重 / 激活 |
| E5M2 | 1+5+2 | · 最小 normal 数 | 较低 | 反向:梯度 |
为什么要两个变体?因为激活和梯度的动态范围差很多。激活值经过 LayerNorm 之后通常集中在小范围内,适合 E4M3 的「重精度、轻范围」;梯度的数值可能跨好几个数量级,必须用 E5M2 的「重范围、轻精度」兜住。
注意 E4M3 不严格遵循 IEEE 754 — 它没有 inf,把本来表示 inf 的编码挪用来扩展数值范围(最大值是 448 而不是 240)。E5M2 则严格遵循 IEEE 754,有 inf 和 NaN。
FP8 的 scaling:单看 8 位完全不够覆盖训练时的数值范围。所以 FP8 几乎总是搭配一个 FP32 的 per-tensor scaling factor(H100 的 Transformer Engine 自动维护),实际存储的数值是 。后面提到的 DeepSeek-V3 在这一层做了更细粒度的改进。
FP6 与 FP4 — 进入微缩格式时代 — 单看无意义 · 必须按块共享 scale
FP6 和 FP4 是 2023 年 OCP(Open Compute Project)发布的 微缩格式(Microscaling, MX) 规范的一部分,Blackwell 是第一代把它写进 Tensor Core 的硬件。
FP6 有两个变体:E3M2(范围大、精度低)和 E2M3(范围小、精度高),按场景选用。
FP4 在 Tensor Core 上有两个版本,都用 E2M1 的位结构,差别在于 scale 的粒度:
| 版本 | 位结构 | 块大小 | 块 scale | 外层 scale |
|---|---|---|---|---|
| MXFP4(OCP) | E2M1 (4 bit) | 32 元素 | E8M0(8 bit,纯指数) | — |
| NVFP4(NVIDIA) | E2M1 (4 bit) | 16 元素 | FP8 E4M3(8 bit) | FP32 per-tensor |
为什么需要微缩格式?因为 FP4 一共只有 4 位,能表示的不同数值只有 16 个(包括正负零)。如果不分组共享一个 scale,这 16 个值根本覆盖不了实际权重的分布。MX 把「per-tensor scaling」做成「per-block scaling」 — 每 32 个数共享一个 8 位的指数 scale,等于在硬件层面就内置了 fine-grained 量化。
NVFP4 把块大小从 32 缩到 16,把块 scale 从纯指数 E8M0 换成更精细的 FP8(E4M3),再外面套一层 FP32 per-tensor scale — 三层 scale 结构让它在 Blackwell 推理上的精度比 MXFP4 明显更好,代价是 metadata 占用稍微多一点。
整数格式 INT8 / INT4 — 没有指数 · 完全靠 scale 兜底
整数格式可以看成是「全部尾数、零位指数」的特殊浮点 — 精度均匀、但动态范围完全靠外部 scale 决定。INT8 与 INT4 在 LLM 推理上几乎占据了消费级 / 部署侧的全部场景。
实际使用整数格式时,定点 → 浮点的映射公式是:
其中 是 FP16 / FP32 的 scale, 是 zero point(对称量化 ,非对称量化 )。INT8 通常 per-tensor 或 per-channel 一个 scale 就够;INT4 几乎必须 group-wise — 每 32 / 64 / 128 个数共享一个 scale,否则精度损失太大。GPTQ(arxiv 2210.17323)、AWQ(arxiv 2306.00978) 这些权重量化算法,核心都是在「找一组合适的 group-wise scale」。
它们能表示的范围 — 对数轴上的一字排开
把所有浮点格式的动态范围放在同一条对数轴上,差异一眼就能看出来:
几个值得点出来的观察:
- 「重范围」vs「重精度」一眼区分。同位宽下,指数位多的(BF16、FP8-E5M2)适合训练 — 梯度跨数量级时不会溢出;尾数位多的(FP16、FP8-E4M3、FP6-E2M3)适合推理 — 权重数值分布已知,精度更值钱。
- 位宽越往下走,范围越小到几乎是个点。FP4 一共只能覆盖 0.5 ~ 6 这个区间。它能用在 LLM 推理上,全靠外挂的 block-scale 把这条小 bar 「拉伸」或「收缩」到目标数值区间。
- TF32 / BF16 是「FP32 的截断」。把它们和 FP32 叠在一起,bar 的左右端完全重合,只是精度刻度不同。这就是为什么 FP32 ↔ BF16 / TF32 转换硬件代价几乎为零。
Transformer block 内部的精度分配 — 训练 vs 推理
整个模型从来不是「全部用一种精度」 — Transformer 的每个组件按运算特性各自选精度。下面这张图把训练和推理两种模式的精度分配并排画出来:
几个非显然的细节:
- GEMM 几乎是低精度的唯一战场。一个 Transformer block 里,真正参与「位宽下移」的就是那几个矩阵乘 — Q/K/V projection、attention 的两个 batched matmul、output projection、FFN 的两个线性层。其他地方(norm / softmax / residual / activation)虽然也能压精度,但收益相比 GEMM 小得多 — LLM 大部分计算和参数都在那几个 GEMM 上。
- Softmax / Norm / Residual 几乎不动。这三个组件的共同点是「对数值范围 / 累加误差敏感」 — softmax 要算 ,exp 对小数点后的位数极度敏感;norm 要算平方和,容易溢出;residual 是逐层累加的关键路径,误差会被 N 层放大。所以它们在训练侧基本都保持 FP32。
- KV cache 是推理特有的精度优化点。长上下文时,KV cache 占的显存甚至超过权重本身。把它单独压到 FP8 / INT8 是 vLLM、TensorRT-LLM、SGLang 都默认提供的常规操作。
- 训练显存的「14 字节/参数」。BF16 权重 2 字节 + FP32 master 4 字节 + Adam 一阶矩 4 字节 + Adam 二阶矩 4 字节 = 14 字节/参数。这就是为什么训练一个 70B 模型至少需要 ~1 TB 的显存(还没算激活)。
微缩格式 MX — 让 FP4 / FP6 真正能用的关键
前面铺过的对数轴上,FP4 / FP6 的范围短到几乎是个点。它们能在硬件上跑起来,根本不在格式本身,而在它们外挂的 block scaling。
OCP 的 MX 规范定义了一个非常简单的结构 — 每 32 个数共享一个 8 位的指数 scale:
块大小: 32 元素
每元素: FP4 (4 bit) 或 FP6 (6 bit) 或 FP8 (8 bit)
块 scale: E8M0 (8 bit, 纯指数, 无符号无尾数)
E8M0 是个特殊的「纯指数」格式 — 8 位全部用来存指数,没有符号也没有尾数,表示的就是 这个缩放因子。块内 32 个 FP4 数的实际数值 = 。
为什么是 32 元素一组、为什么 scale 用 E8M0?这是工程权衡 — 块越小精度越高但 metadata 占用越大;scale 用纯指数可以让乘法在硬件上变成「移位」,完全免费。Blackwell 的 FP4 Tensor Core 之所以能直接跑这个格式,就是因为硬件层面内置了这套块级 scale 解码电路。
NVIDIA 又在 MXFP4 基础上做了一个更激进的版本 NVFP4 — 块大小缩到 16、块 scale 换成 FP8(E4M3)、外面再套一层 FP32 per-tensor scale。三层 scale 结构让它的有效精度比 MXFP4 明显更好,代价是 metadata 多占一点空间。Blackwell 上 NVFP4 已经被实测能让推理精度接近 FP8,这是 FP4 真正变成「可用格式」的关键证据。
硬件支持矩阵 — V100 → Rubin · TPU · MI300
低精度真正能「飞起来」的根本原因是硬件加速 — 没有 Tensor Core / 矩阵引擎的原生支持,低精度只是节省内存,但算不快。下面这张矩阵把主流加速器按代际列出来,看每种格式从哪一代开始原生支持:
几个值得点出的模式:
- 绿色对角线。把所有实心绿圆点连起来,你会看到一条对角下降的「阶梯」 — FP16(2017)→ BF16(2020)→ FP8(2022)→ FP4(2024),大约每两年下移一格。这条线就是「位宽每两年减半」的硬件节奏。
- FP32 / FP16 / INT8 三个「栈底」。所有厂商都支持。这意味着只要代码用这三种格式,部署到任何加速器都没问题;越往下走越锁定到特定厂商和代际。
- AMD 落后 NVIDIA 大约一代。MI300(2023)的格式覆盖度大致等于 NVIDIA 2022 年的 H100;MI350(2025)才补上 FP6 / FP4。
- TPU 的「克制」。Google 在自家 workload 上验证 BF16 + INT8 已经够用,所以 TPU 没有跟进 FP8 / FP4。这是一个有趣的设计取向 — 当你既是硬件设计方又是模型设计方时,可以选择「软件迁就硬件」而不是「硬件追赶软件」。Gemini 训练栈一直围绕 BF16 就是这个选择的直接结果。
Rubin — 没有新格式 · 把 FP4 拉到 50 PFLOPS
英伟达 2024 年 GTC 上公布的下一代架构 Rubin(2026 年量产)有几个值得记一下的判断:
- 没有引入新格式。Rubin 仍然是 FP64 / FP32 / TF32 / FP16 / BF16 / FP8 / FP6 / FP4 + INT8 / INT4 这套,和 Blackwell 完全一样。NVIDIA 这一代没有再发明新精度,而是把工程重点放在让 FP4 算力翻倍、让 FP4 真正好用上。
- 性能倾斜得很明显。Rubin 的 FP4 / FP8 算力比 GB200 提升约 3.5×,而 FP16 只提升约 1.6×。这清晰反映了 NVIDIA 的预判 — 大部分训练和推理工作负载会从 BF16 / TF32 迁移到 FP8 / FP4。如果你还在用 BF16,Rubin 给你的提速远不如从 Hopper 到 Blackwell 时那么大。
- Adaptive sparsity 取代 2:4 sparsity。之前几代的「结构化稀疏」几乎没人用(因为强制一半元素为零会掉精度)。Rubin 的自适应稀疏引擎在数据流中动态检测零元素并消除它们,同时不会把非零值置零,所以既能保持模型精度、又能提升性能。Rubin 公布的 50 PFLOPS FP4 算力就是靠这个机制 — 稀疏度越高越接近。
- Rubin CPX 是个有趣的设计。专门给「长上下文 prefill」用的伙伴芯片,不用昂贵的 HBM4,改用 128 GB GDDR7。这反映出业界已经认识到 prefill 和 decode 的硬件需求完全不同 — prefill 计算密集要 FP4 算力,decode 内存带宽密集要大显存。
主流大模型的精度选择 — Llama 4 · DeepSeek-V3 · Gemini · Claude
把目前主流大模型的训练 / 推理精度放在一张表里:
几个值得展开的观察:
- FP8 训练的破冰点是 DeepSeek-V3(arxiv 2412.19437)。在它之前,业界一直对「FP8 比 FP16 还少 8 个数据位,怎么可能稳定训出大模型」持怀疑态度。DeepSeek-V3 的关键工程贡献是细粒度量化 — 对激活采用 1×128 的 tile-wise 分组,对权重采用 128×128 的 block-wise 分组,通过更细的 scale 粒度来对抗 outlier。这是 FP8 训练从「实验室可行」变成「6710 亿参数 MoE 稳定训完」的转折点。
- Llama 4 把 FP8 训练做成了主流方案。Meta 在 FP8 上预训练 Llama 4 Behemoth(2 万亿参数级别),达到 ~390 TFLOPS/GPU,集群规模 32K H100。这是 FP8 训练从「DeepSeek 的孤例」变成「大厂方案」的关键节点。
- 为什么 Gemini 一直停在 BF16 — 因为 Google TPU 没有原生 FP8 Tensor Core,所以 Gemini 的训练栈一直围绕 BF16。这跟前面硬件矩阵图里 TPU 那一列的「克制」是一致的。
- 封闭模型的精度是黑箱。OpenAI 和 Anthropic 都不公开训练精度细节。表里 GPT-4 和 Claude 那两行的「BF16(推测)」是基于硬件代际的推断,不是公开信息。GPT-5 是否用了 FP8 同样不确定。
- 推理侧已经「双轨」。服务端部署(vLLM、TensorRT-LLM、SGLang)倾向 FP8,因为既能省显存又能跑得快;本地部署(llama.cpp、Ollama)倾向 INT4 GPTQ / AWQ,因为消费级显卡上 FP4 硬件还很少。
总结 — 训练 BF16→FP8 · 推理 FP8→FP4
如果用一句话概括目前 LLM 数据格式的趋势:训练在 BF16 → FP8 的路上,推理在 FP8 → FP4 的路上,而每一步落地都依赖一代新硬件的 Tensor Core 支持。
把全文拎成几条:
- 位宽下降不只是省显存,更是换算力。同样硅片,每降一档精度,MAC 单元数量翻倍 — 这是 Tensor Core 算力呈对数式上涨的根本来源。
- 指数 vs 尾数的取舍贯穿所有格式。训练偏好指数多(BF16 / FP8-E5M2),要兜住梯度的动态范围;推理偏好尾数多(FP8-E4M3 / FP6-E2M3),权重数值已知、精度更值钱。
- 位宽越往下走,越离不开 block-scale。FP8 还能 per-tensor scale,FP6 / FP4 必须 block-wise(MX / NVFP4),否则单个数表达能力太弱。整数格式则永远依赖外部 scale。
- 精度是按运算混用的,不是按层。Transformer block 里的每个组件按运算特性各自选精度 — GEMM 是低精度的主战场,softmax / norm / residual 几乎永远保持高精度。
- 三条主线决定了下一代硬件方向。NVIDIA 在卷 FP4 / FP6 算力(Rubin)、AMD 在追赶 FP8 / FP4(MI350)、Google 在「克制」中坚持 BF16 + INT8(TPU)。这三条路决定了未来 3-5 年大模型的训练和部署成本曲线。
下一篇可以继续深挖的几个方向 — DeepSeek-V3 的 FP8 fine-grained scaling 工程细节、Blackwell 上 NVFP4 vs MXFP4 在不同 workload 上的精度对比、TPU 坚持 BF16 路线背后的「软硬协同」哲学。
参考资料 — 标准 · 论文 · 工程博客
标准与白皮书
- OCP Microscaling Formats (MX) Specification v1.0 (2023) — MXFP4 / MXFP6 / MXFP8 / E8M0 block scale 的官方规范。opencompute.org · MX v1.0 spec
- NVIDIA / Arm / Intel FP8 White Paper — 「FP8 Formats for Deep Learning」(2022) — E4M3 / E5M2 两个变体的设计动机与训练实验。arxiv.org/abs/2209.05433
- NVIDIA Blackwell Architecture Whitepaper (2024) — 第二代 Transformer Engine、NVFP4 块结构、FP4 Tensor Core 设计细节。
- NVIDIA Hopper Architecture Whitepaper (2022) — 第一代 Transformer Engine、FP8 Tensor Core、per-tensor scaling 机制。
论文 — 训练侧
- DeepSeek-V3 Technical Report (2024) — 首个超大规模 FP8 训练的工程报告,详细描述 fine-grained tile-wise / block-wise scaling 与 outlier 处理。arxiv.org/abs/2412.19437
- The Llama 3 Herd of Models (Meta, 2024) — BF16 训练 405B 模型的工程实践,16K H100 集群细节。arxiv.org/abs/2407.21783
- Transformer Engine: Mixed-Precision FP8 Training (NVIDIA, 2022+) — H100 上 FP8 训练的 delayed scaling 机制,Megatron-LM / NeMo 默认依赖。github.com/NVIDIA/TransformerEngine
论文 — 推理量化
- LLM.int8(): 8-bit Matrix Multiplication for Transformers at Scale (Dettmers, 2022) — 把 INT8 量化首次稳定用到大模型,发现 outlier 的存在与处理。arxiv.org/abs/2208.07339
- GPTQ: Accurate Post-Training Quantization for Generative Pre-trained Transformers (Frantar et al., 2022) — INT4 权重量化,基于二阶信息的逐层最优 scale 求解。arxiv.org/abs/2210.17323
- AWQ: Activation-aware Weight Quantization (Lin et al., 2023) — 基于激活幅度的 group-wise scale 选择,效果优于 GPTQ。arxiv.org/abs/2306.00978
- SmoothQuant: Accurate and Efficient Post-Training Quantization for LLMs (Xiao et al., 2022) — 通过「smooth」把激活的 outlier 转移到权重上,让 W8A8 量化变得可行。arxiv.org/abs/2211.10438
工程博客与文档
- NVIDIA Developer Blog · Transformer Engine — H100 / B200 上 FP8 / FP4 训练的实战教程。developer.nvidia.com
- vLLM 文档 · Quantization — INT8 / FP8 / INT4 推理量化的开源实现细节。docs.vllm.ai · Quantization
- Tim Dettmers 博客 — LLM 量化最权威的工程视角,bitsandbytes 库的作者。timdettmers.com
- Hugging Face · Quantization Guide — GPTQ / AWQ / BitsAndBytes 在 transformers 库里的统一入口。huggingface.co · quantization