Prhub

#51357 Fix ROCm architecture import on non-ROCm platforms

原始 PR 作者 xwu-intel 合并时间 2026-08-07 20:32 文件变更 2 提交数 5 评论 4 代码增减 +20 / -9

执行摘要

修复非 ROCm 平台导入 rocm 模块引发 torch.cuda 初始化问题

PR body 明确列出三个目标:用 current_platform.is_rocm() 保护仅 ROCm 可用的 on_gfx1250 导入、为 AITER 后端选择缓存架构检查、以及防止 XPU 模型加载时经由 ROCm 平台模块初始化 torch.cuda。根本问题在于 vllm.platforms.rocm 模块的导入副作用,而非 on_gfx1250() 本身——XPU 用户此前加载 MXFP4 MoE 模型时会被连带初始化 CUDA 环境。

值得快速精读:一是作为“平台相关导入必须加守卫”的参考模板,二是 jikunshang 关于保持短路求值逻辑的 review 讨论很有代表性。若关注 DeepSeek-V4 在非 NVIDIA 平台的部署,本 PR 是前置条件之一。

讨论亮点

jikunshang 在 _setup_kernel 的 diff 上指出初版实现“this doesn't respect previous logic”:原代码依靠 and 短路,只有在 backend 为 AITER_MXFP4_BF16 时才会求值 on_gfx1250();初版把导入与调用外提后会在更多场景下触发 ROCm 模块导入。他建议保持原有条件求值顺序,作者随后以 “Apply suggestion from @jikunshang” 提交采纳。此外 depthfirst-app[bot] 曾标记中间版本把布尔变量误写成 is_gfx1250() 调用、会抛 TypeError,该问题在最终 commit(fix)中已修正。

