Prhub

#48816 Fix GPTQ quantized Qwen3.5 MTP weight loading with spec decode

原始 PR 作者 vllmellm 合并时间 2026-07-23 21:59 文件变更 1 提交数 6 评论 2 代码增减 +12 / -2

执行摘要

修复 GPTQ Qwen3.5 MTP 权重加载失败

加载 Qwen/Qwen3.5-397B-A17B-GPTQ-Int4 并用推测解码时,权重加载失败,报错 AttributeError: 'RoutedExperts' object has no attribute 'w2_weight'. Did you mean: 'w2_qweight'?。原因是 MTP 权重未量化,但权重加载机制期望每层都量化。

建议精读该 PR,了解 GPTQ 量化与推测解码 MTP 层加载的交互机制。该 PR 可作为轻量级修复的范例,但需要关注 Issue 评论中 sdougbrown 提出的更通用修复建议。

讨论亮点

该 PR 的 review 评论较少,主要由 tjtanaa 审批通过。sdougbrown 在 Issue 评论中提供了 ROCm 平台的验证结果,并指出该修复暴露了 AutoGPTQConfig.get_quant_method() 中的一个更通用的排序问题:对于 RoutedExperts,当 check_moe_marlin_supports_layer() 返回 false 时,代码会早于 get_moe_quant_method() 返回,导致 dynamic 排除模式被忽略。建议后续考虑更通用的解决方案。

实现拆解

该 PR 仅修改了 vllm/model_executor/models/qwen3_5_mtp.py 文件,在 Qwen3_5MTP.__init__ 方法中新增逻辑:

  1. 在创建 MTP 层(self.layers)之前,检查当前量化配置是否为 GPTQ(非 modelopt_fp4)。
  2. 从 HuggingFace 配置中读取 quantization_config.dynamic 字典,查找是否包含以 -: 开头且包含 mtp 的键(表示该层应排除量化)。
  3. 如果检测到排除模式,则将 vllm_config.quant_config 临时设为 None,这样后续创建的 Qwen3_5DecoderLayer 将使用非量化的参数初始化(如 w2_weight 而非 w2_qweight)。
  4. 创建完所有 MTP 层后,立即恢复 vllm_config.quant_config 为原始值,避免影响其他模块。
  5. 同时调整了 forward 方法中 self.norm 调用的缩进层级。

整体改动仅 12 行新增、2 行删除,属于轻量级修复。

文件 模块 状态 重要度
vllm/model_executor/models/qwen3_5_mtp.py 模型执行器 modified 6.23

关键符号

Qwen3_5MTP.__init__

关键源码片段

vllm/model_executor/models/qwen3_5_mtp.py core-logic

唯一修改的文件,新增 MTP 层构建前的量化配置检测与临时禁用逻辑。

# 路径 : vllm/model_executor/models/qwen3_5_mtp.py
# 该方法在 __init__ 中创建 MTP 层的 self.layers 之前执行# GPTQ: 量化检查点可能通过 quantization_config.dynamic 中的
# "-:pattern" 条目排除 MTP 层。检测到后,临时禁用量化,
# 使 MTP 层使用非量化参数(如 w2_weight 而非 w2_qweight)。
original_quant = vllm_config.quant_config
# 仅在非 modelopt_fp4 量化类型时检查(因为 modelopt_fp4 有单独的 workaround)
if quant_config and quant_config.get_name() not in ("modelopt_fp4",):
    hf_qc = getattr(model_config.hf_config, "quantization_config", None)
    if isinstance(hf_qc, dict):
        dynamic = hf_qc.get("dynamic", {})
        # 查找所有以 "-:" 开头且键中包含 "mtp" 的排除模式
        if any(k.startswith("-:") and "mtp" in k for k in dynamic):
            vllm_config.quant_config = None # 关闭量化# 创建 MTP 层列表,此时 vllm_config.quant_config 可能为 None
self.layers = torch.nn.ModuleList(
    Qwen3_5DecoderLayer(
        vllm_config,
        layer_type="full_attention",
        prefix=f"{prefix}.layers.{idx}",
    )
    for idx in range(self.num_mtp_layers)
)
# 创建完成后立即恢复原始量化配置,不影响后续模块
vllm_config.quant_config = original_quant

评论区精华

ROCm 平台验证与通用修复方向 设计

sdougbrown 在 Issue 评论中详细描述了在 AMD RDNA4 上验证该修复的过程,并指出该 PR 暴露了 AutoGPTQConfig.get_quant_method() 中的排序问题:当 check_moe_marlin_supports_layer() 返回 false 时,dynamic 排除模式可能被忽略。

结论:当前 PR 作为 Qwen 特定 workaround 通过,但需后续追求更通用的修复。 · 已解决

风险与影响

  1. 回归风险低:改动范围小(仅一个文件 14 行变更),且逻辑有明确的条件分支(仅当 GPTQ 且存在 -:.*mtp.* 动态排除时才执行)。
  2. 缺少单元测试:PR 未附带测试文件,可能遗漏对边界情况(如其他包含 mtp 的模型)的覆盖。
  3. 仅处理了 GPTQ:当前检测只对 modelopt_fp4 以外的量化类型生效;若其他量化方法也有类似 MTP 排除需求,需单独处理。
  4. 临时修改全局配置:在创建层之前修改 vllm_config.quant_config 并后续恢复,若中间抛出异常可能导致配置不一致,但当前代码异常安全(torch.nn.ModuleList 构造通常不抛异常)。

直接影响:修复了 Qwen3.5 GPTQ 量化模型在推测解码模式下 MTP 权重加载失败的问题,影响所有使用此类模型的用户。
间接影响:无,因改动量小且高度特定。
影响程度:对受影响用户而言是关键 bugfix,对系统其他部分无影响。

缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论