☰
TensorFold 投机解码完全指南:MTP 草稿头、DFlash2 Drafter 与 64 并发下的接受规则
2026/10/14 16:11:39 网站建设 项目流程

【免费下载链接】TensorFold

LLM Inference Engine for Metal, CUDA and Vulkan.

项目地址:https://gitcode.com/gh_mirrors/te/TensorFold
点击查看免费下载

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 P0–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.816.6≈3.8×
对话(采样)45.916.1≈2.9×
代码(贪心)61.216.2≈3.8×
对话(贪心)56.216.3≈3.4×

接受规则:GPU 上的 accept 内核

验证在 GPU 上闭环完成,主机几乎不插手:

  1. 窗口行:一轮验证把草稿排成链或树(最多 16 行),树结构允许携带多条备选路径;
  2. accept 内核在 GPU 上把每个草稿 token 与目标的"应然选择"比对,把裁决写进一块小 arena(zig/src/core/lanes/accept.zig 中的acceptPath就是沿着"第一个 token 恰好等于目标选择的子节点"走出一条被接受路径);
  3. 两个轮次同时在飞、用事件串联,主机只从环形缓冲读取被接受的 token,并用两轮之前的数据决定下一轮草稿宽度;
  4. 回滚时恢复被接受路径之后的全部状态——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
8944–953713–717
32958–1019843
64968–1006847–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 NMTP 草稿深度上限(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.

项目地址:https://gitcode.com/gh_mirrors/te/TensorFold
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询