<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[# SGLang 上 MTP 投机的完整调优记录：从"draft 白占 4.7GB"到单路 89 t/s，以及一个会崩服务的 mamba 坑]]></title><description><![CDATA[<p dir="auto">上一篇写了 llama.cpp + Q6_K + MTP 的成绩（工具 81.8 t/s / 代码 80.9 / 创作 52.9）。这篇是 SGLang 侧的续集：换成<strong>带 MTP 权重的 INT4 模型</strong>、把 NEXTN 投机调起来，最后不仅追平还略微超过了 llama.cpp（代码 89.3 t/s）。</p>
<p dir="auto">但过程比想象中曲折：MTP 打开后 KV 池从 28 万 token 掉到 <strong>1.4 万 token</strong>，连 32K 上下文都放不下。这篇把每个坑的定位过程和修法都写下来。</p>
<h2>1. 先给结论</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>项目</th>
<th>结果</th>
</tr>
</thead>
<tbody>
<tr>
<td>权重</td>
<td><code>RedHatAI/Qwen3.8-27B-INT4</code>（17.7 GB，<strong>自带 <code>model_mtp.safetensors</code></strong>）</td>
</tr>
<tr>
<td>引擎</td>
<td>SGLang 0.5.17 + <code>--speculative-algorithm NEXTN</code></td>
</tr>
<tr>
<td>代码生成 decode</td>
<td>41.5 t/s → <strong>89.3 t/s</strong>（+115%，接受率 0.94）</td>
</tr>
<tr>
<td>抽取原文 decode</td>
<td>40.5 t/s → <strong>86.6 t/s</strong>（+114%，接受率 0.93）</td>
</tr>
<tr>
<td>中文创作 decode</td>
<td>41.5 t/s → <strong>59.7 t/s</strong>（+44%，接受率 0.51）</td>
</tr>
<tr>
<td>双流聚合</td>
<td>82.9 t/s → <strong>170.5 t/s</strong></td>
</tr>
<tr>
<td>prefill（13.7K 提示）</td>
<td>1846 → 1775 tok/s（−4%，基本无损）</td>
</tr>
<tr>
<td>128K 上下文下的解码</td>
<td>34.4 → <strong>37.8 t/s</strong>（接受长度掉到 2.0，增益变小但仍为正）</td>
</tr>
<tr>
<td><strong>代价</strong></td>
<td>无（见第 7 节：原本以为要牺牲上下文，最后发现是 SGLang 的一个 bug，修完池子反而 ×4.7）</td>
</tr>
</tbody>
</table>
<p dir="auto">一句话：<strong>MTP 能让解码翻倍（短上下文）到 +10%（128K 长上下文），而且第 7 节那个 bug 修掉之后，连单路 128K 都能带着 MTP 一起跑。</strong></p>
<h2>2. 换权重：先验证包是不是自洽的</h2>
<p dir="auto">上一篇（llama.cpp + Q6_K 那篇）我在 hotdogs 的 AWQ 包上栽过：它的 <code>config.json</code> 用 <code>model.language_model.</code> 前缀声明"忽略 linear_attn"，但文件里真实键名是 <code>model.layers.</code>，而且 linear_attn 其实被量化了 —— 结果加载器按"未量化"去找 bf16 权重，找不到，输出满屏乱码。</p>
<p dir="auto">所以这次拿到 RedHatAI 的包先做了自洽性检查：</p>
<pre><code class="language-python"># 1) ignore 列表里的名字和文件里的真实键名对得上吗
# 2) 声明 bf16 的层，文件里真的是 bf16 吗
model.language_model.layers.0.linear_attn.in_proj_qkv.weight_packed  I32   ← 量化，符合预期
model.language_model.layers.0.linear_attn.in_proj_a.weight            BF16  ← 真 bf16，符合预期
linear_attn.in_proj_a.weight (bf16) 层数: 48    ← 48 层全对
linear_attn.in_proj_a.weight_packed 层数: 0     ← 没有残留的 packed 版本
</code></pre>
<p dir="auto"><strong>这个包是干净的</strong>：前缀和架构（<code>Qwen3_5ForConditionalGeneration</code>）一致，<code>in_proj_a/b</code>（输出维度只有 48，过不了 Marlin 的 64 整除要求）确实保留 bf16，<code>re:^mtp.*</code> 让 MTP 层也保持 bf16。直接就能跑，不用改权重。</p>
<h2>3. 下载坑：HF Xet 存储走不了镜像</h2>
<p dir="auto">用 hf-mirror 下载时直接报错：</p>
<pre><code>RuntimeError: Task error: File reconstruction error: CAS Client Error:
HTTP status client error (401 Unauthorized),
domain: https://cas-server.xethub.hf.co/v2/reconstructions/...
</code></pre>
<p dir="auto">原因：这个仓库用的是 HF 的 <strong>Xet 存储</strong>，客户端会绕过 <code>HF_ENDPOINT</code> 直接去 <code>cas-server.xethub.hf.co</code> 取数据，所以镜像是失效的、而且直连会 401。</p>
<p dir="auto">解决：<strong>关掉 Xet，走经典 HTTP 路径</strong>（这样才会真正走 hf-mirror）：</p>
<pre><code class="language-bash">export HF_ENDPOINT=https://hf-mirror.com
export HF_HUB_DISABLE_XET=1      # ← 关键
hf download RedHatAI/Qwen3.8-27B-INT4 --local-dir /mnt/sda6/download/qwen38-redhat-int4
</code></pre>
<p dir="auto">关掉之后速度稳定在 32 MB/s，19.5 GB 十分钟左右下完。</p>
<h2>4. 打开 NEXTN 投机</h2>
<pre><code class="language-bash">--speculative-algorithm NEXTN \
--speculative-draft-model-path &lt;模型目录&gt; \
--speculative-eagle-topk 1 \
--speculative-num-steps 3 \
--speculative-num-draft-tokens 4
</code></pre>
<p dir="auto"><code>--speculative-draft-model-path</code> 指模型自己的目录就行：<code>model.safetensors.index.json</code> 里同时引用了 <code>model.safetensors</code> 和 <code>model_mtp.safetensors</code>，draft 加载器会把 <code>mtp.*</code> 的键挑出来用。</p>
<p dir="auto"><strong>效果（同一个模型，只差投机开关）</strong>：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>负载</th>
<th>MTP 关</th>
<th><strong>MTP 开</strong></th>
<th>提升</th>
<th>接受率</th>
<th>接受长度</th>
</tr>
</thead>
<tbody>
<tr>
<td>代码生成</td>
<td>41.5 t/s</td>
<td><strong>89.3 t/s</strong></td>
<td>+115%</td>
<td>0.941</td>
<td>3.76</td>
</tr>
<tr>
<td>抽取原文</td>
<td>40.5 t/s</td>
<td><strong>86.6 t/s</strong></td>
<td>+114%</td>
<td>0.931</td>
<td>3.66</td>
</tr>
<tr>
<td>中文创作</td>
<td>41.5 t/s</td>
<td><strong>59.7 t/s</strong></td>
<td>+44%</td>
<td>0.513</td>
<td>2.56</td>
</tr>
<tr>
<td>双流聚合</td>
<td>82.9 t/s</td>
<td><strong>170.5 t/s</strong></td>
<td>+109%</td>
<td>—</td>
<td>—</td>
</tr>
</tbody>
</table>
<p dir="auto">对比之前在没有 MTP 权重时用 NGRAM 投机的成绩（接受率只有 0.06-0.23）：<strong>训练过的 draft head 和 n-gram 匹配完全不是一个量级</strong>，接受率差了 4-15 倍。</p>
<h2>5. 最大的坑：MTP draft 白占 4.7 GB，KV 池被压到 1.4 万</h2>
<p dir="auto">打开 MTP 后服务起来了，但一查 KV 池：</p>
<pre><code>Load weight end. type=Qwen3_5ForConditionalGeneration, mem usage=17.67 GB   ← 目标模型
Load weight end. type=Qwen3_5ForCausalLMMTP,          mem usage=5.53 GB    ← MTP draft？！
Mamba Cache is allocated. ssm_state size: 0.98GB, intermediate_ssm_state_cache size: 1.12GB
KV Cache is allocated. #tokens: 14161        ← 只有 0.44 GB！
Memory pool end. avail mem=4.17 GB           ← 还剩 4GB 没被用
</code></pre>
<p dir="auto">draft 的权重文件只有 <strong>0.85 GB</strong>，加载却占 <strong>5.53 GB</strong>。翻代码发现 <code>Qwen3_5ForCausalLMMTP.__init__</code> 会给 draft 建自己的 <code>embed_tokens</code> 和 <code>lm_head</code>（各 248320×5120×2 byte = <strong>2.5 GB</strong>），但运行时 <code>eagle_worker_v2.init_lm_head()</code> 会调用 <code>set_embed_and_head()</code>：</p>
<pre><code class="language-python">def set_embed_and_head(self, embed, head):
    del self.model.embed_tokens.weight      # 删掉自己的
    if not self.config.tie_word_embeddings:
        del self.lm_head.weight
    self.model.embed_tokens.weight = embed  # 换成目标模型的张量引用
    self.lm_head.weight = head
    torch.cuda.empty_cache()
</code></pre>
<p dir="auto"><strong>问题是：KV 池是在这之前就按"draft 还占着 5.53GB"算好尺寸的</strong>，之后 <code>empty_cache()</code> 释放出来的 5GB 就白空着了（所以才有 <code>avail mem=4.17 GB</code> 却只给 1.4 万 token 的怪现象）。</p>
<p dir="auto">修法：构造时直接把这两个权重换成 0 尺寸占位（<code>del</code> 仍能成功，之后会被目标张量替换）：</p>
<pre><code class="language-python"># Qwen3_5ForCausalLMMTP.__init__ 末尾插入
self.model.embed_tokens.weight = torch.nn.Parameter(torch.empty(0, device=dev))
if not config.tie_word_embeddings:
    self.lm_head.weight = torch.nn.Parameter(torch.empty(0, device=dev))
</code></pre>
<p dir="auto">效果立竿见影：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>指标</th>
<th>打补丁前</th>
<th>打补丁后</th>
</tr>
</thead>
<tbody>
<tr>
<td>draft 加载显存</td>
<td>5.53 GB</td>
<td><strong>0.79 GB</strong></td>
</tr>
<tr>
<td><strong>KV 池</strong></td>
<td><strong>14161 token</strong></td>
<td><strong>45423 token（3.2 倍）</strong></td>
</tr>
</tbody>
</table>
<blockquote>
<p dir="auto">提醒：<code>weight</code> 必须是 <code>nn.Parameter</code>，直接赋 <code>torch.empty(0)</code> 会报 <code>TypeError: cannot assign ... as parameter 'weight'</code>。</p>
</blockquote>
<h2>6. 并发被 mamba 槽位卡住</h2>
<p dir="auto">补丁之后最大上下文到 45K，但日志还有一条：</p>
<pre><code>max_running_requests is capped to 1 by the mamba state cache
  (max_mamba_cache_size=6, 5 state slots per request)
</code></pre>
<p dir="auto">Qwen3.8 是混合架构（48 层 GDN 线性注意力 + 16 层全注意力），<strong>投机解码下每个请求要占用 5 个 mamba 状态槽</strong>（要在验证失败时回滚）。默认/我们之前用的 6 槽只够 1 个请求，双路并发直接变成排队。</p>
<p dir="auto">解决：<strong><code>--max-mamba-cache-size 16</code> + <code>--mamba-ssm-dtype bfloat16</code></strong>（SSM 状态用 bf16 存储，槽位成本减半）→ 并发恢复成 2，而且 mamba 显存从 0.98 GB 变成 1.20 GB（16 槽 bf16），中间态缓存反而更省。</p>
<h2>7. 真正的元凶：MTP 层数识别错误，把 KV 池砍到了 1/5</h2>
<p dir="auto">修完上面的坑，KV 池到 45423，但 128K 需要 ≥131072，于是开始找显存。我先试了各种参数（mem-fraction 0.92→0.99、并发降到 1、prefill 压到 2048、hicache 缩到 4、关 CUDA graph、减投机步数），池子最多只到 <strong>60973</strong>，而且每次分配完都还空着 5-6 GB 显存 —— 说明<strong>不是显存不够，是算错了</strong>。</p>
<p dir="auto">于是往 sizing 代码里插了调试日志，一次就露馅了：</p>
<pre><code>无投机: cell_size=32768B (32.0KiB/token)  num_layers=16  eagle_draft_layers=None   → KV 池 279214
有投机: cell_size=32768B → EAGLE 缩放生效:
        eagle_draft_layers=64  num_layers=16  →  cell_size=163840B  (×5)          → KV 池 44913
</code></pre>
<p dir="auto"><code>pool_configurator.py</code> 里有一段为投机解码准备的缩放：</p>
<pre><code class="language-python"># EAGLE/STANDALONE: scale cell_size to account for draft model KV cache
self._cell_size = int(
    self._cell_size * (1 + int(eagle_draft_num_layers) / int(num_layers))
)
</code></pre>
<p dir="auto">而 <code>eagle_draft_num_layers</code> 的来源在 <code>spec_aux_hidden_state.py</code>：</p>
<pre><code class="language-python">num_nextn_predict_layers = draft_model_config.num_nextn_predict_layers
if num_nextn_predict_layers is not None:
    config.eagle_draft_num_layers = int(num_nextn_predict_layers)
else:
    config.eagle_draft_num_layers = int(max(
        draft_model_config.num_hidden_layers,      # ← 因为 draft 路径就是模型自己，这里拿到 64
        draft_model_config.num_attention_layers,
    ))
</code></pre>
<p dir="auto"><strong>Qwen3.5/3.8 的 MTP 层数写在 <code>text_config.mtp_num_hidden_layers</code> 里（=1）</strong>，不是 DeepSeek/GLM 用的 <code>num_nextn_predict_layers</code>。字段认不出来 → 走了 fallback → <code>max(num_hidden_layers, ...)</code> = <strong>64</strong>（因为 <code>--speculative-draft-model-path</code> 指向模型自己的目录，读到的是整模型的 64 层）。</p>
<p dir="auto">而真正带 KV 的层只有 16 层（48 层是 GDN 线性注意力，不占 KV），于是缩放系数变成 <code>1 + 64/16 = 5</code>，<strong>每 token 成本被高估 5 倍，KV 池被砍到 1/5</strong>。</p>
<h3>修法（一行级的补丁）</h3>
<p dir="auto"><code>fix_mtp_draft_layers.py</code>：在 fallback 之前先认 <code>mtp_num_hidden_layers</code>：</p>
<pre><code class="language-python">elif _mtp_layers is not None and int(_mtp_layers) &gt; 0:      # mtp_num_hidden_layers
    config.eagle_draft_num_layers = int(_mtp_layers)
</code></pre>
<h3>效果</h3>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>mem-fraction</th>
<th>修复前 KV 池</th>
<th><strong>修复后 KV 池</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>0.92</td>
<td>44913</td>
<td><strong>211357</strong>（4.7 倍）</td>
</tr>
<tr>
<td>0.97</td>
<td>59150</td>
<td><strong>257367</strong></td>
</tr>
</tbody>
</table>
<p dir="auto">修好之后，<strong>单路 128K + MTP 直接就跑通了</strong>：</p>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>配置</th>
<th>prompt</th>
<th>prefill</th>
<th>解码 @128K</th>
<th>接受长度</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>MTP</strong></td>
<td>126863 tok</td>
<td>111.4 s（1139 tok/s）</td>
<td><strong>37.8 t/s</strong></td>
<td>2.00</td>
</tr>
<tr>
<td>无 MTP（同 mamba 配置）</td>
<td>126863 tok</td>
<td>106.9 s（1187 tok/s）</td>
<td>34.4 t/s</td>
<td>—</td>
</tr>
</tbody>
</table>
<p dir="auto">也就是说 <strong>128K 上下文下 MTP 仍有 +10%</strong>（接受长度从短上下文的 3.76 掉到 2.0，所以增益变小，但没变负）。</p>
<blockquote>
<p dir="auto">另外补充一句：社区那个 <strong>PR #37155</strong> 是真的，它把 draft 的 vocab 层（embed/lm_head）释放时机提前到 KV 池划分之前 —— 但那解决的是另一个问题（2.4 GiB 的 vocab 层白占），和这里的 5 倍 cell_size 是两码事。两处都值得修：vocab 层那个值 2.4 GB，层数这个值<strong>池子的 4.7 倍</strong>。</p>
</blockquote>
<h3>一个还没解决的并发崩溃</h3>
<p dir="auto">修好池子后，<strong>双路 2×60K 并发</strong>（两个请求都成功完成，51.4s）之后服务会崩在同一个 mamba 槽位断言上：</p>
<pre><code>AssertionError: Can not alloc mamba cache
  mem_cache/unified_cache/components/mamba_component.py:479 _alloc_mamba_slot
  ← cache_unfinished_req ← stash_chunked_request
</code></pre>
<p dir="auto">而且这个崩溃 <strong><code>--mamba-ssm-dtype bfloat16</code> + 16 槽</strong> 才会出现；换回 <code>--max-mamba-cache-size 6</code> + 默认 float32，同样 2×64K 并发是稳的（只是投机下并发会被压成 1）。所以：</p>
<ul>
<li><strong>MTP + 单路 128K</strong>：<code>--max-mamba-cache-size 6</code>（默认 dtype），稳 <img src="https://lcz.me/assets/plugins/nodebb-plugin-emoji/emoji/android/2705.png?v=efcae6a46b1" class="not-responsive emoji emoji-android emoji--white_check_mark" style="height:23px;width:auto;vertical-align:middle" title="✅" alt="✅" /></li>
<li><strong>MTP + 双路（短/中上下文）</strong>：bf16 + 16 槽，但别跑 2×60K 这种长并发</li>
</ul>
<h2>8. 顺带抓到一个会崩服务的 bug（强烈建议避开）</h2>
<p dir="auto">为了让长上下文档多留并发槽位，我把 mamba 调到 16 槽 + bf16 之后，跑 <strong>2×64K 并发</strong>，服务<strong>整个崩了</strong>：</p>
<pre><code>AssertionError: Can not alloc mamba cache
  sglang/srt/mem_cache/unified_cache/components/mamba_component.py:479 _alloc_mamba_slot
  ← cache_unfinished_req
  ← stash_chunked_request        （chunked prefill 每分一块都要暂存 mamba 状态）
→ SIGQUIT → scheduler 异常 → 整个服务退出
</code></pre>
<p dir="auto">根因：<strong>chunked prefill 是分块的，每分一块都要暂存一次当前 mamba 状态</strong>；长提示分块多、并发两个就更容易把槽位耗光，而这里<strong>只有一句 assert，没有任何保护或降级</strong>，直接崩进程。</p>
<p dir="auto">换成验证过的 <code>--max-mamba-cache-size 6</code> 之后单路 128K 和 2×64K 都稳定（服务存活），但并发会被压成 1：2×64K 墙钟 84.4s ≈ 2×42s，是<strong>排队串行</strong>而不是并行。</p>
<h2>9. 顺便把不带 MTP 的单路 128K 验了</h2>
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>测试</th>
<th>prompt</th>
<th>prefill</th>
<th>解码 @128K</th>
</tr>
</thead>
<tbody>
<tr>
<td>单路 ~127K</td>
<td><strong>123462 tok</strong></td>
<td>103.0 s（<strong>1199 tok/s</strong>）</td>
<td>34.5 t/s</td>
</tr>
<tr>
<td>同上重放</td>
<td>123286 tok</td>
<td>102.5 s（1202 tok/s）</td>
<td>37.1 t/s</td>
</tr>
</tbody>
</table>
<p dir="auto">KV 池 289577 token，单路 128K 只占 43%。注意 fp8 KV 下长上下文的解码会从 41.5 掉到 <strong>34-37 t/s</strong>。</p>
<h2>10. 最终启动脚本（三档切换）</h2>
<blockquote>
<p dir="auto">跑 MTP 之前请先打两个补丁：<code>patch_mtp_lmhead.py</code>（draft vocab 层占位，省 4.7 GB）和<br />
<code>fix_mtp_draft_layers.py</code>（修 MTP 层数识别，KV 池 ×4.7）。两个都是幂等的。</p>
</blockquote>
<pre><code class="language-bash"># ===== 档 A：MTP + 单路 128K（修复后新增，decode 37.8 t/s @128K）=====
python -m sglang.launch_server \
  --model-path /mnt/sda6/download/qwen38-redhat-int4 \
  --language-only \
  --context-length 131072 --max-running-requests 1 \
  --mem-fraction-static 0.92 \
  --kv-cache-dtype fp8_e4m3 --page-size 1 \
  --max-mamba-cache-size 6 \
  --enable-hierarchical-cache --hicache-size 12 \
  --hicache-write-policy write_through \
  --speculative-algorithm NEXTN \
  --speculative-draft-model-path /mnt/sda6/download/qwen38-redhat-int4 \
  --speculative-eagle-topk 1 \
  --speculative-num-steps 3 --speculative-num-draft-tokens 4 \
  --trust-remote-code

# ===== 档 B：MTP 速度优先（短/中上下文，code 89 t/s、双流聚合 170 t/s）=====
python -m sglang.launch_server \
  --model-path /mnt/sda6/download/qwen38-redhat-int4 \
  --language-only \
  --context-length 32768 --max-running-requests 2 \
  --mem-fraction-static 0.92 \
  --kv-cache-dtype fp8_e4m3 --page-size 1 \
  --max-mamba-cache-size 16 --mamba-ssm-dtype bfloat16 \
  --enable-hierarchical-cache --hicache-size 12 \
  --hicache-write-policy write_through \
  --speculative-algorithm NEXTN \
  --speculative-draft-model-path /mnt/sda6/download/qwen38-redhat-int4 \
  --speculative-eagle-topk 1 \
  --speculative-num-steps 3 --speculative-num-draft-tokens 4 \
  --trust-remote-code

# ===== 档 C：长上下文/双路（无 MTP，最稳，41.5 t/s）=====
python -m sglang.launch_server \
  --model-path /mnt/sda6/download/qwen38-redhat-int4 \
  --language-only \
  --context-length 131072 --max-running-requests 2 \
  --mem-fraction-static 0.92 \
  --kv-cache-dtype fp8_e4m3 --page-size 1 \
  --max-mamba-cache-size 6 \
  --enable-hierarchical-cache --hicache-size 12 \
  --hicache-write-policy write_through \
  --trust-remote-code
</code></pre>
<h2>11. 给同是小白的提醒</h2>
<ol>
<li><strong>换带 MTP 的权重前，先确认它带 <code>model_mtp.safetensors</code></strong>，并检查 <code>model.safetensors.index.json</code> 里有没有引用它。</li>
<li><strong>Xet 存储的仓库必须 <code>HF_HUB_DISABLE_XET=1</code></strong>，否则镜像站等于没用，还会 401。</li>
<li><strong>MTP 打开后第一件事是看 KV 池</strong>（日志里的 <code>max_total_num_tokens</code>），别以为服务起来了就没事 —— 池子被挤到 1.4 万 token 时，长提示会被 400 拒掉。</li>
<li><strong>池子异常小的时候，别急着调参数，先去读 sizing 代码</strong>。我这次就是靠往 <code>_profile_available_bytes</code> / <code>_compute_cell_size</code> 里插几行日志，一眼看出 <code>cell_size</code> 被放大了 5 倍 —— 参数调到天亮也没用，因为那是<strong>算错</strong>而不是<strong>不够</strong>。</li>
<li><strong><code>max_running_requests is capped to 1</code> 这条日志一定要看</strong>，混合 mamba 模型 + 投机解码下每请求要 5 个 mamba 槽，槽不够就变排队。</li>
<li><strong><code>--max-mamba-cache-size</code> 别乱调大</strong>：它和 chunked prefill 的交互有个会崩整个服务的断言（<code>Can not alloc mamba cache</code>），调完一定要跑 2×64K 压测。</li>
<li><strong>投机参数要自己扫</strong>（和扫 n-max 一样），steps 越大代码/回声越快、但创作类接受率反而下降：1/2 → 接受率 0.97/0.95/0.74；3/4 → 0.94/0.93/0.51；5/6 → 0.91/—/0.42。而且<strong>上下文越长接受长度越低</strong>：短上下文 3.76，128K 时只有 2.0（增益从 +115% 降到 +10%）。</li>
<li><strong>贪婪解码下投机不改变结果</strong>：3 个测试题里 2 个输出和关闭 MTP 时逐字节一致，1 个措辞不同（bf16 下 batch-verify 与单 token 路径的数值抖动），不是投机算错。</li>
</ol>
<p dir="auto">感谢论坛里关于 MTP/投机解码的讨论，让我这次少走了不少弯路。</p>
]]></description><link>https://lcz.me/topic/1629</link><generator>RSS for Node</generator><lastBuildDate>Tue, 22 Sep 2026 16:12:11 GMT</lastBuildDate><atom:link href="https://lcz.me/topic/1629.rss" rel="self" type="application/rss+xml"/><pubDate>Fri, 11 Sep 2026 14:55:07 GMT</pubDate><ttl>60</ttl><item><title><![CDATA[Reply to # SGLang 上 MTP 投机的完整调优记录：从"draft 白占 4.7GB"到单路 89 t/s，以及一个会崩服务的 mamba 坑 on Sat, 12 Sep 2026 12:14:04 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/terry" aria-label="Profile: terry">@<bdi>terry</bdi></a> <a href="/post/17502">说</a>:</p>
<p dir="auto">第七节是精髓，就是不知道比起DFlash如何，DFlash2的版本，显卡运算量明显减少，除了一开始任务时，后期风扇都不转。</p>
</blockquote>
<p dir="auto">成功了，提升很大，准备发帖子</p>
]]></description><link>https://lcz.me/post/17572</link><guid isPermaLink="true">https://lcz.me/post/17572</guid><dc:creator><![CDATA[Enigma]]></dc:creator><pubDate>Sat, 12 Sep 2026 12:14:04 GMT</pubDate></item><item><title><![CDATA[Reply to # SGLang 上 MTP 投机的完整调优记录：从"draft 白占 4.7GB"到单路 89 t/s，以及一个会崩服务的 mamba 坑 on Sat, 12 Sep 2026 10:41:48 GMT]]></title><description><![CDATA[<blockquote>
<p dir="auto"><a class="plugin-mentions-user plugin-mentions-a" href="/user/terry" aria-label="Profile: terry">@<bdi>terry</bdi></a> <a href="/post/17502">说</a>:</p>
<p dir="auto">比起DFlash如何，DFlash2的版本</p>
</blockquote>
<p dir="auto">谢谢坛主鼓励，我再去调试</p>
]]></description><link>https://lcz.me/post/17550</link><guid isPermaLink="true">https://lcz.me/post/17550</guid><dc:creator><![CDATA[Enigma]]></dc:creator><pubDate>Sat, 12 Sep 2026 10:41:48 GMT</pubDate></item><item><title><![CDATA[Reply to # SGLang 上 MTP 投机的完整调优记录：从"draft 白占 4.7GB"到单路 89 t/s，以及一个会崩服务的 mamba 坑 on Sat, 12 Sep 2026 07:02:13 GMT]]></title><description><![CDATA[<p dir="auto">第七节是精髓，就是不知道比起DFlash如何，DFlash2的版本，显卡运算量明显减少，除了一开始任务时，后期风扇都不转。</p>
]]></description><link>https://lcz.me/post/17502</link><guid isPermaLink="true">https://lcz.me/post/17502</guid><dc:creator><![CDATA[terry]]></dc:creator><pubDate>Sat, 12 Sep 2026 07:02:13 GMT</pubDate></item></channel></rss>