从0训练LLM · 现代大模型体系 岔路 阅读 + 实验 ≈ 25 分钟 页内实验 ×2
C9 精度与显存:一个参数要几字节 岔路课

4 位只剩 16 个数,怎么训?

4 位只剩 16 个数
FP4(E2M1)只有 ±{0, 0.5, 1, 1.5, 2, 3, 4, 6} 这些码点,整张量一个缩放时大半的数直接变 0。撑住它的是更小的块和各自的缩放:MXFP4 每 32 个数共用一个 2 的幂(4.25 位/参数),NVFP4 每 16 个数一个 E4M3 缩放(4.5 位)。2026 年它主要以 QAT 的形式用在 MoE 专家权重上,全 FP4 预训练仍是前沿。
🔀

这是一堂岔路课,挂在第 4 课后面:8 位靠「一小块一个缩放」撑住了,那 4 位呢?4 位一共只有 16 个位型。

本课一问:4 位只剩 16 个数,怎么训?
这一课先不碰:推理时的各种权重量化算法(C13);MoE 本身怎么路由(C11)。

从已有出发

第 4 课的做法:把张量切成小块,每块按自己的最大值缩放,再舍入到 E4M3。4 位沿用同一个思路,只是元素格式换成 E2M1(1 位符号、2 位指数、1 位尾数)。它会出现在训练一步的哪里?第 4 课的格式标签里,「更新」那一格写着「FP32 主权重 → 在线量化成 FP8」;到了 4 位,这一格变成「FP32 主权重 → 量化成 FP4 → 给前向用」,本课最后讲这是怎么做的。

从已有出发 · 训练一步在显存里留下什么(FP8 细粒度(DeepSeek-V3)) 本课点任一环节看它在 Qwen/Qwen3.8-27B 上占多少

为什么这里换例子:和第 2–4 课一样,这一课讨论的是「一小块数存成 4 位会变成什么」,贯穿例句不进入这一层;下面用的手算块 [0.3, −1.2, 2.7, 0.05] 是 R4 调研的实算用例(教学构造的 4 个数),8 × 256 的张量同样是标注过的教学构造。

精度与显存的演进:每砍一次位宽,都在一个真数字上失败一次
  1. 起点 FP32 全精度 + AdamW 深度学习早期的默认做法
    解决了范围到 ±3.4 × 10³⁸,1 附近的间距 2⁻²³ ≈ 1.2 × 10⁻⁷,数值上几乎不用操心。
    卡在每个参数 4 + 4 + 4 + 4 = 16 字节(权重、梯度、Adam 的 m、v):锚点 27,781,427,952 个参数就是 444.5 GB,是 80 GB 单卡的 5.6 倍,还没算激活。
  2. 第一代 FP16 混合精度:FP32 主权重 + loss scaling Micikevicius et al. 2017
    解决了矩阵乘和激活用 16 位,带宽与激活显存减半;FP32 主权重接住小更新,loss 乘 S 把小梯度推出下溢区,更新前再除回来。
    卡在指数只有 5 位:fp16(10⁻⁸) = 0,fp16(1 + 10⁻⁴) = 1,fp16(70,000) = inf;缩放倍数要一直调,溢出就得跳过这一步。
  3. 第二代 BF16:用尾数换指数 Google Brain 2019 · Kalamkar et al. 2019
    解决了8 位指数,范围与 FP32 相同:不再下溢,不需要 loss scaling。2026 年的默认训练精度。
    卡在1 附近间距粗到 1/128:bf16(257) = 256,bf16(1 + 10⁻³) = 1——主权重和优化器状态仍要 FP32,账本还是 16 字节/参数。
  4. 第三代 FP8 + 细粒度块缩放 Micikevicius et al. 2022(格式)· DeepSeek-V3 2024(超大规模训练)
    解决了激活每 1 × 128、权重每 128 × 128 一个缩放:张量 [1000, 0.01, 0.02, 0.5] 里,0.01 的误差从整张量缩放的 12.8% 降到 0.45%;DeepSeek-V3 相对 BF16 的 loss 相对误差 < 0.25%(官方自报)。
    卡在只有 256 个位型,E4M3 最大 448;块的形状要跟着离群值走——激活梯度改按 128 × 128 块量化,16B MoE 训到约 300B token 发散(附录 B.2);主权重和梯度仍是 FP32。
  5. 岔路 · 2025–2026 4 位:MX / NVFP4 块缩放 + QAT OCP MX 2023 · NVFP4 2025 · Kimi K3 / DeepSeek-V4 2026 你在这里
    解决了MXFP4 每 32 个数共用一个 2 的幂(4.25 位/参数),NVFP4 每 16 个数一个 E4M3 缩放;K3、DeepSeek-V4 在后训练阶段对 MoE 专家权重做 QAT。
    卡在E2M1 只有 16 个码点:块 [0.3, −1.2, 2.7, 0.05] 用 MX 缩放后,0.05 → 0;全 FP4 预训练仍是前沿。
  6. 另一半账 激活:重计算与 FlashAttention Chen et al. 2016 · Korthikanti et al. 2022 · Dao et al. 2022
    解决了不把 s × s 的注意力分数存下来:锚点一条 4,096 token 的序列,激活从 162.5 GiB 降到 42.5 GiB(选择性重计算 / FlashAttention);全量重计算每层只存输入,只剩 2.5 GiB(标准块公式近似)。
    卡在重计算用多算一遍前向换显存;可 444.5 GB 的模型状态一张 80 GB 卡仍然放不下 → C10 并行。
