跳到主内容
@wquguru
精选88r/LocalLLaMA(Reddit)技巧与观点

推理引擎加速开关导致MoE模型能力显著下降实测

Is your engine lobotomizing your model? Kinda, and I measured it

原文
发到 X
推荐理由

本地部署MoE模型的同学必看,这篇用数据揭示了所谓“加速黑科技”的真实代价,特别是小显存下的精度崩塌,建议对照调整你的推理参数。

I've been reading a lot about "engines lobotomizing the models they run", either because they quantize already quantized weights, or because they automatically turn on "hacky" flags to gain decode/prefill performance by default. I wanted to test this out by myself, not only with KLD but with real tasks, so I set up an experiment using Qwen 3.8 Flash Next with Basalt (disclaimer: I'm the developer) and two of the most popular "speed" flags:

我一直在阅读大量关于“引擎对运行的模型进行脑叶切除”的讨论,原因要么是引擎对已经量化的权重再次量化,要么是因为它们默认自动开启一些“投机取巧”的标志位,以换取解码/预填充性能的提升。我想亲自测试这一点,不仅使用 KLD 指标,还要结合实际任务,所以我搭建了一个实验,使用 Qwen 3.8 Flash Next 和 Basalt(免责声明:我是该项目的开发者),并启用了两个最受欢迎的“速度”标志位:

  • Routing bias: the engine pushes the model toward experts that are already on the GPU, so it sometimes gets a convenient expert instead of the one it actually wanted.
  • Tail skip: when one of the model's lower expert picks isn't on the GPU, the engine just skips it instead of fetching it.
  • 路由偏差(Routing bias):引擎会将模型推向那些已经加载在 GPU 上的专家,因此有时它会得到一个方便的专家,而不是模型真正想要的那个。
  • 尾部跳过(Tail skip):当模型选择的某个较低优先级的专家不在 GPU 上时,引擎会直接跳过它,而不是去获取它。

Both are faster because fewer experts come from RAM, but they change the output. I added them to the engine as opt in flags so I could measure the real cost with everything else fixed.

两者都能带来更快的速度,因为来自 RAM 的专家减少了,但它们会改变输出结果。我将它们作为可选标志位添加到引擎中,以便在其他条件不变的情况下衡量其真实成本。

DISCLAIMER: This post and the experiment were run by me, but it has been polished by AI.

免责声明:本文及实验由我执行,但经过 AI 润色。

Rig: RTX 5090 + RTX 5060 Ti and 128 GB of DDR5. Settings tested:

硬件配置:RTX 5090 + RTX 5060 Ti 和 128 GB DDR5 内存。测试的设置如下:

  • Shipped: bias 1.5, skip rank ≥ 7. Values other engines ship (or have shipped) as defaults on smaller cards.
  • Worst: bias 16, skip rank ≥ 1, plus relaxed draft acceptance. Worst case scenario, not something anyone ships or would make sense to use.
  • 出厂设置(Shipped):bias 1.5,skip rank ≥ 7。这是其他引擎在小显存卡上作为默认值提供(或曾提供)的值。
  • 最差情况(Worst):bias 16,skip rank ≥ 1,以及放宽的草稿接受策略。这是最坏的情况,并非任何引擎会提供或建议使用的设置。

1. KLD

100 chunks of wikitext, decode path, against a llama.cpp Q8 reference. Exact IQ3_XXS and Q2_0 are in there for scale.

100 个 chunk 的 wikitext,解码路径,与 llama.cpp 的 Q8_0 参考模型对比。其中包含了精确的 IQ3_XXS 和 Q2_0 用于比例参考。

Pack + settingFilePPLKLD meanSame top-1
Q8_0 exact178 GiB3.2760.03194.1%
NVFP4 exact122 GiB3.3040.06891.4%
IQ3_S exact81 GiB3.3850.15587.3%
IQ3_XXS exact74 GiB3.4700.24384.0%
IQ3_S + shipped81 GiB3.5830.24484.3%
NVFP4 + shipped122 GiB3.9310.34881.8%
Q8_0 + shipped178 GiB4.2210.40179.4%
Q2_0 exact65 GiB3.9490.43678.2%
NVFP4 + worst122 GiB5.9170.82371.3%
Q8_0 + worst178 GiB12.8581.61656.8%

Note: even exact Q8_0 is 0.031 away from the reference. That's mostly the reference's own noise, not damage: llama.cpp's Q8_0 rounds a few spots of this model more than Basalt does, which adds about 0.01-0.02 to every row equally, so the rows still compare fairly.

注意:即使是精确的 Q8_0,也与参考值相差 0.031。这主要是参考模型自身的噪声,而非损害:llama.cpp 的 Q8_0 对该模型的某些部分舍入程度比 Basalt 更大,这给每一行都均匀增加了约 0.01-0.02 的值,因此各行之间的比较仍然公平。

2. Does it really matter?

2. 这真的重要吗?

KLD by itself is just a number, so I also ran a task eval: thinking off, temp 1.0, top_p 0.95, top_k 20, two different sets of questions:

KLD 本身只是一个数字,因此我还运行了一项任务评估:关闭思维链,温度 1.0,top_p 0.95,top_k 20,两组不同的问题:

  • Ladders: 300 chained steps, scored by step.
  • Facts: 1200 questions with 5 popularity bands (rare to famous), 3 seeds.
  • 阶梯测试(Ladders):300 步连锁步骤,按步骤评分。
  • 事实问答(Facts):1200 个问题,分为 5 个流行度层级(从冷门到著名),3 个随机种子。
