已合并
fix: resolve memory leak issue during recompute forward in context parallel attention #39895
fix: resolve memory leak issue during recompute forward in context parallel attention #39895
已合并
pengjingyou创建于 7月2日
1 个文件变更+6-3
Mtorch_npu/distributed/tensor/experimental/_context_parallel/_npu_attention.py+6-3
@@ -546,9 +546,12 @@ def _npu_fa_v3_handler(op_call, args, kwargs):
546 546 
547 # Push (step_caches, is_causal, merged_out, merged_lse) for backward handler.547 # Push (step_caches, is_causal, merged_out, merged_lse) for backward handler.
548 # Backward needs merged_out to compute D = sum(dout * O_merged); per-step raw output is not enough.548 # Backward needs merged_out to compute D = sum(dout * O_merged); per-step raw output is not enough.
549- _step_cache_stack.append(549+ # These forward intermediates need transformation before backward consumes them, so save them here.
550- (step_caches, is_causal, attn_output.detach(), merged_lse.detach())550+ # Skip this during recompute forward: no need to preserve them for the recompute pass.
551- )551+ if torch._C._current_graph_task_id() < 0:
552+ _step_cache_stack.append(
553+ (step_caches, is_causal, attn_output.detach(), merged_lse.detach())
554+ )
atomgit-bot
atomgit-botatomgit-bot7月2日

🟡 Medium Priority

变更行 551-554:在 _npu_fa_v3_handler 中新增了条件 if torch._C._current_graph_task_id() < 0:,使得 recompute forward 时跳过 _step_cache_stack.append()

受影响的行为/契约

  • _npu_fa_grad_v3_handler 在 backward 时出栈并使用这些缓存。

失败模式: 当同时使用梯度检查点(gradient checkpointing / recompute)和 dropout(dropout_p > 0)时:

  1. 首次 forward:_current_graph_task_id() 返回 -1 → 入栈 entry_0(含首次 forward 的 seed/offset/merged_out/merged_lse)。
  2. Recompute forward:_current_graph_task_id() 返回 >= 0跳过入栈
  3. Recompute backward:_npu_fa_grad_v3_handler 出栈 → 拿到 entry_0(首次 forward 的缓存)。

但 entry_0 中的 seed/offset 对应首次 forward 的 dropout 随机掩码,merged_out 也是首次 forward 中 dropout 后的输出。而 recompute forward 的 dropout 因 RNG 状态已推进而使用了不同的随机掩码。Backward kernel(npu_fusion_attention_grad)使用 out 参数(即 merged_out)和 seed/offset 来计算梯度,此时两者不匹配,导致 梯度计算结果错误,且该错误是静默的——不会报错,但梯度值不正确。

dropout_p == 0 时,首次 forward 与 recompute forward 的计算结果完全相同,entry_0 的缓存有效,此问题不触发。

证据链

建议:短期方案:添加 dropout_p 的运行时校验,当同时检测到 recompute(task_id >= 0)且 dropout_p > 0 时,记录 warning 或 raise,防止静默梯度错误。长期方案:重构缓存管理,使 recompute forward 的缓存能够被 recompute backward 正确消费,同时清理首次 forward 的过期缓存条目。

likedislike
552 555 
553 # Build v3 6-tuple. softmax_max/sum come from the final step; op_plugin typically only uses attn_output.556 # Build v3 6-tuple. softmax_max/sum come from the final step; op_plugin typically only uses attn_output.
554 B, N, S, D = attn_output.shape557 B, N, S, D = attn_output.shape