数字口径:舍入结果在构建时按 IEEE 754 / OCP 规则现算(先存 FP32,再就近舍入、平局取偶);显存由 anchor-model.json 的 param_total 现算,1 GB = 10⁹ 字节;激活按 Korthikanti et al. 2022 式 1(标准块近似,s = 4,096、b = 1);DeepSeek-V3 的数字出自其技术报告 §3.3 与附录 B(本地 PDF,官方自报)。

先看 E2M1 一共能表示哪些数。它没有 inf、没有 NaN,16 个位型里正负各 8 个值:

几个数直接存进 FP8 E4M3 与 FP4 E2M1(不缩放,超出最大值饱和)

口径:浏览器现算。FP32 用 DataView 取位;其余格式先存成 FP32,再按 RNE 舍入(与 PyTorch 的 dtype 转换逐值一致,开发时用 torch 2.6 对照过)。E4M3 是 OCP 规范的 FN 变体(无 inf,最大 448);E5M2 有 inf(最大 57,344)。

E2M1 的非负值只有 0、0.5、1、1.5、2、3、4、6 这 8 个:0.25 恰在 0 与 0.5 正中间,平局取偶数,落成 0;2.5 落成 2、5 落成 4(同样是平局取偶);7 超过最大值 6,饱和成 6。同样的数进 E4M3,误差都在几个百分点以内——4 位和 8 位的差距,一眼就看出来。

先自己设计:整张量一个缩放

照搬第 4 课的朴素方案:整张量取最大值,缩放到 6,再舍入。

  1. ① 朴素方案
  2. ② 它在哪失败
  3. ③ 改进方案
朴素方案FP4 E2M1 + 整张量一个缩放
整张量一个缩放:手算块与 8 × 256 张量

张量是教学构造:8 个 token × 256 个通道,固定种子的标准正态数,其中第 17、90 两个通道(同在前 128 个通道里)整体乘离群倍数 k——模拟「少数通道数值特别大」,不是任何模型的真实激活。量化、反量化、误差全部由浏览器实算(元素格式与 FloatLab 同一套编解码,开发时与 torch 的 float8_e4m3fn 逐值对照)。

改进一:MX——每 32 个数共用一个 2 的幂

2023 年 9 月,AMD、Arm、Intel、Meta、Microsoft、NVIDIA、Qualcomm 联合发布了 OCP Microscaling(MX)格式规范 v1.0:每 32 个元素共用一个缩放因子,缩放因子用 E8M0 存——只有 8 位指数、没有尾数,也就是说它只能是 2 的幂(2⁻¹²⁷ 到 2¹²⁷)。元素格式可以是 FP8(MXFP8)、FP6、FP4(MXFP4)等。

MX 的共享缩放(OCP MX v1.0 §6.3;写成公式出自 Rouhani et al. 2023 算法 1)
= 2^( − )
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
上面的块:X = 2^(1 − 2) = 0.5。四个数除以 0.5 得 0.6、−2.4、5.4、0.1,舍入到 E2M1 是 0.5、−2、6、0,乘回 0.5 得 [0.25, −1.0, 3.0, 0]:误差 16.7% / 16.7% / 11.1% / 100%——块里最小的 0.05 被抹平了。规范原文是文字规则,并写明「应当」这样算(允许别的算法)。

缩放只能是 2 的幂,好处是乘除不引入舍入、硬件做起来便宜;代价是块最大值除以 X 之后落在 [4, 8) 之间,不一定正好是 6,超过 6 的部分只能饱和。上面组件的 MXFP4 一行会报出这张张量里有多少元素被这样截断。

改进二:NVFP4——块更小,缩放更细

NVIDIA 的 NVFP4 做了两处改动:每 16 个元素一个缩放,缩放用 E4M3 存(不必是 2 的幂,可以把块最大值精确对到 6 附近),外加每张量一个 FP32 缩放,把 E4M3 缩放本身的范围也照顾到。每个元素实际占的位数:

格式元素块大小块缩放每元素位数
MXFP8E4M3(或 E5M2)32E8M0(8 位)8 + 8 ÷ 32 = 8.25
MXFP4E2M132E8M0(8 位)4 + 8 ÷ 32 = 4.25
NVFP4E2M116E4M3(8 位)+ 每张量 FP324 + 8 ÷ 16 = 4.5

