Prhub

#35341 [AMD][Fix] Qwen3.5: make empty-batch guard tuple-aware on fused AR+quant path

原始 PR 作者 bingxche 合并时间 2026-08-28 16:11 文件变更 1 提交数 6 评论 4 代码增减 +6 / -2

执行摘要

修复 Qwen3.5 AMD 融合路径空批量守卫元组崩溃

PR #24651 使 Qwen3.5 的 AMD 融合路径返回元组,而 PR #34474 添加的空批量守卫直接读取 hidden_states.shape[0],导致守卫在 attention 解包元组之前抛出 AttributeError。问题在 CUDA graph 捕获时暴露,表现为测试服务器以 code -9 退出。

值得精读。该 PR 是一个典型的数据契约变更(函数返回值从张量变为元组)引起的下游兼容修复,展示了如何通过最小改动适配上游变化。对于涉及此类融合 kernel 的开发,有参考价值。

讨论亮点

Review 评论较少,无实质性讨论。主要审核意见来自合并者 HaiShaw 和审核者 mqhc2020 的 APPROVED,以及 amd-bot 的 CI 状态提醒。

实现拆解

  1. 在 qwen3_5.py 的 GDN 层 forward 方法中,将空批量守卫的条件从 hidden_states.shape[0] > 0 改为先解包:若 hidden_states 是元组则取第一个元素,再判断其 shape[0],同时传入 linear_attn 的仍是原始 hidden_states
  2. 在 full-attention 层的 forward 方法中做同样的修改,因为该层接收的是二元组 (fp8, scale),同样需要在守卫处解包。
  3. 该实现参考了 glm4_moe.py 中的既有惯用法,采用内联解包而非辅助函数,保持 diff 最小化。
  4. 未新增测试文件,依赖已有的 test_qwen35_fp8_ar_fusion_mi35x.py 分区验证。
文件 模块 状态 重要度
python/sglang/srt/models/qwen3_5.py 模型实现 modified 6.05

关键符号

Qwen3_5DecoderLayer.forward Qwen3_5Attention.forward

关键源码片段

python/sglang/srt/models/qwen3_5.py data-contract

核心修复文件,修改两处空批量守卫以兼容元组返回值。

# python/sglang/srt/models/qwen3_5.py
# 空批量守卫需要兼容元组返回值:
# fused AR+quant 路径会返回 (fp8, scale) 或 (bf16, fp8, scale)
# 而 #34474 添加的守卫直接读取 hidden_states.shape[0],导致崩溃
hs = hidden_states[0] if isinstance(hidden_states, tuple) else hidden_states
if not forward_batch.forward_mode.is_idle() and hs.shape[0] > 0:
    # 注意:这里仍把原始 hidden_states(可能是元组)传给 attention
    hidden_states = self.linear_attn(hidden_states, forward_batch)

评论区精华

没有提炼出高价值讨论线程

当前评论区没有形成足够清晰的争议点或结论,后续有更多讨论时会体现在这里。

风险与影响

风险较低。改动集中在两个守卫点,逻辑简单且不改变数据流。潜在风险:如果 hidden_states 元组内部第一个元素不是张量(如包含 None),仍会报错,但根据现有代码路径,元组内为张量。另外,该修复仅针对元组情况,若未来路径返回其他类型,仍需扩展。

影响范围限于 Qwen3.5 模型在 AMD 环境(启用 fused AR+quant)下的推理路径。修复后,空批量守卫正确工作,避免 CUDA graph 捕获崩溃,提升该场景的稳定性。对 GPU(NV)等其他后端无影响。

核心路径变更 依赖上游 PR 缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论