Prhub

#38831 [ModelRunnerV2][Hybrid model] Support kernel block size in hybrid model

原始 PR 作者 MengqingCao 合并时间 2026-05-28 08:55 文件变更 5 提交数 5 评论 42 代码增减 +82 / -75

执行摘要

支持 ModelRunnerV2 混合模型的 kernel block size

PR body 明确指出:This pr is a follow-up pr of #35520, resolving the discussion about kernel block size support. The motivation is to support kernel block size in hybrid model, which allows more attention backends to work with hybrid model. 此前 V2 model runner 完全禁止了 hybrid/mamba 模型,通过此 PR 可解禁大部分场景。

值得精读。重点关注 init_attn_backend 的重构思路(分离 group 发现与 cg support)以及 BlockTableskernel_block_sizes 的集成方式。设计决策(generator vs list、numpy vs list 回退)的权衡过程也值得借鉴。后续 PR 将基于此继续完善混合模型支持。

讨论亮点
  • generator 耗尽问题:ivanium 指出在 init_kv_cacheflattened_attn_groups = (group for groups in attn_groups for group in groups) 是 generator,在 _reshape_kv_cache 中迭代后会耗尽,导致后续 _update_hybrid_attention_layout 收到空迭代器。MengqingCao 确认后改用 list comprehension 避免此问题。
  • 映射计算性能权衡:BlockTables 中 _map_to_kernel_blocks 改用 numpy 还是保持 list 引发讨论。MengqingCao 给出基准测试显示 numpy 在 block ≥ 32 时更快,但 njhill 优先关注简单性,最终决定保留列表推导式并承诺后续 PR 优化。
  • Mamba align cache mode 处理:gemini-code-assist 指出 Mamba 的 block 分配未正确处理 align 模式,可能引起运行时内存不足。MengqingCao 回应前缀缓存支持将在后续 PR 完成,本 PR 专注于基础支持。
  • 类型注解修正:ivanium 发现 group_map 的键类型应为 tuple[str, KVCacheSpec] 而非 tuple[tuple[str, str], KVCacheSpec],已修复。
  • 配置检查强化:ivanium 建议精准拦截 mamba_cache_mode == "align" 而不是完全禁用 hybrid model,该建议被采纳。

实现拆解

  1. 重构 init_attn_backendattn_utils.py):将原来的发现 attention group + 创建 metadata builder + 确定 cudagraph support 合并函数拆解为 init_attn_backend(仅发现 group)和新函数 get_attention_cg_support_info(构建 metadata builder 并确定 cudagraph 支持)。这简化了 kernel_block_sizes 的准备流程。
  2. 传递 kernel_block_sizesblock_table.py):在 BlockTables 构造函数中新增 kernel_block_sizes 参数,计算每个 KV cache group 的 blocks_per_kv_block = block_size // kernel_block_size。在 append_block_ids 中展开 block IDs 时使用 kernel_block_sizes 映射,确保 attention kernel 能在正确的粒度上访问块。
  3. 修正 gather 步长_gather_block_tables_kernel 中不再单独传入 max_num_blocks,而是从 stride 获取,以兼容每组的 max_num_blocks 可能不同(因对齐规则和 MambaSpec 额外块)。
  4. 配置层放宽限制vllm/config/vllm.py):将原来完全禁止 has_inner_state 模型的条件精确到仅当 mamba_cache_mode == "align"(即对齐前缀缓存模式)时才报不支持,从而允许混合模型在非 align 模式下使用 V2 运行器。
  5. 适配调用方:同步更新 model_runner.pyspeculator.py 中的调用,移除不再返回的 attn_backends,并使用新的三元素解包。init_kv_cache 等函数也改用 attn_groups 列表。
文件 模块 状态 重要度
vllm/v1/worker/gpu/attn_utils.py 注意力后端 modified 7.52
vllm/v1/worker/gpu/model_runner.py 模型运行器 modified 5.68
vllm/v1/worker/gpu/block_table.py 块表 modified 5.92
vllm/config/vllm.py 配置 modified 5.27
vllm/v1/worker/gpu/spec_decode/eagle/speculator.py 推测解码 modified 4.32

关键符号

init_attn_backend get_attention_cg_support_info _reshape_kv_cache init_kv_cache BlockTables.__init__ BlockTables.append_block_ids _gather_block_tables_kernel _get_v2_model_runner_unsupported_features

关键源码片段

vllm/v1/worker/gpu/block_table.py core-logic

新增 kernel_block_sizes 参数,计算 blocks_per_kv_block,并用于展开 block IDs。