4.25 这个数在 gpt-oss 的模型卡里出现过:它把 MoE 权重(占总参数 90% 以上)量化成 MXFP4,每参数 4.25 位 。换算到锚点:如果把 Qwen3.8-27B 的全部 27,781,427,952 个参数都存成 MXFP4,是 14.8 GB;BF16 是 55.6 GB(纯算术,锚点实际以 BF16 发布)。

NVFP4 也用来做过预训练:NVIDIA 用它训了一个 12B 的 Mamba-Transformer 混合模型,10T token,loss 与下游指标接近 FP8 基线。要做到这一点,他们加了一整套手段:对 Wgrad 的输入做 16 × 16 的随机 Hadamard 变换、权重按 16 × 16 的二维块量化、梯度用随机舍入,还把最前 2 块和最后 8 块留在 BF16(占线性层的 16%);在 8B、1T token 的对照里,MXFP4 要多用 36% 的 token 才追平 NVFP4 。4 位能训,但要一整套补丁——全 FP4 预训练在 2026 年仍是前沿,不是默认做法。

🎯

回到上面的组件试三件事:① 把离群倍数 k 拖到 1(没有离群值):MXFP4、NVFP4 的误差仍在 10% 上下——1 位尾数的下限摆在那里;② 把 k 拖到 1,000:「FP4 整张量」几乎全变 0,块缩放的几行还活着;③ 在「自定义」里把缩放格式从 E8M0 换成 E4M3,再把块从 1 × 32 改成 1 × 16——你就一步步把 MXFP4 改成了 NVFP4,看误差和每元素位数一起怎么变。

2026 年它用在哪:QAT 与发布格式

4 位在 2026 年的主要用法是量化感知训练(QAT):训练时前向就用量化后的权重,让模型在训练中适应量化误差;反向时梯度「直通」量化这一步,落回 FP32 主权重。

QAT 的一步(以 DeepSeek-V4 的做法为例)
, ,
👆 公式里带下划线的每一项都可以点——点哪项,讲哪项。
DeepSeek-V4 的一个细节:FP4 到 FP8 的反量化是无损的——E4M3 比 E2M1 多 2 位指数,只要一个 128 × 128 的 FP8 块里各个 1 × 32 的 FP4 子块的缩放之比不超过某个阈值,细粒度的缩放信息能被 FP8 的范围完全吸收;他们实测当前的权重满足这个条件。

三家的做法(全部为官方自报):

DeepSeek-V4.1-Flash 的 config 把这件事写进了字段:expert_dtype = fp4,weight_block_size = [32, 32],scale_fmt = ue8m0(frontier-models.json)。同一个模型里,不同用途还会选不同的 4 位格式:V4.1 的 indexer 用 OCP 标准的 MXFP4(硬件兼容面最广),主 KV 缓存用去掉了全局缩放的 NVFP4 式格式(精度更高,而 KV 只存储、不进矩阵乘,不需要硬件原生支持)——这就是 C3 第 8、10 课说「把缓存量化到更低精度」的一个真例子(R3 调研 §1.5、§3.10)。

⚠

常见误解一:「FP4 训练已经是主流。」

2026 年 FP4 进入训练,主要是后训练阶段的 QAT,对象是 MoE 专家权重,目的是让发布出去的 4 位权重不掉点;主干的预训练仍以 BF16 / FP8 为主。全 FP4 预训练(NVFP4 的 12B / 10T 实验)要叠一整套补丁,仍是前沿。

常见误解二:「MXFP4 和 NVFP4 只是名字不同。」

块大小(32 对 16)、块缩放的格式(E8M0 只能是 2 的幂,E4M3 可以不是)、有没有每张量的第二级缩放,三处都不同;每元素 4.25 位对 4.5 位。在上面的组件里把自定义方案一步步从 MXFP4 改到 NVFP4,误差的变化就是这三处差别的后果。

常见误解三(旧版课程 M7 的说法):「MXFP4 存储会让离群激活溢出。」

K3 报告里,MXFP4 用于 MoE 专家权重,专家的输入激活是 MXFP8。它提出 SiTU-GLU 的理由写的是:SwiGLU 的两个因子都没有上界,大坐标相乘会产生激活离群值,增加低精度算术里的溢出风险(§2.3.2)——说的是激活在低精度里的范围,不是「MXFP4 存储」 。

证据三问

问本课的回答
① 它解决什么问题?把权重压到约 4 位(发布与推理的显存、带宽再砍一半),同时不让模型掉点
② 数学上为什么可能有效?每元素位数是计数 ;块越小、缩放越细,块内的动态范围越可能落进 E2M1 仅有的 12 倍范围——这是动机,不保证训练结果 ;STE 是近似梯度
③ 实验上呢?K3、DeepSeek-V4、gpt-oss 都在后训练用 MXFP4 处理 MoE 权重;NVFP4 做了 12B / 10T 的预训练

一句话

📌

4 位只有 16 个码点,只能靠「更小的块 + 各自的缩放」撑住;2026 年它主要以 QAT 的形式用在 MoE 专家权重上,全 FP4 预训练仍是前沿。

回到主线

回主线第 5 课:激活为什么比参数还占显存? → 第 5 课

你可能会问