Mac 实测 MTP:加速幅度随模型而变
作者指出所述 EAGLE-4 版本无法直接在 Mac 上运行,转而测试本地运行时的 MTP:27B 稠密模型代码生成加速 92%,35B MoE 模型文本生成减速 19%。测试均为关闭思考的单请求场景,8 个用例中有 7 个在温度为零时输出发生变化,尚未评估质量。
完整中文译文
本地模型的加速开关,可能让代码生成快 92%,也可能让文字生成慢 19%。作者原本想在 Mac Studio 上验证 EAGLE-4,发现发布版本不支持自己的环境,于是测试了运行时已有的 MTP(多 token 预测)。
结果最有价值的地方,是把模型结构、任务类型、首字等待和输出变化放到一起看。对用 Mac 跑本地编程模型的人,这比一个脱离设备和负载的加速倍数更有参考意义。
EAGLE-4 的加速数字,为什么不能直接搬到 Mac
推测解码(speculative decoding)的思路是:让一个较小、较快的「起草者」提前猜几个 token,再让大模型一次检查。如果猜中得多,就能用一次检查产出多个 token,减少大模型逐个生成的开销。
EAGLE-4 是专门训练的起草模型。发布说明报告,在四张 NVIDIA B300 上,Qwen3.8-27B 的生成速度最高提升到 3.4x。其起草模型 EAGLE-Corp/Qwen3.8-27B-EAGLE4 有 3B 参数,使用 BF16,通过 eagle-harness 接入 SGLang、vLLM,以及实验性的 TokenSpeed。
但快速开始要求 Linux、四张 NVIDIA GPU、CUDA 13 驱动和约 70 GB 磁盘,另有 AMD Instinct MI355X 指南。README 没提 Metal、MLX、llama.cpp 或 Apple Silicon,所以作者没有测到 Mac 上的 EAGLE-4。许可证也是源码可用,未经 OSI 认可,不能直接当成常见开源许可证。
这里还要核对比较对象。作者看到新闻引用「比原生 MTP 快 3.59x」,却没在 README 找到这个数字。README 的基线是同一引擎关闭推测解码,而非 MTP。两种说法回答的是不同问题。
作者实际测试的是 oMLX 的 Lightning MTP。部分模型自带额外的预测头,运行时可以用它起草后续 token,无须另加载一个起草模型,通过每个模型的 mtp_enabled 开关控制。
同一个 MTP 开关,为什么一边提速、一边减速
测试设备是 Mac Studio,Apple M2 Ultra,60 个 GPU 核心、64 GB 统一内存,系统为 macOS 26.5,运行时为 oMLX 0.7.1rc1。
作者按 OFF、ON、OFF、ON 顺序测试,每阶段重启服务,每进程只加载一个模型。任务包括 Kotlin 编程和约 350 词的文字解释,分别开启、关闭 thinking;每个提示每阶段运行 10 次,最多生成 512 tokens,温度为 0,默认串行流式请求。内核编译预热不计入结果,前缀缓存通过 --no-cache 关闭,内存保护也关闭。
主要结果很有反差:
| 模型与任务 | 开启 MTP 后的速度变化 |
|---|---|
| Qwen3.8-27B 编程,关闭 thinking | +92% |
| Qwen3.8-27B 编程,开启 thinking | +39% |
| Qwen3.8-27B 文字解释,开启 thinking | +1% |
| Ornith-1.5-35B-A3B 编程 | +9% 至 +12% |
| Ornith-1.5-35B-A3B 文字解释 | −7% 至 −19% |
| Ornith 长提示、四请求并发 | 分别 −11%、−8% |
关键不只是草稿猜得准不准,还包括检查草稿有多贵。作者用日志做了一个近似核算:
加速比 ≈ 每轮产出的 token 数 ÷ 每轮相当于普通解码的步数
Qwen 每轮成本约为普通解码的 2.1 至 2.2 步,Ornith 则是 2.6 至 2.7 步。Ornith 在文字任务中每轮只产出约 2.1 个 token,覆盖不了成本。它在编程任务上的草稿接受率达到 85%,高于 Qwen 开启 thinking 时的 78%,仍不足以保证更高收益。
作者推测,这与专家混合模型(MoE)的权重读取有关。Ornith 每个 token 从 256 个专家中选择 8 个,不同 token 可能调用不同专家;同时检查多个 token,会读取更多专家权重。它的普通解码本来就快,单步约 7.5 ms,而 Qwen 为 29.8 ms,固定开销也更显眼。
这只是解释假说。作者没有分析内核性能,问题也可能来自 oMLX 的实现,不能据此断言 MoE 普遍不适合 MTP。
生成更快,不等于编程助手响应更快
这次最显眼的 +92%,衡量的是首个输出块之后的解码速度。
作者用完成 token 数除以首尾流式输出块的时间差,排除了首字等待。可编程助手往往先要读取文件、上下文和工具结果,这部分叫预填充(prefill)。
输入 16,125 tokens 时,关闭 MTP 的 Qwen3.8-27B 需要 75.2 秒完成预填充,Ornith 需要 11.9 秒。开启 MTP 后,这一步反而更慢:Qwen 慢 1.7% 至 6.2%,Ornith 慢 2.5% 至 3.7%。
并发测试又用了另一种口径:全部完成 token 数除以总耗时,包含首字等待,不能与单请求的纯解码指标直接比较。Qwen 在四请求并行时仍受益,Ornith 则下降 8%。
输出一致性也是一个问号。关闭 MTP 时,各场景的 20 次运行都生成相同文本;开启后,8 个场景中只有「Qwen 编程、关闭 thinking」与原输出一致,其余 7 个场景均为 0/20 匹配,首次差异出现在第 26 至第 423 个字符之间,开启 MTP 的不同运行之间也有差异。
作者读到的样本主要是措辞变化,没有做质量评估。多 token 检查与单 token 解码的数值误差可能改变相近候选的排序,但原因尚未证实。温度为 0,在这个组合里也没有保证输出完全一致。
我的判断
这篇最有说服力的结论,是应该按「模型、任务、运行时、设备」分别验证 MTP,而不是把它当成通用加速选项。
实验有基本的控制:两轮开关交替、排除预热、记录系统状态。整个过程中 swap 不超过 100 MB,CPU 速度限制保持 100%,服务没有记录「Prefill throttled」。不过后台代码索引确实干扰过 Ornith 的 4 次测试,作者为相关单元格排除了慢样本;改用中位数仍是 132.7 对 111.4 tok/s,即 0.84x,减速方向没有改变。
局限同样明确。这里只有一台机器、一个运行时版本和社区量化模型;长上下文、并发测试仅跑一个阶段,每项 3 至 5 次。其他 Apple 芯片、更高温度、真实工具调用都没有覆盖。自动回退也不可靠:oMLX 曾暂停 MTP、改用 128 个普通 token 解码,却没有在 Ornith 的 512-token 减速场景触发。
与直接选更快模型相比,MTP 也未必是第一优先级。关闭 MTP 时,Ornith 单请求解码已经是 Qwen 的 3.95x;无 MTP 的对照模型 Qwen3-4B 则稳定在 159.2 至 159.9 tok/s。但这些数字不能证明谁更会写代码,质量比较尚未完成。
因此,架构解释目前是经验推断;速度收益有实测支撑,代码可用性还没有。
能拿来做什么
- 如果你恰好使用 M2 Ultra、oMLX 0.7.1rc1 和 Qwen3.8-27B,可以优先验证编程任务的 MTP 收益;使用 Ornith-1.5-35B-A3B 时,先以关闭为默认,再按任务比较。
- 给本地编程助手测速时,分别记录首字等待、持续生成速度和整次请求耗时,并加入常用的长上下文。纯解码 tok/s 无法反映读完整个输入需要多久。
- 用同一批真实编码任务检查开关前后的产物,至少验证能否编译、测试是否通过。原文没有质量结果,不能把速度提升当成可直接采用的依据。
- 需要复现实验时,按作者要求安装 oMLX 0.7.1rc1、下载三个模型,关闭重负载应用,再运行
./run_all.sh。作者全程耗时约 1 小时 43 分钟,结果可用python3 -I verify_numbers.py <results folder>重算。