Prhub

#35143 Add bit-exact class for MTP

原始 PR 作者 ispobock 合并时间 2026-08-17 19:51 文件变更 1 提交数 1 评论 2 代码增减 +79 / -1

执行摘要

为 MTP 投机解码路径新增 bit-exact 测试类并关闭 sheared bias

MTP 目前没有 bit-exact 覆盖:PR body 指出 "MTP has no bit-exact coverage today. #29792 was a wrong-slot pick in the non-speculative decode track save; the speculative verify writes its checkpoint from its own path, and nothing exercises that path, so a matching defect there reaches production unguarded." 即投机 verify 路径的 checkpoint 保存是独立缺陷面,普通 decode 路径的测试无法保护它。关联 issue 34899 的 Roadmap 也明确把 MTP 列为待覆盖项,并确立了 "Any nonzero KL is a KV/state reuse bug" 的验收契约。

值得精读。类 docstring 本身就是一份简短设计文档,展示了"用 bit-exact 测试作为正确性 orcale 暴露底层 kernel 数值不一致"的方法论:测试不是只求通过,而是把根因修复的验收条件定义为"移除 override 后测试仍通过"。建议关注两点:一是 SGLANG_OPT_USE_INKLING_SHEARED_BIAS=0 的撤销时机(issue 34899);二是后续是否将 MTP 场景扩展到 multiturn 与更多状态保存路径。

讨论亮点

本 PR 没有实质 review 线程(仅有 1 条 /rerun-test 命令与对应 CI 结果),核心设计讨论由作者在 PR body 与测试 docstring 中完成:

  • sheared bias 的数值发散:作者指出 "The sheared relative-bias path shears on max_seqlen_q, so a verify pass (a few queries) lands the same absolute (q, k) pair on a different tile than a prefill pass does, and one output element of the attention differs",并给出实测对比:默认开启时 12/16 tokens 发散、最大 |dlogprob| 8.1e-03;关闭后 0/16、精确 0.0。
  • 配置约束的取舍--speculative-num-steps 2 是 load-bearing 配置,与 checkpoint 的 MTP 头数绑定;服务配方中的 --speculative-use-rejection-sampling 被有意省略,因为与 --enable-deterministic-inference 互斥。

实现拆解

  1. 测试类入口:在 test/registered/radix_cache/unified_radix_tree/test_unified_radix_cache_kl_hybrid_bitexact.py 文件末尾追加 TestUnifiedHybridMTPBitExact(CustomTestCase),复用同文件已有的 KL_DIV_THRESHOLD = 1e-9MAX_NEW_TOKENS = 1024_base_args()kill_process_tree 等基建。
  2. 服务器启动配置setUpClass--speculative-algorithm EAGLE--enable-multi-layer-eagle 启动服务器;--speculative-num-steps 2 精确匹配 checkpoint 携带的两个 MTP 头(第三个 step 无权重,loader 拒绝启动而非运行错误校准的 draft);--speculative-eagle-topk 1--speculative-num-draft-tokens 3 固定 draft 行为;--chunked-prefill-size 16384 控制 prefill 分块。
  3. 确定性环境:通过进程级环境变量注入 SGLANG_ENABLE_UNIFIED_RADIX_TREE=1 开启统一 radix 树,SGLANG_OPT_USE_INKLING_SHEARED_BIAS=0 关闭 sheared relative-bias 路径。类 docstring 明确该 override 是 workaround 而非偏好,根因(shear 依赖 max_seqlen_q 导致 verify/prefill 落在不同 tile)跟踪在 issue 34899。
  4. 校验用例_run 统一封装 32 样本、1024 new tokens 的断言入口;test_logprobs_match 调用 assert_logprobs_match 验证 prefill 与 decode 的 logprob 位级一致,test_decode_cache_hit 调用 assert_decode_cache_hit 验证 decode 缓存命中路径一致。
  5. CI 配套register_cuda_ciest_time 从 790 上调至 1150,反映新增 server 启动与两个用例的开销,仍注册在 base-b 阶段、1-gpu-large runner。
文件 模块 状态 重要度
test/registered/radix_cache/unified_radix_tree/test_unified_radix_cache_kl_hybrid_bitexact.py 位精确测试 modified 6.45

关键符号

TestUnifiedHybridMTPBitExact.setUpClass TestUnifiedHybridMTPBitExact.tearDownClass TestUnifiedHybridMTPBitExact._run TestUnifiedHybridMTPBitExact.test_logprobs_match TestUnifiedHybridMTPBitExact.test_decode_cache_hit

关键源码片段

test/registered/radix_cache/unified_radix_tree/test_unified_radix_cache_kl_hybrid_bitexact.py test-coverage

本 PR 唯一变更文件,新增 TestUnifiedHybridMTPBitExact 测试类,以 EAGLE 投机解码模式启动 Inkling 服务器,为 MTP 的 checkpoint 保存路径建立 bit-exact 护栏;文档化 sheared bias 数值发散的量化结果与 workaround 理由。

# 关键:这是 MTP 投机解码路径的 bit-exact 测试类。
# 背景:MTP 的 checkpoint 由投机 verify 路径写入,此前无任何测试覆盖该路径,
# #29792 这类 wrong-slot bug 因而可能流入生产。本类把 prefill 与 decode 的
# logprob 一致性当作 orcale:任何非 0 KL 都视为状态复用缺陷。
class TestUnifiedHybridMTPBitExact(CustomTestCase):
    # 在 setUpClass 中启动一个专用服务器,配置是 load-bearing 的:
    # --speculative-num-steps 2 匹配该 checkpoint 的两个 MTP 头,
    # 第三个 step 没有权重,loader 会拒绝启动而非运行错误校准的 draft。
    @classmethod
    def setUpClass(cls):
        cls.model = _MODEL_PATH
        cls.base_url = DEFAULT_URL_FOR_TEST