实现拆解

  1. 定位根因vllm/model_executor/layers/quantization/mxfp4.py_setup_kernelget_fused_moe_quant_config,以及 vllm/model_executor/layers/fused_moe/oracle/mxfp4.pyconvert_weight_to_mxfp4_moe_kernel_format,都在函数体内无条件执行 from vllm.platforms.rocm import on_gfx1250;该导入在非 ROCm 平台会连带初始化 torch.cuda
  2. 统一守卫并缓存:三处全部改写为 is_gfx1250 = False 初始值 + if current_platform.is_rocm(): 内的延迟导入与调用,结果缓存为局部布尔变量;uses_triton_weight_format、AITER/TRITON 分支路由等后续判断统一改用缓存值,避免重复求值。
  3. 整理导入层级_use_k3_situ_aiter 中原本函数内的 from vllm.platforms import current_platform 上移为 mxfp4.py 模块级导入,供多个方法共享。
  4. 验证配套:本 PR 未新增自动化测试文件;作者通过 pre-commit 检查,并在 TP8 XPU 上手工验证 DeepSeek-V4 加载 46 个 checkpoint shards 后成功生成;已触发 Buildkite CI(#82805),并标记进入 v0.27.0 cherry picks。
文件 模块 状态 重要度
vllm/model_executor/layers/quantization/mxfp4.py 量化层 modified 6.5
vllm/model_executor/layers/fused_moe/oracle/mxfp4.py MoE 后端 modified 5.89

关键符号

_use_k3_situ_aiter Mxfp4MoEMethod._setup_kernel Mxfp4MoEMethod.get_fused_moe_quant_config convert_weight_to_mxfp4_moe_kernel_format

关键源码片段

vllm/model_executor/layers/quantization/mxfp4.py core-logic

主战场文件:`_setup_kernel` 与 `get_fused_moe_quant_config` 两处无条件导入 `on_gfx1250` 均改为 ROCm 守卫 + 缓存局部变量,`current_platform` 上移为模块级导入,是本次修复的核心。

# vllm/model_executor/layers/quantization/mxfp4.py
# 模块级新增导入,供 `_use_k3_situ_aiter`、`_setup_kernel` 等方法共享
from vllm.platforms import current_platform
​
​
# `_setup_kernel`:把加载后的权重转为后端 kernel 格式前的关键路由。
# 平台守卫:`vllm.platforms.rocm` 在导入时会连带初始化 `torch.cuda`,
# 在 XPU 等非 ROCm 平台加载 MXFP4 MoE 模型时会造成不必要的 CUDA 初始化,
# 因此只在 `is_rocm()` 为真时延迟导入,并把结果缓存为局部 bool。
is_gfx1250 = False
if current_platform.is_rocm():
    from vllm.platforms.rocm import on_gfx1250
​
    is_gfx1250 = on_gfx1250()# TRITON 后端返回的是 triton_kernels 包装张量,不支持 `.detach()`,
# 需要手动赋值参数;AITER 在 gfx1250 上同样使用 TRITON 权重格式。
uses_triton_weight_format = self.mxfp4_backend in TRITON_BACKENDS or (
    self.mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16 and is_gfx1250
)
if not uses_triton_weight_format:
    replace_parameter(layer, "w13_weight", w13)
    replace_parameter(layer, "w2_weight", w2)
    replace_parameter(layer, "w13_weight_scale", w13_scale)
    replace_parameter(layer, "w2_weight_scale", w2_scale)
else:
    # 手动赋值权重,并保存 swizzle 后的精度配置,供 `get_fused_moe_quant_config` 使用
    layer.w13_weight = w13
    layer.w2_weight = w2
    self.w13_precision_config = w13_scale
    self.w2_precision_config = w2_scale

get_fused_moe_quant_config 中采用完全相同的守卫与缓存模式:先计算 is_gfx1250,再以 self.mxfp4_backend in TRITON_BACKENDS or (self.mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16 and is_gfx1250) 决定从精度配置还是从 layer 上取 scale。

vllm/model_executor/layers/fused_moe/oracle/mxfp4.py core-logic

MoE 后端选择器的权重转换入口同样缺失平台守卫,与 `mxfp4.py` 是同一缺陷的两个面;修复后三个后端分支路由全部改用缓存的 `is_gfx1250`。

# vllm/model_executor/layers/fused_moe/oracle/mxfp4.py
def convert_weight_to_mxfp4_moe_kernel_format(
    mxfp4_backend: Mxfp4MoeBackend,
    layer: torch.nn.Module,
    w13_weight: torch.Tensor,
    w2_weight: torch.Tensor,
    w13_weight_scale: torch.Tensor,
    w2_weight_scale: torch.Tensor,
    w13_bias: torch.Tensor | None = None,
    w2_bias: torch.Tensor | None = None,
    _cache_permute_indices: dict[torch.Size, torch.Tensor] | None = None,
) -> tuple[torch.Tensor, torch.Tensor, ...]:
    """把加载后的权重转换为后端专用 kernel 格式。"""
​
    # 同一平台守卫模式:只有 ROCm 平台才导入 `on_gfx1250`,
    # 其余平台直接保持 `is_gfx1250 = False`,避免 `vllm.platforms.rocm`
    # 的导入副作用(初始化 `torch.cuda`)。
    is_gfx1250 = False
    if current_platform.is_rocm():
        from vllm.platforms.rocm import on_gfx1250
​
        is_gfx1250 = on_gfx1250()
​
    # 分支路由与改动前保持一致,仅把 `on_gfx1250()` 替换为缓存变量:
    # - DeepGEMM:直接打包 scale,返回原始权重 data
    # - AITER(非 gfx1250):DeepSeek-V4 默认路径,做 gu-interleave shuffle
    # - TRITON 或 gfx1250 AITER:走 swizzle + PrecisionConfig
    if mxfp4_backend == Mxfp4MoeBackend.DEEPGEMM_MXFP4:
        w13_weight_scale, w2_weight_scale = _pack_deepgemm_mxfp4_scales(
            w13_weight, w2_weight, w13_weight_scale, w2_weight_scale
        )
        return w13_weight.data, w2_weight.data, w13_weight_scale, w2_weight_scale, w13_bias, w2_bias
    elif mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16 and not is_gfx1250:
        # 分支体未变:aiter shuffle_weight / shuffle_scale 对权重做 gu-interleave 重排
        ...
    elif mxfp4_backend in TRITON_BACKENDS or (
        mxfp4_backend == Mxfp4MoeBackend.AITER_MXFP4_BF16 and is_gfx1250
    ):
        # 分支体未变:`_swizzle_mxfp4` 生成 FlexCtx 与 PrecisionConfig
        ...

评论区精华

平台守卫是否保持原有短路求值逻辑 设计

jikunshang 在 `_setup_kernel` 的 diff 上指出初版实现 “this doesn't respect previous logic”:原代码依赖 `and` 短路,只有 backend 为 `AITER_MXFP4_BF16` 时才会求值 `on_gfx1250()`;初版把导入与调用外提后会在更宽的条件下触发 ROCm 模块导入,不符合原语义。

结论:作者采纳建议并以 “Apply suggestion from @jikunshang” 提交;最终版用 `is_gfx1250 = False` 初始值 + `if current_platform.is_rocm():` 守卫,在保留“非 ROCm 不导入”目标的同时维持了原分支路由逻辑。jikunshang 随后 APPROVED。 · 已解决

bool 变量被误当函数调用(中间提交) 正确性

depthfirst-app[bot] 标记中间版本把 `is_gfx1250` 写成 `is_gfx1250()`,`bool` 不可调用会抛 `TypeError`,导致 `_setup_kernel` 在 AITER 后端下提前中止;并提示同文件 `get_fused_moe_quant_config` 与 `oracle/mxfp4.py` 已正确使用无括号形式。

结论:后续 commit(`fix`)去掉括号改为 `is_gfx1250`,与其余两处用法保持一致;属于中间态笔误,最终版本无此问题。 · 已解决

风险与影响

行为等价性:ROCm 平台上 is_gfx1250 与原先 on_gfx1250() 求值结果一致,AITER/TRITON 分支路由不变;非 ROCm 平台从“导入即初始化 torch.cuda”变为完全跳过,属于预期修复。回归风险较低:改动仅为导入位置与求值方式调整,但缺少自动化测试覆盖,若后续新代码在函数顶层重新引入 vllm.platforms.rocm 导入,同类问题可能复发。性能上把冷启动路径的模块导入改为缓存布尔值,只有微小正收益。改动位于模型加载核心路径(mxfp4 量化与 MoE 后端选择),但影响面被限制在两个文件内,CUDA 平台此前也会执行该导入(无表象问题),本次一并清理。

修复了 XPU 及 CPU 等非 ROCm 平台加载 MXFP4 MoE 模型(如 DeepSeek-V4)的障碍;消除了平台模块导入的隐式副作用,让平台解耦更干净,对 XPU CI 量化相关测试的稳定性有正面影响。影响范围集中在 quantization 模块,2 个文件 20 行,团队协作上体现了 Intel/XPU 与 ROCm 维护者的跨平台补丁流程。

跨平台导入副作用 平台守卫短路语义 缺少自动化测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论