Prhub

#41602 [Bugfix] Fix /wake_up crash on hybrid models (Mamba/DeltaNet)

原始 PR 作者 kevglynn 合并时间 2026-07-29 08:17 文件变更 2 提交数 4 评论 5 代码增减 +66 / -3

执行摘要

修复混合模型 wake_up 时 kv_cache 列表元素 zero_ 崩溃

从关联 Issue #41564 可知,用户在使用 Qwen3.6-27B-NVFP4 等混合模型(含 Mamba/DeltaNet)时,调用 /wake_up 返回 HTTP 500,Engine 日志报 AttributeError: 'list' object has no attribute 'zero_'。根本原因是 MambaSpec 层的 _initialize_kv_cache_tensors 中,每个 layer 的状态被组织成 list[tensor],而 init_fp8_kv_scales 方法默认认为每个条目都是 torch.Tensor。

值得精读。该 PR 展示了如何识别因 kv_cache 存储结构差异导致的运行时 bug,并用最小的改动(+10/-3 源码,+56 测试)解决实际 customer 问题。测试设计模式(mock + descriptor 绑定实例方法)值得借鉴。

讨论亮点

reviewer @njhill 提议增加 CI 测试覆盖,贡献者 @kevglynn 立即添加了完整的测试类。另外 @njhill 指出 MRV2 不需要做清零操作,因为 CUDA 在返回内存前已清零。贡献者表示将本修复限定在 list 处理上,清零必要性可留作后续清理任务。

实现拆解

  1. 修改入口方法 init_fp8_kv_scalesvllm/v1/worker/gpu_model_runner.py):将原先的 for cache_tensor in kv_caches: if cache_tensor is not None: cache_tensor.zero_() 替换为对每个 cache_entry 的类型判断;若为 list,则遍历内部每个 tensor 调用 .zero_(),否则直接对 tensor 调用 .zero_()
  2. 新增单元测试类 TestInitFp8KvScalesHybridModelstests/v1/worker/test_gpu_model_runner.py):通过 mock 对象构造包含 tensor、list[tensor] 和 None 混合的 kv_caches 输入,覆盖四个场景:混合 tensor 和 list 条目、跳过 None、非量化 cache 类型不执行清零、完全混合的 None/tensor/list 顺序。所有测试在纯 Python 端运行,无需 GPU 硬件。
文件 模块 状态 重要度
vllm/v1/worker/gpu_model_runner.py 模型运行器 modified 6.2
tests/v1/worker/test_gpu_model_runner.py 模型运行器 modified 7.22

关键符号

init_fp8_kv_scales post_kv_cache_wake_up

关键源码片段

vllm/v1/worker/gpu_model_runner.py data-contract

核心修复文件:修改 init_fp8_kv_scales 方法的迭代逻辑,支持 list[tensor] 条目。

@torch.inference_mode()
def init_fp8_kv_scales(self) -> None:
    """
    Re-initialize the KV cache and FP8 scales after waking from sleep.
    """
    if not is_quantized_kv_cache(self.cache_config.cache_dtype):
        return
​
    kv_caches = getattr(self, "kv_caches", [])
    for cache_entry in kv_caches:
        if cache_entry is None:
            continue
        # Hybrid models (Mamba, DeltaNet) store per-layer state as a
        # list of tensors rather than a single tensor.
        if isinstance(cache_entry, list):
            for t in cache_entry:
                t.zero_()
        else:
            cache_entry.zero_()
    # ... scale resetting code unchanged ...

评论区精华

增加 CI 测试覆盖 测试

@njhill 请求贡献者增加 CI 测试来覆盖这个场景;贡献者随后添加了 TestInitFp8KvScalesHybridModels 类。

结论:贡献者添加了完整的单元测试,覆盖四种混合输入场景。 · 已解决

清零操作的必要性 设计

@njhill 指出 MRV2 不做清零,因为 CUDA 在返回内存前已经清零,但本 PR 保持原有行为。

结论:贡献者保持现有清零逻辑,仅修复崩溃;清零必要性可留作后续清理。 · acknowledged

风险与影响

  • 回归风险:极低。修改仅扩展了迭代分支,对纯 tensor 的原有逻辑完全兼容;新增的 list 分支仅在 MambaSpec 层存储结构下触发。
  • 兼容性:对纯 Attention 层模型(如 Gemma-4)无行为变化。
  • 性能影响:无,不影响正常推理路径;仅在 wake_up 过程中增加了一次极低开销的类型检查。
  • 用户:修复了混合模型(Mamba/DeltaNet)在启用 sleep/wake 功能时的崩溃,使得 Qwen3.6-27B-NVFP4、Nemotron-3-Nano-Omni 等变种模型可用。
  • 系统:无影响,修改仅作用于 post_kv_cache_wake_up 的 re-init 流程。
  • 团队:提供了清晰的单元测试,降低了后续重构风险。
缺少集成测试(仅单元测试)

关联 Issue

#41564 [Bug]: /wake_up fails with "'list' object has no attribute 'zero_'" on hybrid-SWA / Mamba / DeltaNet models (SM120, NVFP4) — only Gemma-4 interleaved-SWA survives

完整报告

参与讨论