Prhub

#29509 [NPU]GLM-4.7-Flash optimize with fused kernels

原始 PR 作者 Estrella-xx 合并时间 2026-06-30 19:22 文件变更 2 提交数 1 评论 4 代码增减 +37 / -15

执行摘要

NPU GLM-4.7 MLA 与 MoE 融合算子和配置优化

PR body 明确说明 'Introduce a fused Triton kernel to improve model performance',并提供了精度对比(前/后一致)和速度测试截图(显示显著加速)。

不推荐当前状态合并。需先修复 reviewer 指出的两个 NameError 问题,并补充测试覆盖 Context Parallel 和 q_lora_rank 为 None 的场景。PR 的融合算子思路正确,但实现安全性和完整度需加强。

讨论亮点

Reviewer(gemini-code-assist[bot])指出两个 高优先级问题

  1. 当 Context Parallel 启用时(dsa_use_prefill_cp 为 True),融合分支不会定义 latent_cache,后续 m.rebuild_cp_kv_cache 使用时会触发 NameError当前状态:未解决
  2. m.q_lora_rank is None 时,外部作用域的 k_pe 定义被移除,导致 m.rotary_emb 调用 k_peNameError当前状态:未解决
    PR 未包含 reviewer 建议的修复,也未合并相关修改。

实现拆解

  1. MLA 预处理路径优化 (deepseek_v2_attention_mla_npu.py): 在非 AG 非 Context Parallel 且序列长度小于 65536 的条件下,调用新引入的融合算子 fused_split_qk_norm,将原本分离的 split、q_a_layernorm、kv_a_layernorm 合并为一个核,减少内核启动开销和显存带宽占用。
  2. MoE top-k norm_type 固定 (topk.py): 将 norm_type 从动态判断 (0 if topk_config.scoring_func == 'softmax' else 1) 简化为直接固定为 1(sigmoid),简化控制流并利用固定配置的优化路径。
  3. 重构 else 分支 (deepseek_v2_attention_mla_npu.py): 重写 m.q_lora_rank is not None 分支,分离 AG 场景与非 AG 场景,在非 AG 条件下优先使用融合算子,否则 fallback 到原始 split+norm 路径。
文件 模块 状态 重要度
python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py NPU MLADE modified 6.73
python/sglang/srt/hardware_backend/npu/moe/topk.py MoE Gating modified 5.06

关键符号

forward_mla_prepare_npu fused_topk_npu fused_split_qk_norm

关键源码片段

python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py core-logic

核心变更文件:引入 fused_split_qk_norm 融合算子,重构 MLA 预处理控制流。

# python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py
# forward_mla_prepare_npu 函数片段(head 版本,省略 AG 与 CP 场景分支)
if m.q_lora_rank is not None:
    qkv_latent = get_attn_tp_context().fetch_qkv_latent()
    if not dsa_use_prefill_cp(forward_batch) and qkv_latent.shape[0] < 65536:
        # 融合算子:一次 kernel 完成 split + q_a_layernorm + kv_a_layernorm
        # 减少内存读写和 kernel launch 开销
        q, k_nope, k_pe = fused_split_qk_norm(
            qkv_latent,
            m.q_a_layernorm,
            m.kv_a_layernorm,
            m.q_lora_rank,
            m.kv_lora_rank,
            m.qk_rope_head_dim,
            eps=m.q_a_layernorm.variance_epsilon,
        )
    else:
        # 原 fallback:split + 两次 layernorm
        q, latent_cache = qkv_latent.split([m.q_lora_rank, ...], dim=-1)
        q = m.q_a_layernorm(q)
        k_nope = m.kv_a_layernorm(latent_cache[..., :m.kv_lora_rank]).unsqueeze(1)
        k_pe = latent_cache[..., m.kv_lora_rank:].unsqueeze(1)
    q_lora = q if m.use_dsa else None
    q = m.q_b_proj(q)[0].view(-1, m.num_local_heads, m.qk_head_dim)
else:
    # q_lora_rank 为 None 的分支:同样需要保证 k_pe 被定义
    q = m.q_proj(hidden_states)[0].view(-1, m.num_local_heads, m.qk_head_dim)
    latent_cache = m.kv_a_proj_with_mqa(hidden_states)[0]
    k_nope = m.kv_a_layernorm(latent_cache[..., :m.kv_lora_rank]).unsqueeze(1)
    k_pe = latent_cache[..., m.kv_lora_rank:].unsqueeze(1) # 新增,修复 NameError
python/sglang/srt/hardware_backend/npu/moe/topk.py core-logic

MoE top-k 配置简化:固定 norm_type 为 1,移除动态判断。

# python/sglang/srt/hardware_backend/npu/moe/topk.py
# fused_topk_npu 函数中的 npu_moe_gating_top_k 调用片段(head 版本)
topk_weights, topk_ids, _ = torch.ops.npu.npu_moe_gating_top_k(
    router_logits.to(torch.float32),
    k=topk_config.top_k,
    bias=(correction_bias.to(torch.float32) if correction_bias is not None else None),
    k_group=topk_config.topk_group if use_grouped_topk else 1,
    group_count=topk_config.num_expert_group if use_grouped_topk else 1,
    group_select_mode=(1 if use_grouped_topk else 0),
    renorm=0,
    # 1 for sigmoid, 0 for softmax
    norm_type=1, # 固定 1,移除动态判断(之前为 (0 if scoring_func=="softmax" else 1))
    routed_scaling_factor=(1 if renormalize else topk_config.routed_scaling_factor),
    eps=1e-20,
)

评论区精华

Context Parallel 时 fused_split_qk_norm 导致 latent_cache 未定义 正确性

Reviewer 指出当 dsa_use_prefill_cp() 为 True 时,融合路径不定义 latent_cache,后续 rebuild_cp_kv_cache 会 NameError。建议增加检查避免在 CP 场景使用融合算子。

结论:未解决;PR 未采纳任何修改。 · unresolved

q_lora_rank 为 None 时 k_pe 未定义 正确性

Reviewer 指出移除外层 k_pe 定义后,在 m.q_lora_rank is None 分支中 k_pe 缺失,导致 m.rotary_emb 调用时 NameError。建议在 else 块内部补充定义。

结论:未解决;PR 未包含修复。 · unresolved

风险与影响

  1. 回归风险(高):review 指出的两个 NameError 均属运行时崩溃,若合并将导致 Context Parallel 场景及 q_lora_rank 为 None 的模型无法推理。
  2. 性能风险(低-中):融合算子仅在序列长度 < 65536 且非 CP 时启用,其他场景保持原逻辑,无直接性能退化。
  3. 测试覆盖不足:PR 未提供针对新融合路径的单元测试或集成测试,无法确保 edge case 的可靠性。

影响范围:仅 NPU 后端 DeepSeek V2/V3/GLM4.7 系列模型。如果修复了 review 问题,预计可带来 MLA 前处理阶段的速度提升(PR 速度截图显示显著加速)。影响程度:中高——若当前形式合并,会导致特定配置下的崩溃。

缺少测试覆盖 未修复 Review 指出的崩溃问题 核心路径变更

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论