深度解读 📅 2026-10-03 ✍️ MagicNetWorld 编辑部

FP8 训练为什么能稳:把缩放因子的粒度与累加精度算清楚

把 671B 参数的模型用 8 位浮点训完而不炸,靠的不是「换个低精度类型」,而是两件可以被算清楚的事:把缩放因子的粒度切到 1×128 与 128×128,让离群值只污染自己所在的那一块;以及在 Tensor Core 只保留约 14 位有效位的前提下,每 128 个元素把部分和提升到 CUDA Core 做一次 FP32 全精度累加。本文从 E4M3 的位布局出发,推导共享缩放因子的下溢代价、分块的误差局部化收益、以及归约维度与累加区间共同决定误差上界的线性关系,逐条对照 DeepSeek-V3 技术报告的五个设计选择,并给出一份「在自己的训练栈里最小验证 FP8」的清单。

FP8 训练混合精度量化训练系统数学推导

线上做训练的人第一次看 DeepSeek-V3 的技术报告,容易被一个数字绊住:一个 671B 总参数、每 token 激活 37B 的模型,在 14.8T token 上预训练只花掉 2.664M H800 GPU 小时,全过程没有出现不可恢复的 loss spike、也没有回滚。报告把这份成绩归因于架构与工程的共同作用:摘要点明的是 MLA 与 DeepSeekMoE(以及无辅助损失负载均衡、多 token 预测训练目标),而「首次在超大模型上验证 FP8 混合精度训练框架」是它在正文贡献清单里单列的一条。

摘要里那几条(MLA、DeepSeekMoE、负载均衡、多 token 预测)都是架构与训练目标层面的事,本文要讲的是正文贡献清单里单列的这条——FP8 混合精度框架。而它最容易被误读的地方在于:大家习惯性地把「FP8 训练」理解为「换一个数据类型,理论上算力翻倍」。这句话本身没错——报告也确实写了 GEMM 用 FP8「理论上把计算速度相对 BF16 翻一倍」——但它是结果,不是原因。真正需要解释的是另一个问题:

为什么低精度量化明明只有 3 位尾数,却能让一个 671B 模型的训练曲线几乎贴上 BF16 基线(报告给出的相对 loss 误差始终低于 0.25%)?

本文的答案是两句话,都会在下面被展开成可检验的算式:

  1. 浮点格式的相对精度是「免费」的,代价只出在下溢上。所以缩放因子共享的范围越大,被推出正规区的元素就越多——分块量化的全部收益,是把这份代价从整张量压缩到一小块。
  2. 量化之外还有第二重误差:累加。H800 的 Tensor Core 在对齐后只保留每个尾数积的高约 14 位,误差随归约长度 KK 增长;把累加区间截断到 NC=128N_C = 128,是让这个上界重新变小的一步。

为了让结论可用,本文还会做三件配套的事:把一次 FP8 训练里所有精度损失的来源列成一张清单(第七节),给出一个「不拉开一个 helper 分支就能验证 FP8」的最小实验方案(第十二节),以及把这条路线外推到 4 位时新增了哪些工程件(第十三节)。

文中涉及他人结论的部分都以标注出处的方式给出,凡属于本文自行展开的推导与算例,都在文末「本文自行推导」清单里单列,不与报告的数字混写。

一、先给直觉:低精度训练要解决的不是「位数少」,而是「范围挤」

先把悬念放一边,给一个不用公式的画面。

半精度(bf16)训练之所以几乎不费心,是因为 bf16 的 8 位指数已经把「大数到小数」的跨越能力给足了。真正的问题从来不是「一个数只能写 8 位」,而是:一个缩放因子要同时照顾一批数值。

FP8 的指数只有 4 位或 5 位,能覆盖的比值范围远比 bf16 窄。所以工程上必须先给一个张量配一个缩放因子,把它的最大绝对值映射到 FP8 能表示的最大值附近。这一步本身是标准做法(把输入分布对齐到格式的可表示区间),但它带来一个副作用:缩放因子是按「这一组里最大的那个数」定的。

于是,只要这一组里存在离群值,整组的小数值就得跟着这个离群值一起被压缩。压到什么程度会出问题?不是「精度不够」,而是掉出正规区——一旦掉进次正规区,尾数位会一位一位地被侵蚀;掉得更狠,直接变成 0。

这句话就是整篇文章的骨架:

分块量化不改变 FP8 的精度,它改变的是「有多少元素被离群值连坐」。

第二重误差来自计算本身。即使每个数都量化得无可挑剔,KK 维内积的累加过程仍然会丢精度——因为硬件累加器不是全精度的。这一重误差与调度、与缩放因子都无关,只能靠「定期把部分和搬到高精度寄存器」来截断。

二、符号与术语约定

本文出现的符号与格式名统一约定如下,后文不再重复解释。

符号 / 名称含义
xx / x^\hat{x}原始值 / 量化后的值
ss缩放因子(scale),一个分组共用一个
aa一组元素的绝对值最大值(amax)
MAX该浮点格式可表示的最大有限值
pp有效位数(含隐含的前导 1),决定相对精度
KKGEMM 的归约维度(内积长度)
NCN_C累加区间:部分和被提升到高精度寄存器前,Tensor Core 连续累加的每段长度
tt累加器在对齐后实际保留的有效位宽
Emin⁡E_{\min}该格式正规区的最小二进制指数
E4M3 / E5M2 / E8M0 / E5M6格式名,写作 E⟨指数位⟩M⟨尾数位⟩\text{E}\langle\text{指数位}\rangle\text{M}\langle\text{尾数位}\rangle,符号位另计 1 位
Fprop / Dgrad / Wgrad前向、激活反向、权重反向三类 GEMM
WGMMAWarpgroup 级矩阵乘累加指令(Hopper)
正规区 / 次正规区带隐含前导 1 的指数区间 / 指数全 0 且无隐含 1 的区间

三、把 8 位浮点拆开看:指数换范围,尾数换精度

一个 IEEE 风格的二进制浮点数写作:

x=(−1)s⋅(1.m)2⋅2ex = (-1)^{s} \cdot (1.m)_{2} \cdot 2^{e}

其中 (1.m)2(1.m)_2 是有效数字,mm 是尾数位。8 位浮点把「1 位符号 + 剩余 7 位」切成两种互斥的取舍方案,这就是 E4M3 与 E5M2 的全部区别:

格式位布局(符号+指数+尾数)最大有限值正规区最小值有效位数 pp半 ulp 相对误差上界 2−p2^{-p}
E4M31 + 4 + 34482−62^{-6}42−4=6.25%2^{-4} = 6.25\%
E5M21 + 5 + 2573442−142^{-14}32−3=12.5%2^{-3} = 12.5\%
E5M6(自定义)1 + 5 + 6——72−7=0.78%2^{-7} = 0.78\%
bf161 + 8 + 7约 3.39×10383.39\times10^{38}2−1262^{-126}82−8=0.39%2^{-8} = 0.39\%
fp321 + 8 + 23约 3.40×10383.40\times10^{38}2−1262^{-126}242−24≈5.96×10−82^{-24} \approx 5.96\times10^{-8}

这张表里有两个必须看懂的细节。

第一,E4M3 是「牺牲特殊值换范围」的产物。 按 FP8 格式论文的说明,E5M2 遵循 IEEE 754 对特殊值的约定(有正负无穷、NaN 占多个位型),而 E4M3 通过不表示无穷、并且只留一个位型表示 NaN 的方式,把省下来的编码空间让给了数值本身。所以同样是 8 位,E4M3 的尾巴更长、头顶更低;E5M2 的头顶更高(57344 对 448,约 128 倍,即 7 个二进区间、折合约 2.1 个十进制数量级)、但尾巴更短。这不是设计缺陷,而是两种明确的用途分工。

