NVFP4 与 MXFP4 解码基准对比:B200 上 NVFP4 小批量解码快约 8%
NVFP4 vs. MXFP4 Decode Benchmark
在 B200 上用 vLLM v0.31 跑 Qwen3-32B 的实测显示,NVFP4 在小批量解码时比 MXFP4 快,batch 1、8、32 的解码吞吐分别高出 7.1%、7.6% 和 4.2%,batch 64 以上差距消失。差异主要来自 kernel 实现而非 4.5 与 4.25 bits 的位宽差,NVFP4 从 BF16 量化后的 NLL 损失也小 2.7 倍。
如果你一直在关注最新的 FP4 格式,你可能已经读过一堆比较 NVFP4 和 MXFP4 的文章:块大小、缩放格式,等等等等。
我个人没怎么见过实际生产推理工作负载上的实际结果。这重要吗?!
所以,Stas 在 B200 上测量了,NVFP4 在大 GEMM 上比 MXFP4 多出约 9% 的 TFLOPS。嗯,这差异挺大的!
但这仍然是一个孤立的 GEMM 基准测试。性能差异真的能转化到生产工作负载上吗?
另外,其他非 GEMM 瓶颈的工作负载呢,比如解码?还有……为什么?!
好吧,我们可以测试一下!也许我们能弄清楚。(这正是本文的重点,可能也是你还在读的原因)
好。我尽量保持简单,选了一个比较真实的稠密 LLM(Qwen3-32B),用 vLLM 在 B200 上服务。两种格式都是从相同的 BF16 权重从头量化的,这样我们尽量把混杂因素降到最低。
我的假设是 MXFP4 应该更快,因为我们会饱和 HBM 吞吐量,因为 MXFP4 的位数略小(4.25 对 4.5)。也就是说:这是经典的带宽受限工作负载,为什么不呢?
TL;DR

Claude 主要构建、我运行的基准测试表明,如果你使用 B200 GPU,你可能应该总是优先选择 NVFP4 而不是 MXFP4,优势明显(小批量下解码速度最高快约 8%)!
这适用于低批量解码,而且对于 GEMM 受限的训练,NVFP4 看起来也更好(见下文),不过原始大 GEMM 速度很大程度上取决于内核。在更大的批量下差异消失,起初这并不让我惊讶:我以为随着批量和 KV 缓存读取的增长,我们变得受 HBM 带宽限制。我不会剧透,但事实证明这不是原因!
此外,从 BF16 量化到各自格式并测量损失表明,NVFP4 应该能带来非平凡的更好评估性能。不过我没有运行任何评估来确认这一点。
现在,这些发现可能具有普遍性,但正如 Stas 建议的,你应该始终努力对你的实际生产配置进行基准测试。
内核实现似乎主导了性能差异
在 B200(SM100)上使用 vLLM v0.31,NVFP4/MXFP4 解码性能差异主要归结于内核实现,而不是 4.5 对 4.25 位的差异。再次注意,我只在一个稠密模型(Qwen3-32B,使用 BF16 KV 缓存)上测试了这一点。
小批量解码:NVFP4 明显更快
在批量 1、8 和 32 时,解码吞吐量分别提高 +7.1%、+7.6% 和 +4.2%。
值得强调的是,此工作负载的解码既不是带宽受限(约为理论 HBM 带宽的 40–50%),也不是计算受限(GEMM 很小),因此内核实现差异占主导。NVFP4 在这里的优越性能似乎主要来自 GEMM 周围的内核:激活量化、每步更少的内核等。

批量 ≥ 64:没有明显差异
所以如果你处于这个范围,不妨根据评估性能、可移植性或其他考虑来选择格式。
批量大小主导了性能差异,而且不是由于 HBM 内存带宽饱和
NVFP4 的非 GEMM 内核更快,但其 GEMM 随着规模增长落后于 MXFP4 的,从批量 64 开始,两个差异相互抵消。
那么,最终是批量大小还是令牌数量占主导?我保持批量为 1 并增加上下文,另外单独保持令牌数不变并增加批量:

原来是批大小的问题。看 @ batch 1,NVFP4 在上下文一直扩展到 127k token 时,每步都稳定节省约 0.4 ms(百分比之所以缩小,只是因为每一步变得更长了)。但在同样的 128k token 下,把批大小提到 128,节省就消失了。更多的内存流量并没有带来足够显著的差异,但更大的 GEMM 却带来了!嗯?
但为什么呢?!
也许更长的上下文只是增加了注意力计算,也就是更多的 KV cache 读取。记住,我对两种格式都把 KV cache 保持在 BF16,所以两者变慢的程度相同,NVFP4 得以保持领先。而另一方面,更大的批大小意味着更大的 GEMM,vLLM 会对 MXFP4 的 GEMM 做自动调优,但(我认为?)NVFP4 的则按固定启发式运行。所以随着 GEMM 增大,NVFP4 会越来越落后于 MXFP4,直到这种变慢抵消掉 NVFP4 的领先优势。也许吧!
现在,我仍不能 100% 确定这不是带宽问题:@ batch 128 时,MXFP4 的微弱优势与字节差异理论上应有的值相符。但在 @ batch 1 且上下文为 127k 时,内存流量相同、带宽使用相近,NVFP4 仍保持领先,而两次运行之间唯一变化的就是 GEMM 大小。
这让我困惑到需要重新审视,并直接从 GPU 读取一些指标来确认或排除这一点。
大型 GEMM(预填充/训练)高度依赖内核实现
在 PyTorch 中,NVFP4 的 TFLOPS 高出约 9%(ml-engineering book),但在那里(至少在我检查的 PyTorch 2.13 中)NVFP4 运行在 cuBLASLt 上,而 MXFP4 运行在另一个库(MSLK)上。在 vLLM 的内核(CuTe-DSL)中,NVFP4 最大的 GEMM 在 batch 512 时慢了 4% 到 20%。
此外,对于训练,格式本身也很重要。NVIDIA 自己的论文发现,用 MXFP4 训练的 8B 模型需要多 36% 的 token(1.36T 对 1T)才能达到与 NVFP4 相同的损失,而两种格式在 Blackwell 上的原始吞吐相同。
你应该在 vLLM 的默认内核上服务 NVFP4
也就是 CuTe-DSL(--linear-backend flashinfer_cutedsl)。在 cuDNN(flashinfer_cudnn)上,相同权重会慢 10% 到 18%,并且在每个批大小上都输给 MXFP4。MXFP4 在 vLLM 0.31 中只有一个 W4A4 内核(FlashInfer 的 mm_fp4,使用 CuTe-DSL 后端)。
NVFP4 更准确
其从 BF16 量化后的 NLL 惩罚小 2.7 倍。虽然没有运行评估,但更低的 NLL(负对数似然)表明 NVFP4 应能产生更好的评估结果。
来源:Hacker News · cezarcocu.com