桃子桃子快讯
返回首页
工具

CPU 推理优化实战:重写输入格式让小模型快 6.5 倍

作者在免费 ARM 机器上跑 llama.cpp,发现把输入改成键值对格式比普通散文快 6.5 倍且更准。

2026.07.31 · 周五5 分钟阅读

在一台 4 核 ARM、零预算的 Oracle 免费机器上,作者维护着一套以 CPU 为目标平台的 llama.cpp 推理服务。两周下来,他试遍了引擎层面的常规优化手段,最后真正把速度提上去的并不是内核,而是「文本本身」。

三个看似应该有效却失败的方向

  • 跟进 llama.cpp 上游一年的 ARM kernel 优化:在该量化与 CPU 上实测加速 0%。
  • 把量化换成更粗的 Q4_0:prefill 快 37%、decode 快 19%,但 20 题事实抽取测试中错了 5 个,被否决。
  • 把 MoE 模型 prefill 阶段的活跃专家数减半:快了 44%,却会「污染」KV cache——用 4 专家写入、再用 8 专家读出,准确率从 14/20 掉到 11/20,且损伤被固化在缓存表征里。

让模型「少读几遍」才是关键

同一份文档、同一道题、同一份模型,仅把输入从散文改成 label: value 列表(一行一条事实、条件挂在所修饰的字段上),结果出现反转:

  • 原始散文:2137 token,首 token 延迟 40.5 s,事实题 19/20。
  • 压缩散文:1185 token,21.0 s,20/20。
  • 键值列表:405 token,6.2 s,20/20。

键值格式比原文快约 6.5 倍且更准。为了解释「少 token 反而更准」,作者 dump 了后 softmax 注意力分布:在四个相近价格密集排列的段落里,散文形式下模型对正确价格的注意力只比对错误的高 1.1:1(甚至在小型 MoE 上是 1.9% vs 1.7%,接近抛硬币),而改成键值结构后比例变成 7:1。结论是:散文把价格和服务塞在同一句里,模型能「看见」数字却无法把它和指代物绑定;键值格式把绑定关系从语义层提到了结构层。

输出头吃掉近三成带宽

在很多小模型里,embedding 矩阵与输出投影是「tied」的——每生成一个 token,都要把它按完整词表 151,936 项打分一次。在作者的部署场景下(意大利语、个人代码、技术英语),实际只用得到 9,314 个词条。实测输出头占总带宽的 29.4%,活跃专家占 40.6%,其余注意力与 norm 占 29.9%。

把词表裁到 32k 是安全的,原因有两点:

  • tokenizer 是 byte-level,256 个字节字符全部保留,没有任何文本变得不可表示,最坏情况只是多消耗一个 token;
  • embedding 是 Q6_K,行对齐到完整量化块,裁剪后的存活权重与原模型按位一致,无重量化、无数值损失。

实测三次独立运行、误差 < 2%:decode 从 46.7 tok/s 提升到 55.0 tok/s,提速 17.8%。20 题事实抽取在裁剪前后完全一致(13/13 关键事实)。代价是同一段文档的 token 数增加 1.9%,因此在输入已经足够短时收益最大。理论带宽上限是 +30%,实测 17.8% 之间的差距,作者选择报告测量值而非推算值。

重打包悄悄吃掉的 4.2 GB

另一个不写在文档里的成本是 llama.cpp 在加载阶段会把量化权重重排成 NEON kernel 友好的布局。一个 5.37 GB 的模型,重启后常驻 9,825 MB,看起来像内存泄漏,其实不是:

  • CPU_Mapped model buffer size = 5068.51 MiB
  • CPU_REPACK model buffer size = 4254.45 MiB

而且重排并不只是「整理」:ffn_gate_expsffn_up_exps 会被重排,ffn_down_exps 甚至从 q6_K 被升到 q8_0_4x4,从 6 bit 膨胀到 8 bit。关掉它(-DGGML_CPU_REPACK=OFF)能省下 4.2 GB 常驻,但 decode 会从 45.96 tok/s 掉到 40.09 tok/s,速度损失 12.8%。在内存宽裕的机器上这是亏本买卖;在 8 GB 的小盒子上,这 4.2 GB 决定模型能不能跑起来——而这恰恰是这类部署的硬件目标。

这些数字的局限

事实抽取题目是作者自己写的 20 道题,针对一份意大利商业页面、用正则评分,单页面、单语言、单领域,是全文最薄弱的一环;外推时需要谨慎。但在「免费 ARM + 小模型」这一具体场景下,作者给出的是一组可复现的工程测量,而非口号式结论,对维护低成本 LLM 服务的开发者有直接参考价值。

信源