Prhub

#41090 [Bugfix] Fix Deepseek V4 import error due to AOT compile cache loading

原始 PR 作者 wzhao18 合并时间 2026-04-29 12:08 文件变更 1 提交数 2 评论 7 代码增减 +5 / -5

执行摘要

修复 DeepSeek V4 二次启动时因 AOT 缓存导致的 import 错误

修复 DeepSeek V4 第二次启动时的崩溃问题。当服务器第二次启动时,会直接加载 AOT 编译缓存中的模型前向函数,跳过 eager 路径,导致 vllm.model_executor.layers.mhc 未能被惰性导入,进而触发 AttributeError: '_OpNamespace' 'vllm' object has no attribute 'mhc_pre'。该错误在预热启动场景下稳定复现,严重影响 DeepSeek V4 模型的生产可用性。

建议合并。修复逻辑清晰、风险极低,且经过 zou3519(PyTorch 核心维护者)和 ProExpertProg 批准。适合需要 DeepSeek V4 生产部署的团队优先集成。

讨论亮点
  • zou3519 确认这是 torch.compile 预热启动的已知行为:依赖的自定义算子必须在模型加载前已导入,否则会报错。他指出设计一个系统让 torch.compile 在预热时自动导入依赖可能会导致“import 依赖地狱”。
  • 作者 wzhao18 参考了之前的类似修复 PR#37461(flashinfer allreduce workspace 初始化问题),说明该问题并非首次出现。
  • 整体讨论较短,没有设计争议,reviewer 均快速批准。

实现拆解

  1. DeepseekV4DecoderLayer.__init__() 方法顶部(super().__init__() 之后,config 读取之前)添加 import vllm.model_executor.layers.mhc 懒导入语句,并附带 # noqa: F401 抑制未使用的导入告警。
  2. hc_pre() 方法中移除原来位于方法体中的相同导入语句,避免重复导入。
  3. 清理 hc_pre() 中原有的注释说明(关于为何在两处导入),现已无需保留。

变更文件:vllm/model_executor/models/deepseek_v4.py,+5/-5。

文件 模块 状态 重要度
vllm/model_executor/models/deepseek_v4.py 模型层 modified 5.92

关键符号

DeepseekV4DecoderLayer.__init__ DeepseekV4DecoderLayer.hc_pre

关键源码片段

vllm/model_executor/models/deepseek_v4.py data-contract

核心修复文件,将 `vllm.model_executor.layers.mhc` 的懒导入从 `hc_pre()` 方法提升到 `__init__()` 中,确保在模型初始化时就注册 `torch.ops.vllm.mhc_pre` 和 `mhc_post` 自定义算子。

class DeepseekV4DecoderLayer(nn.Module):
    def __init__(
        self,
        vllm_config,
        prefix,
        topk_indices_buffer: torch.Tensor | None = None,
        aux_stream_dict: dict[AuxStreamType, torch.cuda.Stream] | None = None,
    ):
        super().__init__()
​
        # 将懒导入提前到 __init__ 中,确保在 eager 路径或 AOT 缓存路径下均能
        # 注册 torch.ops.vllm.mhc_pre 和 mhc_post 算子,避免 AttributeError。
        import vllm.model_executor.layers.mhc # noqa: F401
​
        config = vllm_config.model_config.hf_config
        self.hidden_size = config.hidden_size
        # ... 后续初始化代码 ...
​
    def hc_pre(self, x, hc_fn, hc_scale, hc_base):
        # 不再需要在此处导入,__init__ 中已确保算子可用
        post_mix, res_mix, layer_input = torch.ops.vllm.mhc_pre(
            residual=x,
            fn=hc_fn,
            hc_scale=hc_scale,
            hc_base=hc_base,
            rms_eps=self.rms_norm_eps,
            hc_pre_eps=self.hc_eps,
            hc_sinkhorn_eps=self.hc_eps,
            hc_post_mult_value=self.hc_post_alpha,
            sinkhorn_repeat=self.hc_sinkhorn_iters,
        )
        return layer_input, post_mix, res_mix
​
    def hc_post(self, x, residual, post, comb):
        # hc_post 依赖的算子由 hc_pre 中的导入一并注册
        return torch.ops.vllm.mhc_post(x, residual, post, comb)

评论区精华

torch.compile 热启动时自定义算子缺失是否属于 PyTorch bug 设计

reviewer ZJY0516 询问 zou3519 这是否是 torch.compile 的 bug。作者 wzhao18 过去也遇到过类似问题(PR#37461),描述 flashinfer allreduce workspace 未初始化。

结论:zou3519 确认这是“预期的”行为:热启动时 torch.compile 假设所有依赖已导入。设计自动导入系统可能引入依赖地狱,因此当前方案是合理的。 · 已解决

风险与影响

风险极低:仅将懒导入的时机从方法级提前到类初始化时,不改变任何运行时语义;在 eager 路径和 AOT 缓存路径下均能正确注册自定义算子。由于 mhc 模块的导入仅注册 torch.ops.vllm.mhc_premhc_post 两个算子,不引入额外依赖,不会增大内存开销或启动时间。

直接修复了 DeepSeek V4 在 torch.compile 热启动场景下的崩溃 bug(AttributeError: mhc_pre 缺失),恢复二次启动的可用性。对使用 AOT 编译缓存的用户是重要修复。对首次启动(eager 路径)无影响,行为与之前一致。

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论