返回博客

2026.09.17

同一张卡,8bit 比 4bit 单流快 10%——为什么我最后选了慢的那个?

四天前我在这张卡上测完一个 27B 稠密模型,结论是官方 8bit 全面领先。换成 35B 的 MoE 再测,方向整个反了:8bit 单流仍然快,但一上并发就全线输,因为它的权重多占了 11 GiB,换走了 60 万 token 的上下文空间。这篇给出那个换算的除法,和一条判断「这个量化结论能不能外推」的判据。

llmquantizationmoebenchmark

同一张 64 GB 的卡,同一套压测脚本,中间只隔了四天。

第一轮测一个 27B 的稠密模型,官方 8bit 权重赢了 4bit,赢得干干净净——解码更快、上下文缓存还更大。我把结论写进笔记:这张卡上选官方 8bit。

第二轮换成 35B 的 MoE 模型,我以为是走个过场。结果 8bit 单流解码仍然快 9.8%,但并发一开到 8 条就开始输,32 条时输 22.5%。最后进生产的是那个单流更慢的 4bit 版本。

中间没有任何一个环节出错。两个结论都对,只是第一个不能搬到第二个头上,而我差点就搬了。这篇讲那个差异是从哪来的,怎么用一个除法算出来,以及我自己在这轮测量里翻的一次车。

想直接拿判据的看第 2 节,它是一个除法;想知道我怎么给自己的结论挑出毛病的,看第 5 节。

1. 先看这两张表差在哪

量化就是把模型权重从高精度压到低精度存——8bit 一个权重占一字节,4bit 占半字节,模型体积直接减半,代价是精度损失。直觉上这是一个"省显存换质量"的滑块,位宽越低越省。

27B 稠密模型那轮,这个直觉完全成立:

官方 8bit 4bit
体积 29 GiB 26 GiB
单流解码 72.7 tok/s 69.6
上下文缓存 296,766 token 335,717

体积只差 3 GiB,8bit 解码还快一截,那 3 GiB 换来的缓存差距也不大。选 8bit,没什么好犹豫的。

35B 的 MoE 版本,同一张卡,同一套参数:

4bit 官方 8bit
体积 24 GiB 35 GiB
单流解码 147.1 tok/s 161.5
上下文缓存 1,531,743 token 925,214
8 条并发聚合 741.7 tok/s 627.9
32 条并发聚合 1838.3 1501.2

体积差从 3 GiB 变成 11 GiB,上下文缓存的胜负直接调了个头。

MoE 是"混合专家"——模型内部分成很多个专家子网络,每处理一个词只叫醒其中几个干活。这个模型有 256 个专家,每次激活 8 个。所有专家的权重都得装进显存待命,但每次只有 1/32 在动。

关键就在这。

2. 那个除法:总参数管容量,激活参数管速度

解码速度是搬砖速度的问题——每吐一个词,得把这次要用到的权重从显存里读一遍,所以看的是激活参数量

上下文缓存能装多少,是权重占完之后剩多少地方的问题,所以看的是总参数量

稠密模型这两个是同一个数,所以位宽一降,解码变快、缓存变大,一起变好。MoE 把它们劈开了:

总参数 / 每词激活参数 = 脱钩倍数
稠密 27B:      27 / 27 = 1
MoE 35B-A3B:   35 / 3  ≈ 11.7
只看专家部分: 256 / 8  = 32

脱钩倍数越大,"位宽换体积"和"位宽换速度"这两笔账离得越远。

把体积差换算成上下文,用这个除法:

单个 token 的缓存占用 ← 两版体积差 ÷ 两版缓存 token 数差

代进实测:

11 GiB × 1048576 ÷ (1531743 − 925214) = 19.0 KiB/token

这不是什么经验规律,就是一个除法。反过来用就知道那 11 GiB 值多少:

11 GiB ÷ 19.0 KiB = 606,529 token ≈ 2.3 个满窗口

8bit 那 11 GiB 的体积代价,等于吃掉两个多完整的长上下文窗口。 而它换回来的是单流快 9.8%——那一侧根本不是生产会待的地方。

同样的除法放回 27B 稠密那轮,每 token 占 88.1 KiB,3 GiB 体积差只换走 3.24 GiB 缓存,接近一比一。所以那轮 8bit 赢得理所当然:它省下的位宽收益,没被体积代价吃掉。

3. 一个用来验自己算得对不对的检查

上面那个 19.0 KiB 是从两个版本的差值反推的,万一其中一个数抄错了,我不会知道。所以补一个交叉验证:拿它正着算回去,两版剩下的零头应该一样。

显存预算是 64 GiB 的 90%,也就是 57.60 GiB。

4bit : 57.60 − 24 权重 − 27.78 缓存 = 5.82 GiB
8bit : 57.60 − 35 权重 − 16.78 缓存 = 5.82 GiB

两边剩的都是 5.82 GiB。这部分是激活值、图捕获之类的固定开销,跟权重位宽无关,本来就该一样。它一样,说明那个 19.0 KiB 站得住,也说明两个版本确实跑在同一套显存参数下。

这个检查值得养成习惯:任何从差值反推出来的常数,都拿它正着算一遍,看余项对不对得上。对不上就是某个输入抄错了,或者两组数据的口径根本不同。

