执行摘要
- 一句话:修复 NSA CP 和 Prefix Cache 同时开启时的精度问题
- 推荐动作:这是针对特定硬件后端(NPU)和配置组合的定向修复,逻辑清晰。建议在 NPU CI 中增加同时启用 nsa_cp 和 prefixcache 的精度测试,防止未来回归。对于 GPU 用户无需关注。
功能与动机
PR body 明确指出:'when enable both nsa cp and prefixcache, inference accuracy is abnormal.' 这是一个在 NPU 上使用 DeepSeek V2/V3 模型时遇到的精度缺陷修复。
实现拆解
- 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_tensor 和 kv_len_next_tensor 的基础上加上 forward_batch.extend_prefix_lens.squeeze(),以使 KV 长度正确反映缓存前缀的长度。
- 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(模块 注意力机制;类别 source;类型 core-logic;符号 forward_npu): 核心修复文件:修正了当 prefixcache 与 nsa_cp 同时启用时 KV 序列长度的计算,在原有 kv_len 基础上累加 extend_prefix_lens 以正确反映缓存前缀长度。
python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py(模块 注意力机制;类别 source;类型 core-logic;符号 forward_dsa_prepare_npu): 辅助修复:通过添加条件 not nsa_use_prefill_cp(forward_batch) 禁用 fused_split_qk_norm 优化路径,避免在 nsa_cp 下因融合操作与 cp 元数据冲突导致精度异常。
关键符号:forward_npu, forward_dsa_prepare_npu
关键源码片段
python/sglang/srt/hardware_backend/npu/modules/deepseek_v2_attention_mla_npu.py
辅助修复:通过添加条件 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)
评论区精华
PR 没有 review 评论,只有 maintainer 的两次 Approval。不过从实现可以推断,直接原因是在 cp 和 prefix cache 同时启用时,之前未考虑 prefix 对 KV 序列长度的影响,导致 attention 范围不正确。
风险与影响
- 风险:
- 回归风险:条件分支修改了 fused_split_qk_norm 的触发条件,当 nsa_cp 启用时强制走非 fused 路径,可能带来轻微性能开销。
- 兼容性:此修复仅针对 NPU 后端,修改集中在 NPU 专用模块,不影响 GPU/AMD 等其他后端。
- 测试覆盖:无直接测试文件变更,建议补充同时开启 nsa_cp 和 prefix cache 的精度测试用例。
- 影响:直接影响面较小,仅修复了在 NPU 上使用 DeepSeek 模型且同时开启 NSA CP 和前缀缓存时的精度问题。影响的用户群体是 SGLang 的 NPU 用户(如华为昇腾)。风险低,修复明确。
- 风险标记:NPU 专用路径, 缺少测试覆盖
关联脉络
- PR #23885 [Disagg] Finalize routed_experts_output in process_batch_result_disagg_prefill: 同为 NPU + DeepSeek 相关的精度修复,修改了相似的 attention 模块,可能存在重叠或依赖关系。
参与讨论