class BlockTables:
    def __init__(
        self,
        block_sizes: list[int],
        kernel_block_sizes: list[int], # new parameter
        max_num_reqs: int,
        max_num_batched_tokens: int,
        max_num_blocks_per_group: list[int],
        device: torch.device,
        cp_size: int = 1,
        cp_rank: int = 0,
        cp_interleave: int = 1,
    ):
        self.kernel_block_sizes = kernel_block_sizes
        # kernel_block_sizes length must match block_sizes
        assert len(kernel_block_sizes) == len(block_sizes)
​
        self.num_kv_cache_groups = len(block_sizes)
        # 计算每个 kv block 包含多少个 kernel block
        self.blocks_per_kv_block = [
            bs // kbs for bs, kbs in zip(block_sizes, kernel_block_sizes)
        ]
​
        # block table 的列数改为 max_num_blocks * blocks_per_kv_block
        for i in range(self.num_kv_cache_groups):
            max_num_blocks = (
                max_num_blocks_per_group[i] * self.blocks_per_kv_block[i]
            )
            block_table = StagedWriteTensor(
                (self.max_num_reqs, max_num_blocks),
                dtype=torch.int32,
                device=device,
            )
            self.block_tables.append(block_table)
​
    def append_block_ids(self, req_index, new_block_ids, overwrite=False):
        for i in range(self.num_kv_cache_groups):
            start = self.num_blocks.np[i, req_index] if not overwrite else 0
            block_ids = new_block_ids[i]
            bpk = self.blocks_per_kv_block[i]
            if bpk > 1:
                # 展开:每个 kv_block 对应 bpk 个 kernel block
                block_ids = [
                    b * bpk + k for b in block_ids for k in range(bpk)
                ]
            self.block_tables[i].stage_write(req_index, start, block_ids)
            self.num_blocks.np[i, req_index] = start + len(block_ids)

评论区精华

attn_groups generator 导致后续迭代为空 正确性

ivanium 指出在 init_kv_cache 中 flattened_attn_groups 是 generator,_reshape_kv_cache 迭代后会耗尽,导致 _update_hybrid_attention_layout 收到空迭代器。

结论:MengqingCao 确认后改为 list comprehension,保证可多次迭代。 · 已解决

映射 block IDs 时使用 numpy 还是 list 的性能权衡 性能

njhill 质疑 numpy 转换的开销,MengqingCao 提供基准测试表明 numpy 在 block>=32 时更快,但 njhill 建议保持简单并在后续 PR 优化。

结论:最终采用简单 list 推导式,后续 PR 考虑 numpy 优化。 · 已解决

Mamba block 分配未正确处理 align cache mode 正确性

gemini-code-assist 指出 Mamba 的 max_num_blocks_per_req 计算在 align 模式下分配不足,可能导致运行时错误。MengqingCao 回应 prefix caching 支持将在后续 PR 处理。

结论:承认问题但推迟解决,本 PR 仅提供基础支持。 · acknowledged but deferred

group_map 类型注解错误 style

ivanium 指出 group_map 的键类型应为 tuple[str, KVCacheSpec] 而非 tuple[tuple[str, str], KVCacheSpec]。

结论:MengqingCao 已修正。 · 已解决

V2 model runner 是否应完全禁用 hybrid model 设计

ivanium 建议精确拦截 align cache mode 而不是完全禁止,MengqingCao 采纳并实现。

结论:仅当 mamba_cache_mode == "align" 时报不支持,其他 hybrid 模型可正常使用。 · 已解决

风险与影响

  • 回归风险(核心路径):KV cache 初始化和 block table 计算路径被重写,虽然经过了 Qwen3-Next 和 Qwen3.5 的 gsm8k 精度验证,但未覆盖所有模型和 attention backend。
  • 性能风险:最终采用了 list 推导式展开 kernel block ID,在 batch size 较小时性能可接受;但大数据量场景下可能不如 numpy 高效,已计划后续优化。
  • 兼容性风险init_attn_backend 返回值从 4 元组变为 3 元组,所有调用点已同步更新。但仍有部分功能(MTP、prefix cache align、disaggregated prefill)标记为 TODO,混合模型在这些场景下可能仍受限。
  • 缺少测试覆盖:没有新增针对 kernel_block_sizes 的单元测试,仅依赖现有 gsm8k 评估。
  • 用户:V2 model runner 现在可以运行 hybrid/mamba 模型(如 Qwen3-Next),并兼容更多 attention backend;但 align 模式下的 prefix caching 仍不可用。
  • 系统BlockTables 现在依赖 kernel_block_sizes,增加了内存布局的灵活性,但也增加了初始化时计算 blocks_per_kv_block 的开销。
  • 团队:为后续完全支持 hybrid model 搭建了桥梁,明确的 TODO 列表指导后续工作。
核心路径变更 缺少测试覆盖 待完成项多

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论