Prhub

#28856 [Spec] Enable FR-Spec in EAGLE draft-extend CUDA graph by sizing logits buffer from the draft head

原始 PR 作者 hnyls2002 合并时间 2026-06-22 06:35 文件变更 2 提交数 2 评论 2 代码增减 +10 / -11

执行摘要

修复 FR-Spec 下 draft-extend CUDA graph 闪退

FR-Spec 使用缩减词表加速 speculative decoding,但 draft-extend 的 CUDA graph 缓冲区大小固定为完整词表,导致 graph 捕获失败(crash),进而回退到 eager 模式,无法获得 graph 加速。PR body 明确指出:"FR-Spec (--speculative-token-map) injects the reduced draft vocab via a late json_model_override_args, so the draft model's hf_config lacks hot_vocab_size and the draft-extend CUDA graph sized next_token_logits_buffer to the full vocab — mismatching the reduced head (graph capture crashed, so FlashInfer fell back to eager)."

该 PR 修改精炼(+10/-11),逻辑清晰,是典型的边界条件修复。值得关注的设计决策是:通过 getattr 从 worker 实例获取运行时状态,避免了修改 hf_config 或传递复杂参数,保持了接口简洁。建议阅读 eagle_draft_extend_cuda_graph_runner.py 中的回退逻辑和 eagle_worker_v2.py 中 backend 判断的简化。

讨论亮点

无实质 review 讨论,仅有一个自动化 bot 的评论总结变更内容,未提出争议或疑虑。

实现拆解

  1. eagle_draft_extend_cuda_graph_runner.py 中增加 hot_token_id 回退逻辑:在 __init__ 中通过 getattr(self.eagle_worker, "hot_token_id", None) 获取实际词表,当 hf_config 中既无 draft_vocab_size 也无 hot_vocab_size 时,使用 len(hot_token_id) 作为 vocab_size,确保 logits 缓冲区大小与缩减后的输出头匹配。
  2. eagle_worker_v2.py 中移除 FlashInfer draft-extend graph 的 FR-Spec 限制:将 FlashInferAttnBackend 加入 graph_supported_backendisinstance 检查元组中,并删除原有的 flashinfer_graph_supported 变量(包含 speculative_token_map is None 检查),使 supports_cuda_draft_extend_graph 直接使用 graph_supported_backend 判断,从而允许 FR-Spec 使用 FlashInfer draft-extend CUDA graph。
文件 模块 状态 重要度
python/sglang/srt/speculative/eagle_worker_v2.py 推测解码 modified 6.35
python/sglang/srt/speculative/eagle_draft_extend_cuda_graph_runner.py 推测解码 modified 6.28

关键源码片段

python/sglang/srt/speculative/eagle_worker_v2.py core-logic

移除了 FlashInfer draft-extend graph 的 `speculative_token_map is None` 限制,将 `FlashInferAttnBackend` 加入支持的 backend 列表,是 FR-Spec 启用 graph 的关键开关。

def init_cuda_graphs(self):
    # ... 前面的代码省略 ...
    graph_supported_backend = isinstance(
        self.draft_extend_attn_backend,
        (
            TritonAttnBackend,
            TRTLLMMLABackend,
            TRTLLMHAAttnBackend,
            TokenspeedMLABackend,
            FlashInferAttnBackend, # 新增:FR-Spec 也可以使用 FlashInfer graph
        ),
    )
    # 之前这里有 flashinfer_graph_supported 变量,限制了 speculative_token_map 为 None
    # 现在直接统一判断,不再区分普通和 FR-Spec 场景
    supports_cuda_draft_extend_graph = (
        _is_cuda or _is_musa
    ) and graph_supported_backend
    # 后续捕获 graph 的逻辑不变
python/sglang/srt/speculative/eagle_draft_extend_cuda_graph_runner.py core-logic

新增 `hot_token_id` 回退逻辑,确保 CUDA graph 的 logits 缓冲区大小与 FR-Spec 缩减后的输出头一致,修复 graph 捕获崩溃的根本原因。

def __init__(self, eagle_worker):
    # ... 前面的代码省略 ...
    # 获取 worker 上的 hot_token_id(FR-Spec 场景下存在)
    hot_token_id = getattr(self.eagle_worker, "hot_token_id", None)
​
    if hasattr(
        self.model_runner.model_config.hf_config, "draft_vocab_size"
    ): # llama_eagle
        vocab_size = self.model_runner.model_config.hf_config.draft_vocab_size
    elif hasattr(
        self.model_runner.model_config.hf_config, "hot_vocab_size"
    ): # llama_eagle3
        vocab_size = self.model_runner.model_config.hf_config.hot_vocab_size
    elif hot_token_id is not None:
        # FR-Spec: 缩减词表通过 json_model_override_args 注入,hf_config 中缺失此字段
        # 因此从 worker 的 hot_token_id 中获取实际大小
        vocab_size = len(hot_token_id)
    else:
        vocab_size = self.model_runner.model_config.vocab_size
​
    next_token_logits_buffer = torch.zeros(
        (
            self.max_bs * self.num_tokens_per_bs,
            vocab_size,
        ),
        dtype=torch.float,
    )

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

变更影响范围小(2 个文件,共 10 行新增、11 行删除),但涉及 CUDA graph 捕获和 attention backend 选择。若 hot_token_id 意外为 None 或长度错误,可能导致缓冲区越界或 graph 捕获失败,但代码中已通过 getattr 安全获取并回退到 vocab_size。移除 speculative_token_map is None 限制后,所有使用 FlashInfer 的 FR-Spec 场景都会尝试 draft-extend graph,若 attention backend 不支持,graph 捕获可能失败并回退到 eager,不会影响正确性。

对使用 FR-Spec(--speculative-token-map)且 attention backend 为 FlashInfer 的用户,draft-extend 将自动使用 CUDA graph 加速,显著提升 speculative decoding 性能。对其他场景无影响。无需用户配置变更。

核心路径变更 缺少测试覆盖

关联 Issue

未识别关联 Issue

当前没有检测到明确关联的 Issue 链接,后续同步到相关引用后会出现在这里。

完整报告

参与讨论