折腾本地模型最烦的,是装上了才发现发布会里快的那部分跟你的机器没关系。
本地推理的 2 倍速不是白捡。它来自一套配合——小模型先猜,大模型一次验收,硬件把验收做成大矩阵乘。缺一个就掉倍率。
一套刚放出来的本地推理实现,把这套东西做到了 Apple M5 上:同样量化档位下,比 MLX 加投机解码快近 2 倍,比 llama.cpp 快 3 倍以上;数学和代码任务收益最明显。它把投机预算拉到 16 到 32 个 token,而常见的模型自带 MTP 通常只猜 3 到 4 个。
放到 M4 Pro 上,实测是另一幅画面:首 token 3.14 秒,prefill 117.43 t/s,生成 16.06 t/s,每次前向只落 1.00 个 token,占用 14.03 GB 内存。1.00 t/f 基本等于说,投机那部分没吃到收益。
投机解码在赌什么
普通自回归解码,每生成一个 token 都要把模型权重读一遍。GPU 算力大量闲着,瓶颈在显存带宽。投机解码利用这个空档:让更小的 draft 模型先猜几个 token,再让目标模型一次性全验一遍。
验完以后,从第一个被拒绝的位置截断,接受前面那一段,再补一个正确的 token。理想情况下,目标模型的单次前向成本没变,但每次前向的产出变多了。
- 1起草小模型按当前上下文连续猜 16 到 32 个 token
- 2并行验收目标模型一次前向,给每个位置算概率
- 3逐位比对从第一个不匹配处截断,保留前面接受的前缀
- 4状态回滚把 KV 缓存或循环状态退回到接受位置
- 5补一个 token目标模型给出被拒绝位置的正确 token,继续下一轮
关键不是“猜”,是“验”。猜得再多,只要验收不能把 16 到 32 个位置并行算完,省下的时间又会被验证成本吃回去。那套实现把 kernel 和量化 checkpoint 一起设计,就是让验收变成大矩阵乘,而不是一串小算子原地打转。
16 到 32 个 token,和 3 到 4 个差在哪
模型自带的 MTP 头一般只给 3 到 4 个 token 的 draft 链。链短,验收容易,但一次前向多推进的 token 有限。把预算拉到 16 到 32,等于加大赌注:猜对一段收益很高,猜错得早后面全废。
这条路线能成立,前提是 draft 和目标模型足够“像”。同源、同 tokenizer、同分布,接受率才上得去。数学和代码收益最大,也是这个原因:步骤有强约束,下一个 token 的可选范围窄,draft 容易猜中。开放式写作和长对话,接受率会明显下来。
draft 自己也要占内存。Qwen3.6 27B 在 M4 Pro 上已经跑到 14.03 GB,draft 再塞进来,16 GB 机器就很紧。预算拉到 32,验算的中间激活还会涨,省下的时间可能被内存压力和更小的量化档位抵消。
M4 的 1.00 t/f 说明了什么
16.06 t/s 只是表面,1.00 t/f 更能说明问题:每次前向只落一个 token,投机没形成“一次验多个”的收益。原因不神秘,这套实现是围着 M5 的 GPU Neural Accelerators 做的,draft、量化格式、验收算法和 kernel 一起调。换到 M4,硬件路径对不上,倍率自然兑现不了。
发布数字里的 2 倍、3 倍,通常是在“整套配置都对”时测出来的。换模型、换量化、拉长上下文,数字都会变。M5 之前的机器,现阶段更稳的选择可能还是成熟的 MLX 路线,没必要为一个没验证过的倍率换硬件。
三个会被平均值藏起来的问题
第一是接受率。吞吐翻倍是平均值,真正决定体验的是低接受率时的尾延迟。猜错得早,一轮只推进一两个 token,验算成本却按 16 到 32 个位置付。交互式使用看 p95、p99,不看峰值。
第二是并发。投机解码在单流、低 batch 下最舒服,因为算力本来有富余。batch 一上来,计算变成瓶颈,空档消失,收益缩水。跑共享服务和本地单人对话,是两笔账。
第三是长上下文。上下文越长,prefill 和 KV 缓存越重,省下的 decode 时间占比越小。主要做长文档问答,先测 prefill,别只看生成速度。
循环状态才是最难的一关
纯 attention 模型回滚简单:把 KV 缓存截到接受位置就行。但很多新模型带线性注意力、状态空间或门控线性层。这些层的状态是递推的,第 n 个 token 依赖第 n-1 个。你一次猜 32 个,第 5 个错了,后面 27 个的状态全得退回去。
退回去有两种做法:每个 draft token 存一份状态检查点,或者从接受位置重新算。前者吃内存,后者吃时间,预算越大账越难看。所以看到“16 到 32 个 token”,先问一句:循环状态怎么回滚?只对纯 attention 调过的实现,换到混合架构上倍率很可能消失。
真要上手,按这个顺序试
- 先确认模型架构。纯 attention 和带循环层的模型,回滚成本不是一个量级。
- 确认 draft 和目标模型同 tokenizer。不同 tokenizer 的投机,接受率很难看。
- 从 4 到 8 个 token 的预算起步,别一上来就 32。先看接受率,再看 tok/s。
- 用你自己的任务测:代码、数学、长文各跑一轮,记录 p50 和 p99。
- 固定变量:量化档位、上下文长度、batch=1。换一个变量,倍率就可能不成立。
最后
投机解码本质上是在拿显存和实现复杂度换 decode 吞吐。M5 这种把验收路径做进硬件的机器上很划算;M4 或更早的机器上,同一套东西可能只剩 1.00 t/f。看到 2 倍、3 倍,先看芯片、量化和任务。