第二,E5M2 覆盖的「比值范围」约是 E4M3 的 2152^{15} 倍。 用正规区上下限的比来衡量:

MAX2Emin⁡={448×26≈2.87×104≈214.8E4M357344×214≈9.40×108≈229.8E5M2\frac{\text{MAX}}{2^{E_{\min}}} = \begin{cases} 448 \times 2^{6} \approx 2.87\times10^{4} \approx 2^{14.8} & \text{E4M3} \\ 57344 \times 2^{14} \approx 9.40\times10^{8} \approx 2^{29.8} & \text{E5M2} \end{cases}

这就是 NVIDIA 的 FP8 使用口径里「前向用 E4M3、反向用 E5M2」的全部理由:反向传播的梯度对精度的容忍度更高、但对动态范围的需求更大。先记住 214.82^{14.8} 这个数,下一节它会直接变成一个判据。

四、形式化:共享缩放因子只在「下溢」时才伤人

设某分组的 amax 为 aa,我们把 FP8 的最大值记作 MAX(E4M3 取 448)。标准做法是令

s=aMAXs = \frac{a}{\text{MAX}}

然后把每个元素量化成 x^=s⋅Q(x/s)\hat{x} = s \cdot Q(x/s),其中 Q(⋅)Q(\cdot) 是「舍入到最近的 FP8 可表示值」。

现在来问一个很关键、但常被跳过的式子:在正规区内,量化后的相对误差有多大?

设 y=x/sy = x/s 落在区间 [2k,2k+1)[2^{k}, 2^{k+1})。在这个二进区间内,相邻可表示值的间隔(ulp)是 2k−p+12^{k-p+1},四舍五入的误差不超过半个 ulp:

∣Q(y)−y∣≤2k−p≤y⋅2−p|Q(y) - y| \le 2^{k-p} \le y \cdot 2^{-p}

把 y=x/sy = x/s 代回去,注意缩放因子在两侧同时出现并抵消:

∣x^−x∣=s ∣Q(x/s)−x/s∣≤s⋅xs⋅2−p=∣x∣⋅2−p|\hat{x} - x| = s\,|Q(x/s) - x/s| \le s \cdot \frac{x}{s} \cdot 2^{-p} = |x| \cdot 2^{-p}

结论看起来很反直觉,但它是浮点格式的核心性质:

只要不越界,浮点量化的相对误差与缩放因子无关,恒为 2−p2^{-p}。

换句话说,一个共享的缩放因子不会让「小数值的相对误差变大」——它只会做两件事:把组内元素推出正规区(下溢),或者让它们撞上够不着的天花板(上溢)。训练里缩放因子通常按 amax 归一,上溢基本不发生,所以唯一真正的杀伤来自下溢。

这个结论还有一层重要的方法含义:讨论「FP8 精度够不够」时,用「有效位数少」当论据是错的论据。位数决定的是那个恒定的 2−p2^{-p};真正随规模、随负载变化的风险因子是「有多少元素被挤出了正规区」。后面所有的工程措施,都是在动这个比例。

4.1 下溢的两道门槛

E4M3 的正规区下限是 2−62^{-6}。在缩放后的坐标系里,一个元素要保持「完整的 3 位尾数」,需要

∣x∣s≥2−6⟺∣x∣≥a⋅2−6MAX=a28672≈3.49×10−5 a\frac{|x|}{s} \ge 2^{-6} \quad\Longleftrightarrow\quad |x| \ge \frac{a \cdot 2^{-6}}{\text{MAX}} = \frac{a}{28672} \approx 3.49\times10^{-5}\,a

次正规区的最小刻度是 2−92^{-9}(把 2−62^{-6} 再按 3 位尾数细分成 8 档后的最小非零档,E4M3 共 7 个非零次正规值)。但要注意:本文的量化用的是四舍五入,所以量级超过半个刻度(2−102^{-10})的元素仍会被舍入到 2−92^{-9} 保留下来——真正归零的门槛是半个刻度:

∣x∣≤a⋅2−10MAX=a458752≈2.18×10−6 a|x| \le \frac{a \cdot 2^{-10}}{\text{MAX}} = \frac{a}{458752} \approx 2.18\times10^{-6}\,a

把两道门槛合并成一个更好用的形式。称一个分组「内部跨度」为组内 amax 与需要保留的最小有效量级之比:

agroup∣x∣≤MAX⋅26=28.81+6=214.81\frac{a_{\text{group}}}{|x|} \le \text{MAX} \cdot 2^{6} = 2^{8.81 + 6} = 2^{14.81}

这就是上一节那个 214.82^{14.8} 的去处。 一个共享缩放因子只能覆盖约 14.8 个二进区间;分组内部的跨度一旦超过这个数,分组里最靠下的一批元素就会被侵蚀。分组越大、越可能同时包含「巨大的离群通道」和「正常量级的小值」,也就越容易越界。

五、推导:分块把误差从「全局」压成「局部」

上一节给出了一个纯判据,这一节把它变成一个可以估影响的模型。

考虑一个隐藏维度为 CC 的激活张量(本文算例统一取 C=4096C = 4096,属示例假设)。理想化地设:绝大多数通道的数值量级约为 σ\sigma;另有 ff 个「离群通道」,量级约为 MM,并记跨度比 R=M/σR = M/\sigma。这是 LLM 激活里真实存在的形态——离群通道的存在是低精度量化文献反复指出的核心困难,报告第 3.3 节也把「激活、权重与梯度中的离群值」列为低精度训练的主要限制。

方案一:整张量共享一个缩放因子。 此时 atensor=Ma_{\text{tensor}} = M,判据要求

Mσ=R≤214.81≈28672\frac{M}{\sigma} = R \le 2^{14.81} \approx 28672

也就是跨度比不能超过约 4.5 个数量级。一旦 RR 更大,所有非离群元素一起掉出正规区(若 R≥218.81≈4.6×105R \ge 2^{18.81} \approx 4.6\times10^{5} 则直接归零)。这就是「一个离群值连坐整张量」的确切含义——不是比喻。

方案二:按 1×128 的 tile 分块共享。 报告对激活采用的就是这个粒度:每个 token、每 128 个通道一组。现在只有包含离群通道的那些块的 amax 被 MM 支配;其余块的 amax 只由本块的 128 个样本决定。对量级 σ\sigma 的样本,128 个样本的期望最大值约为 σ\sigma 的 3 倍(正态情形下 nn 个样本最大值的期望约为 2ln⁡n σ\sqrt{2\ln n}\,\sigma,n=128n=128 时约 3.1),于是这些块的跨度比降到个位数,远在 214.812^{14.81} 之内。

受影响的比例因此可以被估出来。把每个 token 的 CC 个通道切成 C/128C/128 个块,若 ff 个离群通道落在互不相同的块里,被污染的就是这些块:

受影响元素占比≈128fC=128×14096=3.1%\text{受影响元素占比} \approx \frac{128 f}{C} = \frac{128 \times 1}{4096} = 3.1\%

(取 f=1f = 1、C=4096C = 4096 的算例;这个数字随 ff 线性变化,属本文自算。)

对照一下就清楚了:同样的离群值,整张量缩放会伤到 100% 的元素,1×128 分块最多伤到 3.1%。这就是「分块把误差从全局压成局部」的量化版本。报告在权重侧用的是更粗的 128×128 块(128 个输入通道 × 128 个输出通道),理由也在这个框架内:权重矩阵的离群结构通常更平滑,用 128×128 已经足够把跨度比压下来,而更大的块能摊薄缩放因子本身的存储与计算开销。

值得单独记一笔的是为什么激活不能照抄权重的分块方式。报告在正文里明确提到:如果对激活也按权重那样的块方式分组缩放,会引发训练不稳定(细节放在其附录 B.2)。也就是说,激活与权重的分块粒度不同不是随手取值,而是被稳定性实验反向约束出来的——激活沿 token 方向按 128 通道切(1×128)才是能跑通的那一侧。

5.1 算例:走一遍一个 1×128 激活 tile 的量化

抽象推导容易滑过去,这里把数字代进去走一遍,顺便验证第四节那个「相对误差恒为 2−p2^{-p}」的结论。

设一个 1×128 的激活 tile,绝大多数元素量级在 0.02–0.05,其中一个通道是离群值 12.5。

第一步,定缩放因子。 a=12.5a = 12.5,MAX 取 448:

s=12.5448≈0.0279s = \frac{12.5}{448} \approx 0.0279

第二步,查门槛。 保持完整 3 位尾数需要

∣x∣≥a28672=12.528672≈4.36×10−4|x| \ge \frac{a}{28672} = \frac{12.5}{28672} \approx 4.36\times10^{-4}

而本 tile 里除离群值之外最小的元素也有 0.02 量级,是门槛的约 46 倍——整个 tile 的元素都留在正规区。这就是分块想要的结果。

第三步,估误差,并用两种算法互相验算。 对量级 0.03 的元素:

  • 用第四节的相对误差上界:0.03×2−4=1.88×10−30.03 \times 2^{-4} = 1.88\times10^{-3}。
  • 用 ulp 直接算:0.03/0.0279≈1.0750.03/0.0279 \approx 1.075,落在二进区间 [1,2)[1,2)(k=0k=0),ulp 为 2k−p+1=2−3=0.1252^{k-p+1} = 2^{-3} = 0.125(缩放坐标),换算回原坐标是 0.125×0.0279≈3.49×10−30.125 \times 0.0279 \approx 3.49\times10^{-3},半个 ulp 即约 1.74×10−31.74\times10^{-3}。

两种算法给出 1.88e-3 与 1.74e-3,同量级且后者不超过前者——相对误差上界那套推导是对的。

第四步,把缩放因子换成「整张量共享」再走一遍。 假设这张量里还有另一个更大的离群值(比如 1000),于是

s=1000448≈2.232,门槛=100028672≈3.49×10−2s = \frac{1000}{448} \approx 2.232, \qquad \text{门槛} = \frac{1000}{28672} \approx 3.49\times10^{-2}

本 tile 里那些 0.02 量级的元素已低于门槛(0.02 < 0.0349),掉进次正规区:在缩放坐标里它们只能落在 2−92^{-9} 的整数倍上,而 E4M3 的次正规档位总共只有 7 个。粗算一下误差:量级 0.02 的元素在缩放坐标约 0.00896,最近可表示的档位间隔 2−92^{-9},换算回原坐标的半个刻度是 2−9×2.232/2≈2.18×10−32^{-9} \times 2.232 / 2 \approx 2.18\times10^{-3},相对误差约 10.9%(这是半刻度上界;该点按最近舍入实际约 9%)——比正规区里的 6.25% 明显恶化,而且元素越小越糟,继续小下去就归零。

同一个元素、同一个格式、同一组数据,唯一的差别就是缩放因子的粒度:6.25% 对 10.9%。这就是第五节那套「影响半径」论证的微观形态。

六、第二类误差:累加精度,以及为什么是 128

量化只是第一重误差。即使每个数都完美量化,KK 维内积的累加过程还会再丢一次精度。

6.1 硬件的实际行为

报告第 3.5.2 节在给硬件厂商的建议里给出了一个非常具体的描述:在当前 Hopper 架构的 Tensor Core 上,FP8 GEMM 的累加精度受限——对齐 32 个尾数积时,是按住其中最大的指数做右移对齐的,然后只取每个尾数积的高 14 位参与相加,超出这个范围的位被截断。 报告同时给出一个实测(§3.3.2):对两个随机矩阵、K=4096K = 4096 的 GEMM,这种受限累加导致的最大相对误差接近 2%。

这段描述值得停一下:误差不是来自「存不下」,而是来自「对齐」。两个量级相差很远的数相加时,小的那个要右移才能和小数点对齐,右移过程中低位被丢掉——指数差越大,丢掉的有效位越多。误差上界因此与「参与累加的数之间的指数跨度」直接挂钩。

6.2 一个可用的数量级模型

设累加器保留 t=14t = 14 位有效位。第 ii 次加法中,被丢弃的低位量级不超过

δi≤(该步参与运算的最大量级)×2−t\delta_i \le \left(\text{该步参与运算的最大量级}\right) \times 2^{-t}

把 mm 次加法串起来,有两种极端估值:

  • 最坏情况(所有截断误差同号、互相不抵消):m⋅2−tm \cdot 2^{-t},相对最终结果的上界随 mm 线性增长。
  • 独立随机模型(每次截断误差近似独立、按随机游走叠加):m⋅2−t⋅O(1)\sqrt{m} \cdot 2^{-t} \cdot \mathcal{O}(1)。

代入 t=14t = 14、m=K=4096m = K = 4096:最坏情况给出 4096×2−14=0.254096 \times 2^{-14} = 0.25,即 25%;随机游走给出 4096×2−14=0.39%\sqrt{4096} \times 2^{-14} = 0.39\%。报告实测的最大相对误差接近 2%——恰好落在两个界之间,这说明「界是保守的、真实硬件介于最坏与随机之间」这个判断是自洽的。(以上三个数字均为本文按该模型自算,不是报告的推导。)

这段模型还顺带解释了报告提到的另一句话:这个问题「在归约维度 KK 较大时会更加明显」。原因就在模型里——mm 越大,线性项越占上风,而 KK 大正是大模型训练的常态(批量与宽度一涨,KK 就涨)。

6.3 把 KK 截断:NC=128N_C = 128 的来历

既然误差上界与「连续累加的步数 mm」挂钩,最直接的干预就是限制 mm。

报告的做法是「提升到 CUDA Core 求高精度」:Tensor Core 的矩阵乘累加按受限位宽进行,但每累计到一个固定的元素区间 NCN_C 之后,就把这些部分和复制到 CUDA Core 的 FP32 寄存器上做一次全精度累加。根据报告的图 7 与正文,这个最小累加区间为 128 个元素,相当于 4 次 WGMMA;报告给出的判断是:这是「能显著改善精度、又不引入可观开销」的最小累加区间。

把 NC=128N_C = 128 代回模型,上界立刻缩小:

m=128:最坏=128×2−14=0.78%,随机游走=128×2−14≈0.069%m = 128:\quad \text{最坏} = 128 \times 2^{-14} = 0.78\%, \qquad \text{随机游走} = \sqrt{128} \times 2^{-14} \approx 0.069\%

对比 m=4096m = 4096 时的 25%:把累加区间从整段 KK 截到 128,最坏界缩小 32 倍。 这就是「为什么是 128」——它不是魔法数字,它是把 KK 的线性项按固定倍数折掉之后、在精度收益与指令开销之间选出的最小截断点。(0.78% 与 0.069% 为本文按该模型自算。)

报告还交代了这个改动的代价与它为何被隐藏:提升操作会降低单个 warpgroup 的 WGMMA 发射率;但在 H800 上通常有两个 WGMMA 并发存在,一个 warpgroup 做提升、另一个继续发射 MMA,两者重叠,Tensor Core 利用率得以维持。

妙的是,这套机制与上一节的分块缩放是同一个设计的两半:因为缩放因子是沿归约维度 KK 分组给出的(每个 1×128 tile 一个),这些 per-group 缩放因子恰好可以在 CUDA Core 上、伴随高精度累加一起做反量化乘法,代价极小——报告第 3.3.2 节把它写成「与精确的 FP32 累加策略结合,可以高效实现标准 FP8 GEMM 不支持的分组缩放」。

6.4 把模型代回报告的数字:三处一致性自查

模型的价值在于能不能解释现实。这里用报告自己给的两三个数字反向检验它。

自查一:为什么报告报出的 loss 误差(低于 0.25%)比「最坏界 0.78%」还小? 两者并不矛盾,因为在 NC=128N_C = 128 的配置下,随机游走估计是 0.069%、最坏界是 0.78%,而 0.25% 恰好在两者之间;再叠加两层体制性折减——累加误差在多层、多步训练里会被部分平均掉,且 loss 层面的相对误差不等于单个 GEMM 的相对误差。一个既做了分块、又做了提升的系统,落在 0.069%–0.78% 这个带里,是自洽的。

自查二:为什么「KK 越大越糟」? 本文模型里误差上界对连续累加步数 mm 是线性的,而 mm 在无截断时等于 KK——所以「KK 大更糟」是模型的直接推论,不需要额外假设。

自查三:为什么分块能让 E4M3 全线可用? 把第五节的判据拿来量余量:分块之后,块内跨度比约为 3(128 个正态样本的期望最大值与标准差之比;这里用 σ\sigma 作「需要保留的最小量级」的代理——它默认远低于 σ\sigma 的量级不值得保留,真实数据里跨度比约 3 的块仍可能含少量下溢小值),换算成二进区间是 log⁡23≈1.6\log_2 3 \approx 1.6 个;而 E4M3 一个共享缩放因子可用约 14.81 个二进区间(第四节)。1.6 / 14.81 约 11%,余量接近 9 倍。这个余量正是「敢把 E5M2 换成 E4M3」的定量依据:省下的动态范围换来了尾数位,而范围用不完。

三处自查都指向同一个结论:报告的数字与本文的推导彼此不打架;而这也正是判断一篇解读有没有跑偏的实用标准——如果推导不能复现报告里那些「为什么」,模型就该被换掉。

七、误差全景:一次 FP8 训练里有几处精度损失

把前面两节的结论并到一张表里,能看清一件事:「上 FP8」不是一个开关,而是一组互相配套的取舍。下表把报告里出现过的精度相关决策按「误差来源」归类,这也是后文所有判断的基础。

误差来源出现在哪一步治理方式数量级参照
量化舍入(正规区内)每次把张量写成 FP8无:格式固有,只由尾数位决定E4M3 上界 6.25%,E5M2 上界 12.5%
量化下溢(次正规 / 归零)分组的缩放因子由该组 amax 决定缩小分组:激活 1×128、权重 128×128与组内跨度比挂钩(见第四节判据)
累加截断Tensor Core 对齐后只保留高约 14 位每 128 个元素提升到 CUDA Core 做 FP32 累加见第六节数量级模型
存储量化激活缓存、优化器状态选格式:自定义 E5M6、BF16 存 AdamW 矩0.78% / 0.39%(格式固有)
通信量化MoE dispatch / combinedispatch 前量化 FP8(缩放取 2 的整数幂)、combine 保 BF16与 FP8 前向同量级
算子级保留attention、归一化、MoE gating、embedding、output head直接留在 BF16 / FP32数值上为 0,代价是显存与带宽

这张表最有用的地方是把两类误差分开:第一类(舍入、下溢、存储与通信)由「分块 + 选格式」治理,第二类(累加截断)由「提升到高精度」治理,两者不能互相顶替。一个常见的工程误判,是看到 loss 抖动就先去调缩放因子,而真正的瓶颈其实在累加侧;反之亦然。要分清它们,最省事的办法是做一次纯 GEMM 的误差探针(见第十二节)。

八、三张图:数据流、误差局部化、累加截断

第一张图是报告第 3.3.1 节那个混合精度框架的骨架——注意它同时回答了两个问题:哪些算子走 FP8、以及误差在哪一步被两次截断。

flowchart TD
  A["输入激活与主权重(BF16)"] --> B["按 1x128 激活 tile 与 128x128 权重块在线取 amax"]
  B --> C["求缩放因子并量化为 FP8 E4M3"]
  C --> D["FP8 GEMM 三件套:Fprop / Dgrad / Wgrad"]
  D --> E["Tensor Core 分段累加(对齐后约 14 位有效位)"]
  E --> F["每累计 128 个元素提升到 CUDA Core 做 FP32 累加"]
  F --> G["输出 BF16 / FP32 激活"]
  H["保留高精度:embedding / output head / MoE gating / 归一化 / attention"] -.-> D

这张图说明了什么:FP8 只出现在「密度最高的那一段」——线性层的三种 GEMM;而量化与累加各自有一处被有意干预的关口(分块缩放、每 128 元素提升一次),其余算子与主权重整体留在 BF16/FP32。

第二张图把第四节与第五节的推导画成对照,解释「同样的离群值,为什么分块之后伤害变小」。

flowchart TD
  T["整张量共享一个缩放因子"] --> T1["amax 由离群通道决定"]
  T1 --> T2["其余通道被挤进次正规区,尾数位被侵蚀"]
  B["每 128 个元素独立缩放"] --> B1["块内 amax 只由本块决定"]
  B1 --> B2["小值留在正规区,保住 3 位尾数"]

这张图说明了什么:分块量化并没有提高 FP8 本身的精度,它做的是把「离群值的影响半径」从一个张量缩小到 128 个元素。

第三张图是第六节的时间轴:误差上界与「连续累加的步数」挂钩,所以对策就是切断连续累加。

flowchart TD
  A["K 维内积,K 很大"] --> B["Tensor Core 累加器:对齐后只保留约 14 位"]
  B --> C{"已连续累计 128 个元素?"}
  C -->|否| B
  C -->|是| D["把部分和复制到 CUDA Core 的 FP32 寄存器"]
  D --> E["做一次全精度累加,再开始下一段"]
  E --> B

这张图说明了什么:把误差从「随 KK 线性增长」变成「随 128 线性增长、再被 FP32 段间接上」,这正是 NC=128N_C = 128 想买到的东西。

九、DeepSeek-V3 的五条对策,逐条对应上面的机制

把报告第 3.3 节的设计摊开,会发现每一条都能对应到本文前面推出来的某一处误差来源。下面这张对照表是全文的收口。

报告中的设计针对哪一处误差报告给出的关键口径
细粒度量化:激活 1×128 tile、权重 128×128 块共享缩放因子的下溢连坐(第四节)按更小的元素组自适应缩放,「更好地容纳离群值」
提升到 CUDA Core:每 NC=128N_C = 128 个元素做一次 FP32 累加Tensor Core 约 14 位累加的截断误差(第六节)图 7 与正文:128 个元素相当于 4 次 WGMMA,是「能显著改善精度且无实质开销」的最小区间
尾数优先于指数:所有张量统一用 E4M3E5M2 的 2 位尾数精度不足与既有「前向 E4M3、反向 E5M2」的混合方案相对;可行性归因于分块缩放「让分组元素共享指数位、缓解动态范围受限」
在线量化:每个 tile / 块在线取 amax 求缩放因子延迟缩放的尺度滞后相对「用历史 amax 推断当前缩放因子」的延迟方案,改为在线计算,以保证尺度准确并简化框架
低精度存储与通信显存与 all-to-all 带宽,而非数值本身AdamW 一/二阶矩存 BF16;主权重与梯度保 FP32;attention 后的 Linear 输入用自定义 E5M6 且缩放因子取 2 的整数幂;MoE dispatch 前量化到 FP8、combine 保留 BF16

几条容易被忽略、但值得单独点出来的细节:

  • 保留高精度的算子是有清单的,不是「看着办」:embedding、output head、MoE gating、归一化算子、以及 attention 算子全部维持在 BF16/FP32。报告用「对低精度计算敏感」与「代价低、反正不差这一点」两类理由解释这个保留。
  • 主权重与梯度始终是 FP32,只有优化器的一阶、二阶矩被压到 BF16。这个取舍方向很清楚:状态量(矩)对噪声的容忍度高,而真正决定更新方向的量保持高精度。
  • attention 之后的 Linear 输入用了一个自定义的 E5M6 格式,而不是 E4M3。报告给的理由是这些激活同时要被 attention 的反向用到、对精度敏感;它比 E4M3 多 3 位尾数(p=7p=7,相对误差上界 0.78%)。同一处还有一个细节:这些激活在反向会从 1×128 的量化排列转成 128×1,为了避免二次量化引入额外误差,缩放因子被取整为 2 的整数幂。
  • 通信侧也做了量化:MoE up-projection 之前的激活量化到 FP8 再进 dispatch,与 FP8 Fprop 天然衔接;但 forward/backward 的 combine 组件被保留在 BF16。这一条的动机是带宽,而不是算力。
  • 在线量化选得比延迟量化更贵,但更准。延迟缩放要靠前若干轮的 amax 历史去猜当前的缩放因子,省下了每步统计 amax 的开销,代价是尺度滞后;报告选择在线统计,理由写成「保证尺度准确并简化框架」——这是一次明确拿带宽/指令换数值稳定的取舍。

9.1 报告自己给出的验证与成本

上面这些都是机制,机制要能兑现才行。报告给出的验证是:在接近 DeepSeek-V2-Lite 与 DeepSeek-V2 的两个模型规模上、训练约 1T token,FP8 训练模型相对 BF16 基线的相对 loss 误差始终低于 0.25%,报告认为这一水平落在训练随机性可接受的范围内。

成本侧的数字同样值得记:预训练 14.8T token 花掉 2.664M H800 GPU 小时(即每 1T token 约 180K GPU 小时;换算到 2048 卡集群,是每 1T token 约 3.7 天),加上上下文扩展 119K 与后训练 5K,全程合计 2.788M H800 GPU 小时;报告按每 GPU 小时 2 美元的租用价折算为约 557.6 万美元。同时报告强调,训练全程未出现不可恢复的 loss spike、也没有回滚——这一条才是「FP8 训练能稳」的最终证据,前文的推导只是解释它为什么可能。

十、对照表:三代缩放范式的分野

把 NVIDIA 侧公开的口径与 DeepSeek-V3 的选择放在一张表里,能看清这不是一次孤立的技术选择,而是一条可外推的路线。

范式缩放粒度缩放因子存储何时计算典型代表
延迟缩放每张量一个FP32用前若干轮迭代的 amax 历史推断早期 FP8 训练配方(本行口径出自 NVIDIA Transformer Engine 文档)
在线逐张量缩放每张量一个FP32当前轮在线取 amax同上文档列出的 current scaling 配方
分块缩放每 128 个元素(激活)/ 128×128(权重)FP32当前轮在线取 amaxDeepSeek-V3;NVIDIA Transformer Engine 已提供对应配方
微缩放(MXFP8)每 32 个连续元素8 位幂次(E8M0)由硬件格式规定OCP 微缩放格式规范 v1.0
微缩放(NVFP4)每 16 个元素(权重用 16×16 二维块)E4M3,另加一个每张量 FP32 因子由硬件格式规定NVIDIA 后续一代硬件与其 NVFP4 预训练工作

这张表里有两点是本文想强调的:

  1. DeepSeek-V3 的 1×128 / 128×128 与后来的 MX 微缩放格式是同一个思想的两个实现。报告自己也写了这一点:其细粒度量化「与微缩放格式的思路高度一致」,而下一代 GPU 已宣布支持更小量化粒度的微缩放格式。NVIDIA 的 Transformer Engine 文档里那个明确注明「as described in DeepSeek-v3 paper」的分块缩放配方(Float8BlockScaling),是这条判断最直接的落地证据。
  2. 粒度越细,缩放因子的存储与搬运开销越不可忽略。到 NVFP4 这一代,缩放因子本身要占 1 个 E8M0 或 E4M3 值 / 16 或 32 个元素;此外还引入了随机舍入、随机 Hadamard 变换、以及「最后几层用更高精度」的规则。这些新增的工程件说明:精度继续往下压,代价从「精度」转移到了「算法复杂度」。

十一、工程含义:什么时候值得上 FP8

把前面的机制翻译成几条可操作的判断。

第一,先看瓶颈在算力还是在别处。 FP8 的收益主要来自 GEMM 的算力(报告写的「理论上翻倍」)以及权重/激活/通信的字节数减半。如果你的训练瓶颈是 all-to-all 通信或数据加载,FP8 本身不会解决它——报告对 MoE 通信的处理是另一套(DualPipe 与通信核函数),量化只是顺带把带宽又压了一次。

第二,分块缩放不是「免费的开关」。 它依赖「高精度累加 + 沿 KK 维的分组缩放」这套组合实现;报告明确说标准 FP8 GEMM 不直接支持沿内维的分组缩放因子,是配合 FP32 累加策略才高效落地的。在自己的训练栈里复现时,请把「分块」与「高精度累加」当成一个整体来验证,而不是只打开其中一个。

第三,模型规模与超参不变性是有证据的:FP8 格式论文(2209.05433)报告过在不改超参的情况下匹配 16 位训练质量,覆盖 CNN、RNN、Transformer 与最大 175B 参数的语言模型;DeepSeek-V3 报告则是把 FP8 与 BF16 放在同一批基线模型上做对照(附录 B.1),未声明超参细节。⚠️ 「不用改超参」这个结论的出处是格式论文,不是 V3 报告——引用时别混。这两条合起来说明 FP8 已经不是「冒险的前沿尝试」,而是可复现的工程选项。

第四,别把 NCN_C 当成普遍最优。 128 这个值是「最小且显著改善精度」的取值,而它背后的硬件事实是「对齐后保留约 14 位」。换到不同架构、不同累加器位宽,最优 NCN_C 会变;报告的 §3.5.2 也正是基于这一点向硬件厂商提了建议——希望未来 Tensor Core 的 FP8 GEMM 累加精度更高。

第五,收益要按「哪一类误差被消掉」来算,而不是按位数算。 从 bf16 换到 FP8,省下的是带宽与算力;没被省掉的是累加截断与算子保留带来的开销。如果一次改造只换了 GEMM 的数据类型、没动累加路径,你会拿到一半收益、同时拿到一整份累加误差。

11.1 算清收益上限:2× 的 GEMM 换不来 2× 的训练加速

一笔必须提前算清楚的账:FP8 把 GEMM 的理论算力翻倍,但这不等于训练步速翻倍。设一步训练的总时间为 TT,其中 GEMM 占比例 rr,其余(通信、优化器、归一化、attention 等)占 1−r1-r。换 FP8 后,GEMM 部分的时间理论上减半:

T′=T(1−r)+rT2=T(1−r2)T' = T\left(1 - r\right) + \frac{rT}{2} = T\left(1 - \frac{r}{2}\right)

于是加速比有一个与 rr 有关的闭式上界:

speedup=TT′=11−r/2\text{speedup} = \frac{T}{T'} = \frac{1}{1 - r/2}

代两组数字:r=0.6r = 0.6 时约 1.43 倍;r=0.8r = 0.8 时约 1.67 倍。

这个式子的用处是在改造之前就判定值不值:它告诉你收益的天花板完全由「GEMM 占比」决定,而这个占比可以用一次 profile 直接量出来。它同时解释了为什么报告要把 DualPipe 与通信核函数和 FP8 放在同一段里讲——当 GEMM 变快,非 GEMM 部分占比上升、rr 变小,加速比的边际收益随之下降;不解决通信,FP8 省下的那一半时间会被剩下的部分吃掉。

还有一层隐含成本值得记:分块量化本身要额外的统计与反量化运算,提升操作也会占掉一部分 Tensor Core 利用率(见第六节末)。这些开销都被记在「其余」里,所以真实加速比通常略低于上面的上界——把它当成上界用,而不是当成预期值。

十二、怎么在自家训练栈里最小验证 FP8

这一节是给动手派的操作清单。它的目标是用尽量少的算力,把第七节那张表里的两类误差分开,而不是一上来就跑全量对照。

第零步:先量一次「离群有多离群」。 这一步只读数据、不改训练,却决定了后面所有选择。对每个分组算跨度比 Rg=ag/σgR_g = a_g / \sigma_g(组内 amax 与组内标准差的比;用 σ\sigma 当分母是代理,它默认「远低于 σ\sigma 的量级不值得保留」;要更严格,应改用该分组内你真正在意的最小量级作分母),然后看分布:

  • 若绝大多数分组 Rg≲210R_g \lesssim 2^{10},说明离群并不凶猛,逐张量缩放可能就够了,先别急着上分块;
  • 若尾部有一批分组超过 214.812^{14.81}(第四节的判据线),分块是必需的;此时再看这些「超标分组」的占比——如果它和 128f/C128f/C 这种「少数通道」型分布吻合,1×128 分块正对症;如果每个分组都超标,那问题不是「少数离群通道连坐」,而是「分组内部本身就太宽」,此时该考虑的是更细的分组或分布整形(对应第十三节 4 位那一代的随机 Hadamard 变换),而不是简单把 128 调小。

这一步的产出应当是一张分布图,而不是一个结论句——它同时回答「要不要分块」与「分多细」两个问题。

第一步:确认三个前提是否成立。 这三条任一不成立,你的 FP8 收益都会打折,且症状会伪装成「精度问题」。

  1. 你的硬件/软件栈是否支持沿归约维的分组缩放,并且配了高精度累加?不支持时,1×128 与 128×128 这两档要么退化成逐张量,要么需要额外的反量化开销。
  2. 你的框架是否暴露了累加区间这个旋钮(对应 NCN_C)?没有的话,累加侧只能被动接受硬件默认值。
  3. 你的卡上并发 MMA 是否足够,能把提升操作的指令开销藏掉?报告口径是 H800 上两个 warpgroup 并发。

第二步:做一次纯 GEMM 的误差探针,把累加误差单独量出来。 取两个随机矩阵、固定 KK(对齐报告用的 4096),在「有提升」与「无提升」两种配置下各算一次,与 fp64 参考解比最大相对误差。这个实验与模型结构、数据分布都无关,却能把第二类误差直接测出来;如果两种配置差异不明显,说明你的瓶颈在第一类误差上,先去调缩放粒度。

第三步:用「分组内的下溢比例」诊断第一类误差。 这是一个可以直接算的量:对每个分组统计

Psub≈1n∑i=1n1 ⁣[∣xi∣s<2−6]P_{\text{sub}} \approx \frac{1}{n}\sum_{i=1}^{n} \mathbb{1}\!\left[\frac{|x_i|}{s} < 2^{-6}\right]

即落在正规区下限之下的元素占比。三个使用要点:(a)必须按分组统计,不要对整张量取平均——受损的是少数块,平均会把信号稀释掉;(b) 这个量随训练步数变化,值得按步记录而不是只看第一步;(c) 它一旦持续显著大于 0,先把分组切细,再谈别的。

第四步:对照实验要「同超参、同数据顺序、同 token 预算」,只切精度。 报告附录 B.1 是在同一批基线模型上做的 BF16/FP8 对照,但没有声明是否同数据顺序——把它当作方法建议看,不要当成报告背书。判据建议同时看两个:相对 loss 误差,以及少量下游任务分数;不要用单步 loss 曲线的形状下结论——训练本身的随机性足以制造出「看起来 FP8 更差」的曲线。

第五步:给自己定阈值时,以「同规模」为限。 报告那句「低于 0.25%」是在两个中等规模、约 1T token 的条件下测得的;把它当成一个「同量级参考」而不是你的验收线。规模、数据、超参一变,误差的可接受带也会变。真要立内部标准,就在自己的尺度上先跑一次 bf16 重跑的方差,把「随机性带宽」量出来,再判断 FP8 是否落在带内。

一句提醒:这五步里最容易跳过、也最容易出事的是第三步。第七节的表讲得很清楚——第一类误差是局部现象,用全局指标去监控它,等于没有监控。

十三、从 FP8 到 4 位:治理结构没变,件数变多了

如果 FP8 的结论成立,一个自然的问题是:再往下压到 4 位会怎样?NVIDIA 后续的 NVFP4 预训练工作给出了一个很清楚的回答:治理结构完全一样,只是每一件都要做得更狠。

它报告的要素可以逐条映射回本文的框架:

  • 格式是 E2M1(2 位指数、1 位尾数),可表示的最大幅度只有约 6——相对精度降到极致,于是分块缩放的粒度进一步细到每 16 个元素,缩放因子用 E4M3 存储,再加一个每张量 FP32 因子防溢出。
  • 引入了随机 Hadamard 变换(16×16)来「重塑张量分布、使其更接近高斯」,从而压制块级离群——这对应本文第五节的思路:块内跨度越小,越不容易越界。
  • 用随机舍入替代确定性舍入。这一点值得单独算一下:确定性舍入的误差是系统性的(同一个数每次都被往同一个方向拉),而随机舍入让

E[Q(x)−x]=0\mathbb{E}\left[Q(x) - x\right] = 0

即误差在期望意义上无偏,代价是方差变大。在 4 位这种极端精度下,「有偏」比「有噪」更致命,所以宁可换。

  • 权重改用 16×16 的二维量化块,理由可以自己推出来:如果按一维(比如 1×16)切块,权重矩阵 WW 与其转置 W⊤W^{\top} 的分组成员就不一样,同一个元素在前向与反向会落在不同的量化块里、得到不同的量化值;而 16×16 的二维块在转置下成员集合不变,前后向自然一致。
  • 最后几层保留更高精度——这与 FP8 时代保留 attention/归一化/gating 是同一个策略:把「对噪声最敏感的部分」从低精度里摘出去。

效果参照:这份工作用一个 12B 模型、在 10T token 上训练,报告的 MMLU-pro 得分为 62.58%,与 FP8 预训练基线的 62.62% 基本持平。

于是可以得到一个比「位数越低越难」更有用的判断:低精度训练的难点不在位宽,而在「有多少件事必须同时做对」。FP8 需要做对两件(分块缩放 + 高精度累加),4 位需要做对五件(更细分块 + 分布整形 + 随机舍入 + 二维块 + 选择性高精度层)。位宽下降带来的是链路变长,而不是某一环的难度突增。

十四、边界与未解

以下几条是本文认为必须说清的限制,而不是瑕疵:

  1. 报告的 2% 是随机矩阵的测试结果,不是「任何模型上都会差 2%」。本文用它来标定误差模型的数量级,不能反过来当作你自己任务的收益或损失预期。
  2. 0.25% 的相对 loss 误差是在两个较小规模(约 V2-Lite / V2 量级)、约 1T token 上测得的,不是 671B 全量预训练的逐点对比。把这条外围证据与「671B 全程无回滚」的工程结论分开看,才是对报告的正确读法。
  3. 本文第六节的误差模型是自建的数量级模型,它给出的 25% 与 0.39% 是上界与随机估计,不是报告的推导;报告只给了「接近 2%」这一个实测值。模型的价值在于解释「为什么 KK 越大越糟、为什么截断有效」,不在于精确预测误差。
  4. 分块在激活侧不能照搬权重侧。 报告指出按权重方式对激活做块级缩放会引发训练不稳定(附录 B.2),这意味着「离群值只污染本块」这个结论在激活上需要按 1×128 的形态才能成立;这块的完整稳定性分析只能回到报告的附录。
  5. E5M6 不是标准格式。 它是这份工作为「attention 之后的 Linear 输入」单独定义的自定义精度档,跨框架复用时没有现成载体;同时它的缩放因子被取整为 2 的整数幂,这是一处刻意的工程取舍(牺牲一点表示效率,换取反向换排列时不引入二次量化误差)。
  6. 提升操作并非无代价。 报告明说它会降低单个 warpgroup 的 WGMMA 发射率,靠 H800 上两个 WGMMA 并发才能把开销隐藏掉。若硬件并发度不同,这笔开销就未必能白拿。
  7. 本文第五节那个 3.1% 的受影响元素占比是一个带假设的算例(C=4096C = 4096、单离群通道、落在独立块内),真实激活的离群分布未必满足这些前提;它只用来做量级对照。
  8. 第十二节的方法清单是本文组织的,不是报告给出的流程。 其中「按分组统计下溢比例」与「纯 GEMM 误差探针」两步,报告中并没有以这个形式出现——报告给的是结论与硬件建议,落到工程诊断清单是本文的整理。

十五、五条常见误解

误解一:「FP8 精度只有 3 位尾数,所以训练注定比 BF16 差很多。」 不成立。相对误差是 2−p2^{-p} 的量级,但真正的差距由「有多少元素掉出正规区」决定;分块缩放正是把这个问题按分组规模缩小。

误解二:「分块量化提高了 FP8 的表示精度。」 没有。FP8 的位布局没变,2−p2^{-p} 也没变。分块改变的是离群值的影响半径,以及分组内部的动态范围。

误解三:「用一个缩放因子就够了,反正误差是相对的。」 这句话在正规区内是对的,正是本文明确定下来的结论;但它恰好掩盖了真正的失败模式——下溢。共享范围越大,越有可能出现「同一组里既有 10510^{5}、又有 10−310^{-3}」的局面。

误解四:「装下 8 位、算得快就行,累加精度无关紧要。」 恰恰相反。报告给出的硬件事实是:对齐后只取高约 14 位,K=4096K = 4096 的随机矩阵 GEMM 最大相对误差接近 2%——而这是在量化已经做对之后仍然存在的误差。必须靠提升到 FP32 累加来截断。

误解五:「E4M3 和 E5M2 随便选一个都行。」 两者的取舍是明确的:E4M3 换精度、E5M2 换范围。传统配方因此前向用 E4M3、反向用 E5M2;而 DeepSeek-V3 敢全线用 E4M3,前提是分块缩放已经把每组的动态范围需求压下来了——这是一个依赖前一项设计的结论,不能单独摘出来用。

十六、小结

把全文压缩成四句话:

  1. 浮点量化的相对误差与缩放因子无关,恒为 2−p2^{-p};共享缩放因子的真实代价是下溢,而一个共享因子只覆盖约 214.82^{14.8} 的组内跨度。
  2. 分块量化不提升精度,只缩小离群值的影响半径:同样的离群值,整张量缩放伤 100% 的元素,1×128 分块最多伤到 128f/C128f/C 的比例。
  3. 累加是第二重误差,与量化无关;它的上界随连续累加步数增长,所以对策是截断——每 NC=128N_C = 128 个元素把部分和提升到 CUDA Core 做 FP32 累加,把最坏界按固定倍数折掉。
  4. DeepSeek-V3 的五条设计各自对应一重误差:分块缩放治下溢、提升累加治截断、E4M3 全集治精度、在线量化治尺度滞后、低精度存储与通信治带宽——而它们能被组合起来的前提,是「沿归约维分组缩放」与「高精度累加」在工程上被当成一件事实现。

真正值得带走的判断是最后这一条:低精度训练不是「选一个格式」,而是「为一组误差找到一个能被拆开、逐项治理的结构」。DeepSeek-V3 的贡献不在于发明了 FP8,而在于把这套结构做到了 671B 的规模上,并且用「全程无不可恢复回滚」给出了工程证据。而当下一个位宽(4 位)到来时,变的只是清单长度,不是这份结构。

最后补几条「怎么用这篇」的话,它们比结论本身更影响它的价值:

  • 把它当检查表,而不是当结论。 第一节到第六节的推导给出的是一组判据:下溢门槛 214.812^{14.81}、累加步数 mm 的线性项、以及 1/(1−r/2)1/(1-r/2) 的加速上界。它们的价值在于你能拿自己的数据代进去。
  • 代进去之后结论与本文不同,是正常的——那才是判据被使用的证据。反过来,如果一篇文章的所有数字都只能由原文复述、不能被代换,它提供的是措辞,不是判断。
  • 分清「来源说的」与「本文算的」。 文中每个数字都能在文末两条清单里找到归属:来源清单里的属于报告与论文,自行推导清单里的属于本文的模型。
  • 引用数字时请连归属一起引用,否则一个带假设的算例会在传抄中变成一条「官方结论」——这是技术解读里最常见的信息失真方式。
  • 格式选择应当先实测、再定论。 E4M3 与 E5M2 的取舍在本文是一张表,在你的栈里应该是一次实验:同一批数据、同一个 KK,分别量化成两种格式,比较最大相对误差与误差分布,而不是照搬别处的结论。
  • 关于复现。 本文所有自算数字都能用文中的算式手算复现,不需要任何未公开数据;这正是把「解读」与「转述」区分开的方式。
  • 若只想快速取用:看第七节的误差清单(判断瓶颈在哪一类)与第九节的对策对照表(DeepSeek-V3 各选了什么);若要做改造,从第十二节的第零步开始。

这几条合起来,就是这个栏目做深度解读的底线:宁可把边界写清楚,也不制造确定性。

📋 来源与核验记录

下列一手来源均为本轮实地打开核验(2026-10-03):

  1. DeepSeek-AI. DeepSeek-V3 Technical Report. arXiv:2412.19437(v1 2024-12-27 提交,v2 2025-02-18 修订)。用于:模型规模与训练成本(671B 总参数 / 37B 激活、14.8T token、2.664M 预训练 GPU 小时、合计 2.788M H800 GPU 小时、按每 GPU 小时 2 美元折算约 557.6 万美元)、FP8 训练在约 1T token 上相对 loss 误差低于 0.25%、第 3.3 节混合精度框架与五项策略、第 3.5.2 节「对齐 32 个尾数积、右移对齐后只取高 14 位」与第 3.3.2 节「K=4096 随机矩阵 GEMM 最大相对误差接近 2%」。https://arxiv.org/abs/2412.19437
  2. 上述报告的 arXiv HTML 全文版(第 3.3.1–3.3.3 节的完整正文;量化粒度 1×128 激活 tile 与 128×128 权重块、在线量化、AdamW 矩存 BF16 而主权重/梯度保 FP32、attention 后 Linear 输入用自定义 E5M6 且缩放因子取 2 的整数幂、MoE dispatch 前量化 FP8 而 combine 保 BF16、提升到 CUDA Core 的累加区间为 128 个元素相当于 4 次 WGMMA,均出自这里)。https://arxiv.org/html/2412.19437v2
  3. Micikevicius, P. et al. FP8 Formats for Deep Learning. arXiv:2209.05433(v1 2022-09-12,v2 2022-09-29)。用于:E4M3/E5M2 的位布局定义、E4M3 通过不表示无穷且只保留一个 NaN 位型来换取动态范围、以及该格式在含最大 175B 参数语言模型在内的任务上匹配 16 位训练质量。https://arxiv.org/abs/2209.05433
  4. NVIDIA. Using FP8 and FP4 with Transformer Engine(Transformer Engine 官方文档的 fp8_primer 示例章节)。用于:E4M3 上限 448 / E5M2 上限 57344、前向 E4M3 与反向 E5M2 的通行理由、即时刻度与延迟刻度两种缩放策略的权衡、微缩放 MXFP8 的 32 元素粒度与 E8M0 缩放因子、NVFP4 的 16 元素粒度与 E4M3 缩放因子、以及「明确注明 as described in DeepSeek-v3 paper 的分块缩放配方(Float8BlockScaling)」这一落地证据。https://nvidia.github.io/TransformerEngine/examples/fp8_primer.html
  5. NVIDIA. Pretraining Large Language Models with NVFP4. arXiv:2509.25149。用于:FP8 训练已被广泛采用、继续下压到 4 位时的稳定性挑战(随机 Hadamard 变换压制块级离群、二维量化、随机舍入、选择性高精度层),以及 12B 模型 / 10T token 上 MMLU-pro 62.58% 与 FP8 基线 62.62% 的对照。https://arxiv.org/abs/2509.25149
  6. Open Compute Project. OCP Microscaling Formats (MX) Specification, Version 1.0。用于:微缩放格式的规范化定义(含 E8M0 缩放数据类型)与其参与厂商范围。https://www.opencompute.org/documents/ocp-microscaling-formats-mx-v1-0-spec-final-pdf
  7. deepseek-ai/DeepSeek-V3(官方仓库 README)。用于:模型摘要(61 层、MoE、MLA)以及其列出的 FP8/BF16 推理支持生态(vLLM、SGLang、LMDeploy、TensorRT-LLM、MindIE)。https://github.com/deepseek-ai/DeepSeek-V3

本文自行推导与自算数字(非上述来源,属本文计算,假设值已随算式列出):

  • 第三节的格式对照表:半 ulp 相对误差上界 2−p2^{-p} 的取值(E4M3 的 6.25%、E5M2 的 12.5%、E5M6 的 0.78%、bf16 的 0.39%、fp32 约 5.96×10−85.96\times10^{-8}),以及两种 FP8 格式正规区比值范围的折算(E4M3 约 214.82^{14.8} / 28672,E5M2 约 229.82^{29.8} / 9.40×10⁸)。
  • 第四节的相对误差推导 ∣x^−x∣≤∣x∣⋅2−p|\hat{x}-x| \le |x|\cdot 2^{-p},以及由它导出的两道下溢门槛:保持全精度需 ∣x∣≥a/28672|x| \ge a/28672(约 3.49×10−5a3.49\times10^{-5}a)、完全归零阈值(按四舍五入、半个次正规刻度)为 ∣x∣<a/458752|x| < a/458752(约 2.18×10−6a2.18\times10^{-6}a)、分组内部跨度判据 214.812^{14.81}。
  • 第五节的算例模型与结果:隐藏维度 C=4096C = 4096、单离群通道 f=1f = 1 时,整张量缩放受影响元素占比 100%、1×128 分块受影响元素占比 3.1%;正态情形下 128 个样本最大值的期望约为 3.1 倍标准差(2ln⁡128\sqrt{2\ln 128});以及「归零需要跨度比超过约 218.81≈4.6×1052^{18.81} \approx 4.6\times10^{5}」的折算。
  • 第六节的累加误差数量级模型:以「每次加法丢弃不超过最大量级 × 2−t2^{-t}、t=14t = 14」为假设,m=4096m = 4096 时最坏界 25%(4096×2−144096\times2^{-14})、随机游走估计 0.39%(4096×2−14\sqrt{4096}\times2^{-14});m=128m = 128 时最坏界 0.78%(128×2−14128\times2^{-14})、随机游走估计 0.069%(128×2−14\sqrt{128}\times2^{-14});以及「截断到 128 使最坏界缩小 32 倍」的比值。
  • 第六节末「缩放因子可随 FP32 反量化一起在 CUDA Core 上乘」与第八节「NC=128N_C = 128 相当于 4 次 WGMMA、即每段 128 元素」的对应关系,为本文依据报告第 3.3.2 节正文所做的归纳。该数值在报告中直接给出,原文为「setting NC=128N_C = 128 elements, equivalent to 4 WGMMAs, represents the minimal accumulation interval…」;本文发布前又复核了一次 arXiv HTML 的内联公式(alttext="N_{C}=128")确认无误——注意纯文本抽取该页会丢掉内联数学,只看抽取结果会误以为符号缺失。
  • 第 5.1 节的算例:缩放因子 0.0279 与 2.232、全精度门槛 4.36×10⁻⁴ 与 3.49×10⁻²、0.03 量级元素的两条误差算法(相对误差给出 1.88×10⁻³、ulp 半刻度给出 1.74×10⁻³)、次正规区下 0.02 量级元素的相对误差约 10.9%(半刻度上界;该点按最近舍入实际约 9%;对比正规区的 6.25%)、“是门槛的约 46 倍”这一比值,以及 E4M3 次正规档位共 7 个的计数,均为本文自算。
  • 第 9.1 节的成本折算:由报告给出的 2.664M H800 GPU 小时 / 14.8T token 推出的「每 1T token 约 180K GPU 小时」,以及换算到 2048 卡集群的「每 1T token 约 3.7 天」,均为本文自算(报告只给总量)。
  • 第 6.4 节的三处一致性自查:随机游走估计 0.069% 与最坏界 0.78% 构成的区间、块内跨度比约 3 对应的约 1.6 个二进区间、以及「1.6 / 14.81 约 11%、余量接近 9 倍」的折算,均为本文自算。
  • 第十二节第零步给出的判据线(Rg≲210R_g \lesssim 2^{10} 与 214.812^{14.81})为本文据第四、五节判据自行整理的诊断口径。
  • 第 11.1 节的收益上限推导:T′=T(1−r/2)T' = T(1 - r/2)、speedup=1/(1−r/2)\text{speedup} = 1/(1 - r/2),以及 r=0.6r = 0.6 时约 1.43 倍、r=0.8r = 0.8 时约 1.67 倍的代入值,均为本文自算。
  • 第十三节的映射与公式:随机舍入的无偏性 E[Q(x)−x]=0\mathbb{E}[Q(x)-x]=0、以及「一维块在转置下分组成员改变、16×16 二维块在转置下成员集合不变」的推导,均为本文自行整理(NVFP4 相关事实来自来源 5 与来源 4,推导与映射关系为本文所加)。

未能核实的点(如实记录):

  • 报告附录 B.1(FP8 验证实验的模型规模细节)与附录 B.2(激活按块缩放导致训练不稳定的分析)本轮只读到正文对其的引用,未逐页核对其内部数据。
  • 第五节 3.1% 的算例假设「离群通道落在互不相同的块内」,真实激活的离群结构可能集中在同一块的相邻通道上,此时受影响比例会低于该算例。