【免费下载链接】TensorFold
LLM Inference Engine for Metal, CUDA and Vulkan.
TensorFold 是一个用 Zig 编写的 LLM 推理引擎,直接跑在 Metal、CUDA 和 Vulkan 上,无需 Python 或 MLX 依赖。它的解码默认走投机解码(speculative decoding):先用小得多的"草稿方"一口气提出一串 token,再让目标模型一次前向验证整串草稿——命中就整段收下,不中则回滚到分叉点。本文带你拆解 TensorFold 的两类草稿来源(MTP 草稿头与 DFlash2 Drafter),以及它在 64 路并发下如何保证每一路输出都与串行解码逐 token 一致。
先记住一条铁律:草稿可以错,输出不能变
TensorFold 对所有投机路径设了一条硬约束(见 docs/recipes/README.md):
- 草稿输出必须等于同一引擎串行解码(
"draft": false)的输出,逐 token 相同; - 采样器用seed、绝对位置、token ID给每次抽签定键,草稿只有在恰好命中目标模型的这次抽签时才被接受;
- 验证窗口中的每一行都要使用和串行步骤完全一致的算术(注意力边界、路由平局、循环状态更新都要对齐)。
也就是说,投机解码在 TensorFold 里是"零风险的加速":草稿错了大不了白跑,答案本身永远不会变。
MTP 草稿头:随检查点自带的"小抄"
MTP(Multi-Token Prediction)头是训练好的多 token 预测层,直接包含在检查点里,不需要额外下载草稿模型:
- Nemotron 3.5 Lightning 的
mtp-4bit.safetensors由tensorfold pull一并校验,serve时自动启用(docs/recipes/nemotron-3.5.md); - GLM-5.3-Flash 与 Qwen3.6 等家族同样把 MTP 层写进检查点,
pull后自动生效; - 关闭方式:
--no-drafts(完全串行解码)或请求字段"draft": false。
深度与置信度控制(CUDA 上的 Nemotron):
| 参数 | 含义 |
|---|---|
| 默认上限 | 3 个 MTP 草稿 |
--mtp-drafts N | 把上限设为 0–8 |
| 停止规则 | 后续草稿的累积头置信度低于 20%时停止,第一个草稿始终保留 |
--mtp-confidence P | 0–1 之间设定链条停止的阈值 |
引擎并不傻坚持固定深度。核心里的深度规则(zig/src/core/lanes/depth.zig)会为每个草稿深度维护"命中率"的滑动平均,按"每毫秒产出的 token 数"决定下一轮出多深的草稿;Flash Next 使用 3 / 6 / 15 三档,接受率高于 0.8 升档、低于 0.65 降档(详见 docs/recipes/adding-a-zig-family.md)。GLM 还支持更细的策略表:auto、固定深度N、按运行中接受率动态调整的a:LOW:HIGH、概率乘积阈值cN:P,以及 DFlash2 对应的fN/fcN:P/fa:...(docs/recipes/glm-5.3-flash.md)。
DFlash2 Drafter:给 Qwen3.8-27B 配一个独立草稿模型
对 Qwen3.8-27B,TensorFold 使用一个独立训练的 DFlash2 草稿模型,通过--drafter指定(默认就是z-lab/Qwen3.8-27B-DFlash2,pull模型时一起拉下来):
tensorfold pull TensorFold/Qwen3.8-27B-MLX-4bit z-lab/Qwen3.8-27B-DFlash2 tensorfold serve TensorFold/Qwen3.8-27B-MLX-4bit --name bench要点(docs/recipes/qwen3.8-27b.md):
- 拉下来后自动启用;MLX 上
--drafter none只关草稿模型,--no-drafts关掉一切草稿; --drafter-bits 4(默认)把草稿权重压到 4-bit,0则保留 bf16;- DFlash2 在草稿词表上切片目标模型的 6-bit 输出头读取 logits,因此它只是"提议者",验证永远用目标的完整词表;
- 效果对比(M5 Pro 64 GB,64 token 回复中位数,tok/s):
| 场景 | DFlash2 草稿 | --no-drafts串行 | 加速比 |
|---|---|---|---|
| 代码(采样) | 62.8 | 16.6 | ≈3.8× |
| 对话(采样) | 45.9 | 16.1 | ≈2.9× |
| 代码(贪心) | 61.2 | 16.2 | ≈3.8× |
| 对话(贪心) | 56.2 | 16.3 | ≈3.4× |
接受规则:GPU 上的 accept 内核
验证在 GPU 上闭环完成,主机几乎不插手:
- 窗口行:一轮验证把草稿排成链或树(最多 16 行),树结构允许携带多条备选路径;
- accept 内核在 GPU 上把每个草稿 token 与目标的"应然选择"比对,把裁决写进一块小 arena(zig/src/core/lanes/accept.zig 中的
acceptPath就是沿着"第一个 token 恰好等于目标选择的子节点"走出一条被接受路径); - 两个轮次同时在飞、用事件串联,主机只从环形缓冲读取被接受的 token,并用两轮之前的数据决定下一轮草稿宽度;
- 回滚时恢复被接受路径之后的全部状态——Mamba 卷积与循环状态、KV cache、甚至草稿头自己的 KV 行。
这套规则同时覆盖采样和贪心:min_p、top-k、top-p 都是"带键规则"的一部分,所以草稿开启与否,抽签结果都一致。
64 并发下的接受规则:共享轮次与行预算
TensorFold 的--parallel N让 N 路请求共享同一个前向:每路流在自己的行切片上做嵌入、注意力、采样,共享的稠密矩阵乘、路由和专家只跑一次。保持精确的关键是所有宽窗口内核都是**行不变(row-invariant)**的——一行单独算和在窗口里算,比特级相同。
Zig 引擎的共享轮次有明确的行预算(docs/recipes/nemotron-3.5.md):
- 每 lane 持 4 行,总行数下限 64、上限 128:
--parallel ≤ 16时与 64 行缓冲完全等价,行为零变化; - 32 或 64 lane 时,每条草稿流保留自己的草稿行,而不是把本轮拆碎;超过 64 行的每行多占一个 Mamba 状态槽(2 MiB/层,23 层共 47 MiB),
--parallel 64比--parallel 8大约多 2.9 GiB; - 深度规则在共享轮次下会按深度读接受率,对草稿流只授予它实际"吃得下"的行数,避免某一路的长草稿拖累整轮。
实测数据(Nemotron 3.5 Lightning,M5 Ultra 256 GB,--parallel 64 --context 32768,256 token 回复,贪心):
| 并发会话数 | 代码 tok/s | 对话 tok/s |
|---|---|---|
| 8 | 944–953 | 713–717 |
| 32 | 958–1019 | 843 |
| 64 | 968–1006 | 847–849 |
全部 832 条并发回复都与各自的单流运行逐 token 相同,而每条单流运行又等于"draft": false的输出——这是发布前用二进制校验过的,不是抽样。
Qwen3.8-27B 上则是另一组对照:48 条共享 2900 token 系统提示的对话、一次全发,16 路并发下 TensorFold 跑出161.7 tok/s、峰值 25.4 GiB;同机的 vLLM(NVFP4、MTP=3、前缀缓存、--max-num-seqs 16)为 132.1 tok/s、51.7 GiB。新提示词以每轮 1024 token 的块在其他流解码的间隙做 prefill,互不阻塞。
如何观测接受率
不用翻日志,接口把草稿统计直接吐给你(docs/api.md):
- 每条原生回复的
tensorfold运行时块里有rounds、drafted、accepted、acceptance_rate、tokens_per_round; /metrics提供 Prometheus 计数器mtp_drafted_total/mtp_accepted_total,并镜像 vLLM 的spec_decode_num_draft_tokens_total/spec_decode_num_accepted_tokens_total,现成的 vLLM 仪表盘换个前缀就能用;--dashboard打开/dashboard页面和/stats快照,每秒轮询一次。
想自己复核精确性,用仓库自带工具:tools/bench_concurrent.py --alone --serial对比"并发 vs 单流 vs 串行"三组输出(tools/bench_concurrent.py),tools/bench_openai.py跑固定基准用例并记录中位解码速率(tools/bench_openai.py)。
速查:草稿相关开关一览
| 开关 | 作用 |
|---|---|
--no-drafts | 关闭一切草稿,走精确的串行参考路径 |
"draft": false | 单请求关闭草稿(CUDA 引擎需支持串行切换) |
--drafter <repo> | Qwen3.8-27B 的 DFlash2 草稿模型目录或仓库 ID |
--drafter none | 仅禁用 DFlash2,MTP 头仍然可用(MLX) |
--mtp-drafts N | MTP 草稿深度上限(0–64 合法,家族自行约束) |
--mtp-confidence P | 链条停止的置信度阈值 |
--parallel N | 共享轮次的并发上限,决定行预算 |
小结
TensorFold 的投机解码可以概括成三句话:草稿来源可插拔(检查点内 MTP 头或独立 DFlash2 模型),接受判定在 GPU 上闭环(seed+位置+token ID 定键的采样器保证草稿输出等于串行输出),并发共享轮次靠行预算维持(64 lane 下每路各拿各的草稿行,且全部 832 条回复经过逐 token 校验)。想深入实现细节,可以从 zig/src/core/lanes/ 里的accept.zig、depth.zig、proposer.zig读起。
【免费下载链接】TensorFold
LLM Inference Engine for Metal, CUDA and Vulkan.
相关推荐
vLLM MTP 投机解码:免独立草稿模型的多 Token 预测加速实战
vLLM MTP 投机解码:免独立草稿模型的多 Token 预测加速实战 MTP(Multi Token Prediction,多 Token 预测)是 vLL
人工智能大模型模型推理服务推理引擎本地部署30 分钟调通第一台 SDR 接收机:用 SDR++ 从插上 RTL-SDR 到收到 FM 广播
30 分钟调通第一台 SDR 接收机:用 SDR++ 从插上 RTL SDR 到收到 FM 广播 SDR++ 是一款跨平台、开源、轻量化的软件定义无线电接收软件
桌面应用通信vLLM EAGLE 投机解码实战:EAGLE/EAGLE3 草稿模型配置、源码实现与接受率评测
vLLM EAGLE 投机解码实战:EAGLE/EAGLE3 草稿模型配置、源码实现与接受率评测 本文以 vLLM 的 EAGLE 系列投机解码(specula
人工智能大模型模型推理服务推理引擎本地部署
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考