Prhub

#34936 [NPU] [FIX] Fix non-contiguous parameter issue in FIA operator

原始 PR 作者 silencejade 合并时间 2026-08-20 20:43 文件变更 1 提交数 6 评论 15 代码增减 +3 / -3

执行摘要

修复 FIA 算子非连续输入导致的 NPU 前向失败

PR body 明确指出:新版 npu_fused_infer_attention_score 算子对输入参数 k_ropek_valuev_value 新增了 contiguity 检查,而当前调用传入的是非连续张量,导致算子执行失败,并附上了失败的 CI job 链接(Ascend/sglang actions run)。这是算子版本升级带来的契约变化,必须在调用侧适配。

值得快速浏览,作为 NPU 算子升级适配的参考案例。重点关注的决策是:在调用侧通过 .contiguous() 显式满足算子新契约,并接受 tensormove 的性能代价;未来可通过在算子内部恢复 AutoContiguous 或在上游保证张量连续来消除该开销。建议补充一个非连续输入场景的单元测试,防止回归。

讨论亮点

核心讨论围绕 .contiguous() 的性能代价与必要性展开:

  • iforgetmyname 指出 .contiguous() 会引入 tensormove,造成性能退化。
  • silencejade 回应:算子旧版本内置了 AutoContiguous,版本升级后该行为被移除,必须由调用方显式处理连续性。
  • sglang-npu-bot 曾评论 k_rope.is_contiguoxus() ?(疑为拼写错误),最终该机器人多次 APPROVED。
  • 最终 iforgetmyname 也给出 APPROVED,说明性能担忧被接受为必要代价。

实现拆解

变更围绕 NPU 后端 FIA 算子调用链路展开,共 3 处修改:

  1. 定位问题:在 python/sglang/srt/hardware_backend/npu/attention/ascend_backend.pyforward_extend 方法中,k 张量经 split 得到 k_nopek_rope,此类视图通常不连续;v 直接透传也可能不连续。新版算子新增的 contiguity 检查使这些输入直接触发执行失败。

  2. 显式调用 .contiguous():在调用 torch.ops.npu.npu_fused_infer_attention_score 时,将 k_nopevk_rope 三个参数分别改为 k_nope.contiguous()v.contiguous()k_rope.contiguous()q_nopeq_rope 保持不变。这是对算子升级移除内置 AutoContiguous 行为的适配。

  3. 提交与配套:PR 共 6 个 commit,其中 5 个为 Merge branch 'main',实际逻辑变更仅 1 个 commit。未新增单元测试或文档变更。

该修复位于 attention 前向核心路径,影响所有在 Ascend NPU 上使用 FIA 算子的 extend 请求;修复方式简单直接,但 contiguous() 可能引入张量复制开销。

文件 模块 状态 重要度
python/sglang/srt/hardware_backend/npu/attention/ascend_backend.py NPU 后端 modified 5.19

关键符号

forward_extend

关键源码片段

python/sglang/srt/hardware_backend/npu/attention/ascend_backend.py core-logic

唯一变更文件,位于 NPU 后端 attention 核心路径,修复 FIA 算子非连续输入导致的执行失败。

# NPU 前向扩展阶段(forward_extend)中调用 FIA 融合注意力算子的关键片段。
# 新版算子升级后移除了内置的 AutoContiguous 行为,要求调用方显式保证
# k_nope、v、k_rope 等参数为连续内存,否则算子执行直接失败。
q_nope, q_rope = q.split([layer.v_head_dim, self.qk_rope_head_dim], dim=-1)
k_nope, k_rope = k.split([layer.v_head_dim, self.qk_rope_head_dim], dim=-1)# 对非连续输入显式调用 .contiguous(),避免因算子新增 contiguity 检查而报错
attn_output, _ = torch.ops.npu.npu_fused_infer_attention_score(
    q_nope,
    k_nope.contiguous(),
    v.contiguous(),
    query_rope=q_rope,
    key_rope=k_rope.contiguous(),
    num_heads=layer.tp_q_head_num,
    input_layout="TND",
    atten_mask=self.fia_mask,
    sparse_mode=3,
    actual_seq_lengths=self.forward_metadata.seq_lens_list_cumsum,
    actual_seq_lengths_kv=self.forward_metadata.seq_lens_list_cumsum,
    scale=layer.scaling,
    next_tokens=0,
)

评论区精华

k_rope 连续性检查的写法疑问 question

sglang-npu-bot 评论 "k_rope.is_contiguoxus() ?"(疑为 is_contiguous() 的拼写错误),对实现方式提出疑问;diff_hunk 中实际改动为调用 `.contiguous()` 而非 `is_contiguous()`。

结论:该评论未获得直接文字回复,但后续 sglang-npu-bot 对 PR 给出了 APPROVED,确认改动可接受。 · 已解决

`.contiguous()` 引入 tensormove 的性能退化担忧 性能

iforgetmyname 指出 "this will introduce tensormove causing performance degradation";silencejade 回复 "The operator previously had built‑in AutoContiguous. This behavior is removed after version upgrade; contiguous needs to be handled explicitly at caller side.",说明这是算子升级后的必要适配。

结论:性能代价被接受为必要支出,iforgetmyname 最终 APPROVED,该线程关闭。 · 已解决

风险与影响

  1. 性能退化风险.contiguous() 在输入非连续时会产生张量拷贝(tensor move),增加显存带宽开销;该路径位于 forward_extend 的每次调用中,对长序列 extend 场景可能有可见影响。
  2. 覆盖不全风险:修改只对 k_nopevk_rope 做了 contiguous()q_nopeq_rope 未处理。若未来算子版本对 query 侧也增加连续性检查,将再次出现同类失败。
  3. 测试缺失:PR 未新增针对非连续输入的单元测试,回归防护不足,后续重构可能重新引入该问题。
  4. 兼容性:依赖算子新版本行为,旧版本(内置 AutoContiguous)算子下 contiguous() 属于冗余调用,但语义安全。

该修复直接影响 Ascend NPU 后端所有依赖 npu_fused_infer_attention_score 的模型推理路径,属于阻断性 bug 修复:不修复则新版本算子下 NPU 前向直接失败。修复后 NPU 用户可恢复正常推理,但可能伴随微小性能开销。对团队而言,这是一个典型的"上游算子契约变化"适配案例,提示后续 NPU 算子升级时需要同步检查调用侧的连续性假设。

核心路径变更 缺少测试覆盖 潜在性能退化

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论