ConfigLaddersFactsLadders ΔFacts ΔProse tok/s
Q8_0 exact45.438.1117
NVFP4 exact45.638.0272
Q8_0 + shipped43.836.6-1.6 [-3.4, +0.2]-1.5 [-2.5, -0.5]202
NVFP4 + shipped44.136.8-1.5 [-3.2, +0.2]-1.2 [-2.2, -0.4]271
IQ3_S exact, small card*44.136.7192
IQ3_S + shipped, small card*38.934.3-5.2 [-7.1, -3.2]-2.3 [-3.4, -1.3]299
Q8_0 + worst26.62.7-18.8-35.3379
配置阶梯表事实准确率阶梯表 Δ事实准确率 Δ每秒词元数
Q8_0 精确值45.438.1117
NVFP4 精确值45.638.0272
Q8_0 + shipped43.836.6-1.6 [-3.4, +0.2]-1.5 [-2.5, -0.5]202
NVFP4 + shipped44.136.8-1.5 [-3.2, +0.2]-1.2 [-2.2, -0.4]271
IQ3_S 精确值,小卡*44.136.7192
IQ3_S + shipped,小卡*38.934.3-5.2 [-7.1, -3.2]-2.3 [-3.4, -1.3]299
Q8_0 + worst26.62.7-18.8-35.3379

* Small card: the 5090 alone capped to 16gb, the experiment was run this way because it was still much faster than the 5060 Ti.

* 小卡:仅 5090 被限制在 16GB,实验采用此方式是因为其速度仍远快于 5060 Ti。

On a big card the shipped flags barely matter (NVFP4: 272 -> 271 tok/s) and cost about 1.5 points, 4% of the facts the model knew. On a small card you get +56% speed but a much bigger hit. At the worst setting facts fall from 38% to 3%, and the model says things like "The Great Composer" with total confidence. Easy tests barely notice. The damage is mostly in chained reasoning and recalled facts.

在大显存卡上,shipped 标志的影响微乎其微(NVFP4:272 -> 271 tok/s),代价约为 1.5 个点,即模型已知事实的 4%。在小显存卡上,你获得了 +56% 的速度提升,但付出了更大的代价。在最差设置下,事实准确率从 38% 跌至 3%,模型会自信地输出诸如“伟大的作曲家”之类的内容。简单测试几乎察觉不到问题。损害主要出现在链式推理和回忆事实中。

3. Bonus: a loop in the model weights

3. 附加内容:模型权重中的循环

Not every bad output is the engine's fault. One prompt made Qwen 3.8 Flash Next get stuck into an endless run of 0 in its reasoning:

并非所有糟糕的输出都是引擎的错。有一个提示让 Qwen 3.8 Flash Next 陷入无限输出 0 的推理循环:

Setup, same request, seeds 1-4Stuck in zeros
Basalt, NVFP44 of 4
Basalt, IQ3_S4 of 4
Basalt, Q8_03 of 4
llama.cpp, same IQ3_S GGUF3 of 4
API (OpenRouter - Alibaba)6 of 6
设置,相同请求,种子 1-4陷入零值
Basalt, NVFP44 of 4
Basalt, IQ3_S4 of 4
Basalt, Q8_03 of 4
llama.cpp, 相同 IQ3_S GGUF3 of 4
API (OpenRouter - Alibaba)6 of 6

The odds of another 0 are the same on every quant and both engines: 0.99 after 10 zeros, 95%+ past 100 or so. top_p 0.95 leaves 0 as the only choice, and temp 1.0 doesn't fix it. The API fixes it by cutting the run at ~500 zeros. Basalt patched the issue as well, after 256 identical reasoning tokens it closes the thinking block and keeps going.

在所有量化方法和两种引擎中,下一个输出为 0 的概率是相同的:连续 10 个零后为 0.99,大约 100 个零后超过 95%。top_p 0.95 使得 0 成为唯一选择,而 temp 1.0 无法解决此问题。API 通过在约 500 个零时截断输出来修复此问题。Basalt 也修补了该问题,在生成 256 个相同的推理 token 后,它会关闭思考块并继续运行。

TLDR: there's no free lunch.

TLDR:天下没有免费的午餐。

  • Engines can buy speed on MoE models by turning on speed "hacks".
  • With values some engines ship, every pack drops to somewhere between IQ3_XXS and Q2 on KLD. A Q8 ends up next to Q2. This is as bad as it gets.
  • In practice the model forgets things it knew and loses the thread on multi step problems. Small cards get the biggest speedup and pay the most for it.
  • If your engine is faster than it should be on a model that doesn't fit, check whether it's still running the model you downloaded.
  • 对于 MoE 模型,引擎可以通过开启速度“黑客”手段来换取速度。
  • 使用某些引擎提供的 shipped 值时,每个包在 KLD 指标上都会降至 IQ3_XXS 和 Q2 之间的某个位置。一个 Q8 最终会靠近 Q2。这已经是最坏的情况了。
  • 在实践中,模型会遗忘已知的知识,并在多步问题上迷失方向。小显存卡获得的加速最大,为此付出的代价也最高。
  • 如果你的引擎在处理不适合的模型时比预期更快,请检查它是否仍在运行你下载的模型。

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

关联信息,但可能不是同一事件