Prhub

#51167 [Model] Voxtral Realtime: add support for `CUDAGraphMode.FULL_DECODE_ONLY`

原始 PR 作者 NickLucche 合并时间 2026-09-15 03:16 文件变更 3 提交数 1 评论 20 代码增减 +174 / -62

执行摘要

Voxtral Realtime 解码接入完整 CUDAGraph,吞吐提升 10%-24%

PR body 明确说明了动机与阻塞点:Currently decode steps are stuck on piecewise capture and pay the per-step launch overhead. The blocker is the whisper encoder's block-pooling attention builder: its build did a copy.deepcopy of the common attention metadata and allocated a fresh slot_mapping every step, so the tensor addresses baked in at capture time were dead by replay. 即:解码步长较短、per-step kernel launch 开销占比高,而完整 CG 一次性捕获整步可大幅削减 launch 次数;唯一障碍是 block-pooling builder 每次生成新张量,破坏捕获期的地址稳定性。

值得精读。该 PR 是理解 vLLM V1 CUDAGraph 与 attention backend 契约的极好样例:_cudagraph_support 能力声明、持久缓冲区 + 就地 copy_、禁用会绕过自定义 metadata 的快速路径,这三个手法组合起来解决了“捕获期地址固化”这一核心约束。关注重点:WhisperCausalAttentionWithBlockPoolingBuilder.build 的重写方式,以及 voxtral_realtime.py 中 mixed_mode() 断言的语义。

讨论亮点

该 PR 无实质技术争论(review_comments_count = 0),主要讨论集中在流程与署名:

  • MatthewBonanni 人工 review:LGTM, thanks!,直接 APPROVED,说明方案在维护者视角下风险可控。
  • JorgeGF24 的署名请求:coauthored-by: was not parsed correctly in commit. Could the merger include Co-authored-by: Jorge Gallego Feliciano <jorge.gallego@mistral.ai> in the squash message? 最终提交信息中确已包含该行。
  • mergify[bot] 多次提示冲突:This pull request has merge conflicts that must be resolved before it can be merged. Please rebase the PR,作者通过 rebase 解决后推送 cd745ed,触发 CI #88857 后合并。
  • claude[bot] 说明:fork 来源的 PR 不自动执行 Claude 审查,需维护者手动触发,因此技术审查完全依赖人工。

实现拆解

实现分为四步:

  1. 能力声明与快速路径禁用(vllm/model_executor/models/whisper_causal.py)
    - 在 WhisperCausalAttentionWithBlockPoolingBuilder 上新增 _cudagraph_support: ClassVar[AttentionCGSupport] = AttentionCGSupport.UNIFORM_SINGLE_TOKEN_DECODE,向 CUDAGraph runner 声明该 builder 只对“纯解码、每序列单 token”的均匀批次支持完整捕获,其余场景自动回退 piecewise。
    - 新增 supports_update_block_table: bool = False:disabled 掉 runner 的 update_block_table 快捷路径,因为该路径会用原始 slot_mapping / block_table 直接拼接缓存 metadata,绕过 block pooling 的扩池逻辑,导致捕获期与重放期的 metadata 不一致。

  2. 持久缓冲区 + build 重写(whisper_causal.py)
    - 新增 _maybe_init_pool_buffers:首次 build 时按输入张量的 dtype / device,结合 scheduler_config.max_num_seqs 与 max_num_batched_tokens 上限,惰性分配 _qsl_buf、_seq_buf、_slot_buf、_pool_arange 四个持久缓冲区,此后所有 capture / replay 复用同一块地址。
    - 重写 build:query_start_loc、seq_lens 缩放后通过 copy_ / mul_ 就地写入缓冲区头部切片;slot_mapping 按 block_pool_size 展开写入 _slot_buf,padding 槽位 -1 经 clamp(min=-1) 保持跳过语义;CPU 侧张量不参与捕获,直接新建缩放副本;最后用 cm.replace(...)(dataclasses.replace 语义)基于原 metadata 生成新实例并调用父类 build。

  3. 模型入口断言放宽(vllm/model_executor/models/voxtral_realtime.py)
    - VoxtralRealtimeGeneration.__init__ 中的断言从 not has_full_cudagraphs() 改为 not cudagraph_mode.mixed_mode().has_full_cudagraphs():纯 CUDAGraphMode.FULL 仍被拒绝,FULL_DECODE_ONLY 与 FULL_AND_PIECEWISE 放行,并更新报错文案提示用户改用这两种模式。

  4. 测试配套(tests/models/multimodal/generation/test_voxtral_realtime.py)
    - 抽取 _build_inputs 与 _assert_expected_text 复用逻辑;新增 test_voxtral_realtime_cudagraph,以 current_platform.is_cuda() 为 skipif 条件,参数化 FULL_DECODE_ONLY 与 FULL_AND_PIECEWISE 两种模式,enforce_eager=False、cudagraph_capture_sizes=[4],用真实音频资产端到端验证输出文本与 eager 基准一致。

