Prhub

#23268 【NPU】【bugfix】accuracy fix when enable both nsa cp and prefixcache

原始 PR 作者 cen121212 合并时间 2026-04-28 09:08 文件变更 2 提交数 4 评论 2 代码增减 +21 / -5

执行摘要

修复 NSA CP 和 Prefix Cache 同时开启时的精度问题

PR body 明确指出:'when enable both nsa cp and prefixcache, inference accuracy is abnormal.' 这是一个在 NPU 上使用 DeepSeek V2/V3 模型时遇到的精度缺陷修复。

这是针对特定硬件后端(NPU)和配置组合的定向修复,逻辑清晰。建议在 NPU CI 中增加同时启用 nsa_cp 和 prefixcache 的精度测试,防止未来回归。对于 GPU 用户无需关注。

讨论亮点

PR 没有 review 评论,只有 maintainer 的两次 Approval。不过从实现可以推断,直接原因是在 cp 和 prefix cache 同时启用时,之前未考虑 prefix 对 KV 序列长度的影响,导致 attention 范围不正确。

实现拆解

  1. python/sglang/srt/layers/attention/nsa/nsa_indexer.py:在 Prefill 且启用 nsa_cp 的分支中,修正 actual_seq_lengths_kv 的计算。当存在前缀缓存时(即 sum(forward_batch.extend_prefix_lens_cpu) > 0),需要在 kv_len_prev_tensorkv_len_next_tensor 的基础上加上 forward_batch.extend_prefix_lens.squeeze(),以使 KV 长度正确反映缓存前缀的长度。
  2. python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py:在非 Scatter 模式的 MLA 预处理中,为 fused_split_qk_norm 调用增加条件 not nsa_use_prefill_cp(forward_batch)。当启用 nsa_cp 时,跳过 fused 的 Q/K 拆分和 LayerNorm 操作,回退到非 fused 的 split 加逐层 norm 路径,避免因融合操作与 cp 元数据不兼容导致的精度问题。
文件 模块 状态 重要度
python/sglang/srt/layers/attention/nsa/nsa_indexer.py 注意力机制 modified 6.46
python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py 注意力机制 modified 5.47

关键符号

forward_npu forward_dsa_prepare_npu

关键源码片段

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

辅助修复:通过添加条件 `not nsa_use_prefill_cp(forward_batch)` 禁用 fused_split_qk_norm 优化路径,避免在 nsa_cp 下因融合操作与 cp 元数据冲突导致精度异常。

# python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py
# 跳过 fused_split_qk_norm 的条件:当开启 NSA CP 时,该融合操作与 cp 元数据不兼容
# 原条件只检查 batch 大小,现在额外检查是否使用 prefill cp
if fused_qkv_a_proj_out.shape[0] < 65535 and not nsa_use_prefill_cp(
    forward_batch
):
    # nsa_cp 未启用时走融合优化路径
    q_lora, k_nope, k_pe = fused_split_qk_norm(
        fused_qkv_a_proj_out,
        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:
    # nsa_cp 启用或 batch 太大时走标准的 split + 逐层 norm 路径
    q, latent_cache = fused_qkv_a_proj_out.split(
        [m.q_lora_rank, m.kv_lora_rank + m.qk_rope_head_dim], dim=-1
    )
    q = m.q_a_layernorm(q)
    q_lora = q.clone()
    k_nope, k_pe = latent_cache.unsqueeze(1).split(
        [m.kv_lora_rank, m.qk_rope_head_dim], dim=-1
    )
    k_nope = m.kv_a_layernorm(k_nope)

评论区精华

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

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

风险与影响

  1. 回归风险:条件分支修改了 fused_split_qk_norm 的触发条件,当 nsa_cp 启用时强制走非 fused 路径,可能带来轻微性能开销。
  2. 兼容性:此修复仅针对 NPU 后端,修改集中在 NPU 专用模块,不影响 GPU/AMD 等其他后端。
  3. 测试覆盖:无直接测试文件变更,建议补充同时开启 nsa_cp 和 prefix cache 的精度测试用例。

直接影响面较小,仅修复了在 NPU 上使用 DeepSeek 模型且同时开启 NSA CP 和前缀缓存时的精度问题。影响的用户群体是 SGLang 的 NPU 用户(如华为昇腾)。风险低,修复明确。

NPU 专用路径 缺少测试覆盖

关联 Issue

未识别关联 Issue

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

完整报告

参与讨论