4. 拆穿别人的量化跑分:先问它同时开了几条流

网上绝大多数量化对比只给一个"解码 tok/s"。这个数默认是单流跑出来的——一个请求,独占整张卡。

看这条曲线在什么位置翻转:

并发 4bit 8bit 4bit 优势
1 147.1 161.5 −9.8%
8 741.7 627.9 +18.1%
32 1838.3 1501.2 +22.5%
128 3432.9 3016.0 +13.8%

交叉点在 1 到 8 之间。 单流那一档的胜负,和 8 条以上的胜负是相反的。首字延迟也是同一个方向:8 条并发时 4bit 是 0.10 秒,8bit 要 0.59 秒。

所以看任何量化跑分,先问两句:同时开了几条流,以及上下文缓存还剩多少 token。只报单流解码速度而不报并发曲线的对比,在 MoE 上会稳定地把人带向错误的那一边——因为位宽的收益全在单流那一侧,代价全在并发这一侧。

如果那份跑分只给了单流数字,也不必直接扔掉。它至少还告诉了你体积,拿第 2 节那个除法自己把缺的一半补上:体积差除以每 token 占用,就知道它换走了多少上下文。

5. 我自己这轮测量里的三个毛病

写到这里前面的数字都挺好看,但有三处我得摊开说,不然上面那些不该被信。

第一处,我拿两张不同的卡凑了一个对比。 这轮为了省时间,两个版本并行跑在不同卡上。这引入了一个新变量:卡的温度状态不一样,会降频。

补的动作是换卡复测:

卡0 卡1 卡2
4bit 147.1 145.5
8bit 161.5 162.5

卡间差 ≤1.1%,量化差 9.8%,差了近十倍,归因成立。

但我原始笔记里写的是"8bit 单流赢 10.5%"——那个数是拿 8bit 最好的一张卡(162.5)比 4bit 最差的一张卡(145.5)算出来的,一边挑了个高的,一边挑了个低的。同卡对比是 9.8%。 本文全部改用同卡数字。1.1% 的卡间差不影响结论方向,但报一个自己没在同一张卡上测出来的差值,是个该改的习惯。同样的问题在预填充那行也有:跨卡算是 +6.6%,同卡是 +8.9%。

第二处,并行测量得挑指标。 解码可以并行测,因为每张卡的显存和算力是独占的。但并发扫描不行——128 条并发的时候瓶颈可能在主机 CPU 上,两边同时打会互相拖,数字就不可比了。那部分是串行跑的。

规则是:并行化测量前先问一句,这个指标的分母是共享的吗。显卡独占,可以并行;主机 CPU、网络、磁盘是共享的,必须串行。

第三处,质量差我不敢说赢。 140 题四域评测,4bit 均分 9.35,8bit 9.49,差 0.14。其中 124 题同分,剩下 16 题里 8bit 赢 11 题。配对检验 t=1.49,95% 置信区间跨零,统计上不显著。

所以准确说法是:这轮没测出质量差异,不是测出了两者相等。 140 题这个样本量,就分辨不了 0.14 分。真想定这件事得加题量。

还有一条我先前信错的。 有份广被引用的说明讲,社区 4bit 量化会把投机解码的草稿头一起压掉,导致它基本失效。这份 4bit 权重的草稿头确实全压到 4bit 了,按那个说法应该废掉。实测接受长度 2.23,8bit 是 2.27,差 1.8%,逐位置的接受率形状也一致。没崩。

判据得改一下:查草稿头张量还在不在仍然必要(一个都没有 = 直接出局,这是存在性判断),但张量存在之后不能再假定"4bit 的一定废"——那是质量判断,只能实测。

6. 还没做的

诚实起见列一下,这几处补完之前我不会把结论说死:

  • 质量只测了 140 题,分辨不了 0.14 分的差距。要定论得加题量。
  • 并发只扫到 128 条,没扫到饱和拐点。更高档位谁赢不知道。
  • 只测了这一个 MoE 模型的这两份权重。脱钩倍数 11.7 是这个模型的,别的 MoE 得自己算。
  • 上下文缓存的 token 数是引擎启动时报的容量,不是塞满实测的。

7. 下次遇到量化选型,按这个顺序问

  1. 这是不是 MoE?看配置文件里有没有专家数和每词激活数这两个字段。
  2. 是的话,算脱钩倍数:总参数除以每词激活参数。接近 1 就是稠密,同架构的旧结论可以外推;远大于 1 就得重测,倍数越大越不能信外推。
  3. 算每 token 的缓存占用:两版体积差 ÷ 两版缓存 token 数差。
  4. 拿这个数把体积差换算成上下文 token,看它换走了多少个完整窗口。
  5. 并发扫描扫到你实际会遇到的档位,找那个交叉点在哪。别拿单流定案。
  6. 两版跑在同一张卡上再比。做不到就先测卡间差,确认它比待测效应小一个量级。
  7. 质量差算一下置信区间。跨零就写"没测出差异",别写"赢了"。

那张卡最后跑的是 4bit,单流慢 9.8%,多了 60 万 token 的上下文。四天前我在同一张卡上写下的结论,救了它一次——因为我没有直接照抄。