文件 模块 状态 重要度
vllm/model_executor/models/whisper_causal.py 注意力层 modified 7.92
vllm/model_executor/models/voxtral_realtime.py 模型入口 modified 5.61
tests/models/multimodal/generation/test_voxtral_realtime.py 模型测试 modified 7.15

关键符号

_maybe_init_pool_buffers WhisperCausalAttentionWithBlockPoolingBuilder.build VoxtralRealtimeGeneration.__init__ test_voxtral_realtime_cudagraph

分析完成后,这里会展示 LLM 生成的相对完整源码片段和详细注释。

评论区精华

Co-authored-by 署名与 squash 信息 other

JorgeGF24 指出提交中 `coauthored-by:` 未被正确解析,请求合并时在 squash message 里补上 `Co-authored-by: Jorge Gallego Feliciano <jorge.gallego@mistral.ai>`。

结论:最终提交信息中包含该 Co-authored-by 行,署名问题解决。 · 已解决

合并冲突与 rebase other

mergify[bot] 多次提示 `This pull request has merge conflicts that must be resolved before it can be merged. Please rebase the PR`。

结论:作者 rebase 后推送最终 commit `cd745ed`,触发 CI #88857 后合并。 · 已解决

fork PR 自动化审查禁用 other

claude[bot] 说明 fork 来源的 PR 不自动执行 Claude 审查,需要维护者手动触发。

结论:人工 review 由 MatthewBonanni 完成并 APPROVED(LGTM)。 · 已解决

风险与影响

  • 共享 builder 行为变更:whisper_causal.py 的 create_whisper_attention_backend_with_block_pooling 服务所有使用 whisper 编码器的模型。build 从“每次 deepcopy 生成全新张量”改为“就地写入持久缓冲区”,若外部调用方持有旧返回 metadata 中的张量引用并期望不被改写,会观察到数据被就地更新。语义上缩放 / 展开 / clamp 结果一致,但引用语义有变化。
  • 快速路径被禁用:supports_update_block_table = False 会让非 CG 路径(eager、piecewise)也丢失该快捷路径,PR 未提供 eager / piecewise 模式的前后性能对比,存在小幅回退的可能。
  • CUDA-only 验证:测试用 skipif(not current_platform.is_cuda()) 跳过非 CUDA 平台,ROCm 等后端的行为未验证;AttentionCGSupport 声明也可能与后端能力不匹配。
  • 显存与越界:新增缓冲区按 max_num_seqs / max_num_batched_tokens 上限分配,断言防越界,但超大 max_num_batched_tokens 配置下显存占用会额外增加 max_num_batched_tokens * block_pool_size 的 slot 缓冲区。
  • 用户与服务:Voxtral Realtime 在纯解码批次下的吞吐提升 1.10x-1.24x(batch 4 时最高),cudaGraphLaunch 次数从约 12,272 降到约 208,显著降低 per-step launch 开销;prefill / 混合批次保持原 piecewise 行为不变。
  • 系统与代码:变更集中在 whisper block-pooling attention builder 与 Voxtral 模型入口,影响面限定在使用该 builder 的语音模型族;为后续其他 whisper 派生模型接入 FULL_DECODE_ONLY 提供了可复用的 capture-safe 模式。
  • 团队:无需新增配置项,用户只需在启动参数中选用 FULL_DECODE_ONLY 或 FULL_AND_PIECEWISE 即可受益。
共享 attention builder 行为变更 禁用 update_block_table 快路径 仅 CUDA 验证,ROCm 跳过 非 CG 路径性能回退待评估

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论