​
        other_args = _base_args() + [
            '--speculative-algorithm', 'EAGLE',
            '--enable-multi-layer-eagle',
            '--speculative-num-steps', '2',
            '--speculative-eagle-topk', '1',
            '--speculative-num-draft-tokens', '3',
            '--chunked-prefill-size', '16384',
        ]
        if _MODEL_REVISION:
            other_args += ['--revision', _MODEL_REVISION]
​
        cls.process = popen_launch_server(
            cls.model,
            cls.base_url,
            timeout=DEFAULT_TIMEOUT_FOR_SERVER_LAUNCH,
            other_args=other_args,
            env={
                **os.environ,
                'SGLANG_ENABLE_UNIFIED_RADIX_TREE': '1',
                # 关闭 sheared relative-bias 路径:该路径按 max_seqlen_q 做 shear,
                # verify pass(多个 query)与 prefill pass 的同一 (q, k) 对会落在
                # 不同 tile 上。实测 12/16 tokens 发散(最大 |dlogprob| 8.1e-03),
                # 关闭后 0/16、精确 0.0。这是 workaround 而非偏好,
                # 根因修复跟踪在 issue 34899,达标后应移除本行。
                'SGLANG_OPT_USE_INKLING_SHEARED_BIAS': '0',
            },
        )
​
    @classmethod
    def tearDownClass(cls):
        if getattr(cls, 'process', None) is not None:
            kill_process_tree(cls.process.pid)
​
    # 两个用例共用 32 样本 / 1024 new tokens 的校验入口,
    # 仅 helper 不同:一个验证 logprob 位级一致,一个验证 decode 缓存命中路径。
    def _run(self, helper):
        helper(
            self.base_url,
            {self.model: {'kl_div': KL_DIV_THRESHOLD}},
            self.model,
            max_samples=32,
            max_new_tokens=MAX_NEW_TOKENS,
            trust_remote_code=True,
        )
​
    def test_logprobs_match(self):
        self._run(assert_logprobs_match)
​
    def test_decode_cache_hit(self):
        self._run(assert_decode_cache_hit)

评论区精华

sheared relative-bias 导致 verify/prefill 数值发散 正确性

PR body 分析:sheared bias 路径按 max_seqlen_q 做 shear,verify pass(多个 query)与 prefill pass 的同一 (q, k) 对落在不同 tile 上,一个注意力输出元素不同并沿下游传播。实测默认开启时 12/16 tokens 发散、最大 |dlogprob| 8.1e-03;关闭后 0/16、精确 0.0。

结论:以 SGLANG_OPT_USE_INKLING_SHEARED_BIAS=0 作为 workaround 达成 bit-exact;根因修复跟踪在 issue 34899,修复后应移除 override,并由本测试类证明 query-count 不变性。 · 已解决

--speculative-num-steps 必须匹配 MTP 头数 question

PR body 配置说明:checkpoint 只有两个 MTP 头,第三个 step 没有权重,loader 拒绝启动而非运行错误校准的 draft。

结论:固定 --speculative-num-steps 2,与 checkpoint 权重结构绑定,属于 load-bearing 配置。 · 已解决

rejection sampling 与确定性推理互斥 question

服务配方中的 --speculative-use-rejection-sampling 被有意省略,因为它与 --enable-deterministic-inference 互斥,无法同时启用。

结论:省略该参数以保持确定性推理,保证 bit-exact 测试前提成立。 · 已解决

风险与影响

  1. workaround 依赖SGLANG_OPT_USE_INKLING_SHEARED_BIAS=0 是绕过而非修复。一旦 issue 34899 的 shear 修复落地,必须同步移除该环境变量,否则测试将不再覆盖真实默认路径,产生虚假安全感。
  2. 覆盖边界有限:只覆盖 single-turn 的 logprob 一致与 decode cache hit;MTP 场景的 multiturn、分支切换(同文件其他类覆盖的是非 MTP 场景)以及 DSpark/DFlash 路径仍无 bit-exact 测试。
  3. CI 时长增加:est_time 从 790 增至 1150(约 45%),base-b 的 1-gpu-large 流水线被显著拉长。
  4. 外部模型依赖:测试强依赖 thinkingmachines/Inkling 的 test revision 与两个 MTP 头的权重结构,模型 revision 变化时 --speculative-num-steps 2 的合法性需要重新确认。

对用户无运行时影响(纯测试变更)。对 CI 系统,base-b 阶段新增约 6 分钟的服务器生命周期开销,est_time 调整为 1150。对团队而言,本 PR 堵住了 MTP 投机验证路径 checkpoint 保存缺陷流入生产的窗口(#29792 同类问题),并把 sheared bias 的 query 数依赖发散固化为可回归验证的显式约束;同时为 issue 34899 roadmap 中的 DSpark/DFlash 等后续覆盖项提供了可复用的测试模板。

sheared bias 依赖环境变量绕过 测试覆盖路径有限(无 multiturn) CI 时长增加约 45% 强依赖模型 revision 与 MTP 头配置

关联 Issue

#34899 [Feature] Bit-exact correctness coverage for Unified Radix Cache

完整报告

参与讨论