已开启
feat: 优化连续 SAVE 区域的输出显存 #1135
feat: 优化连续 SAVE 区域的输出显存 #1135
已开启
DavidFFFan创建于 8月9日
DavidFFFan
DavidFFFan成员
8月9日

Paired: GitHub #914 ↔ GitCode !1135

What type of PR is this?

/kind feature


What does this PR do / why do we need it:

连续配置多个 checkpoint-excluded SAVE 区域时,
每个区域默认都会缓存完整输出,导致中间输出产生额外显存占用。

本 PR 为 checkpoint_exclude_wrapper 增加 save_output 参数,
默认值为 True,保持现有行为及前向兼容性。

当相邻 SAVE 区域显式配置 save_output=False 时,
区域内部通过 saved-tensor pack 保存的数据保持不变,
但不再缓存该区域的真实输出。

重放阶段根据正向输出中的 Tensor 叶子数量构造零元素占位结果,
保持正向和重放的自定义反向节点及 saved-tensor 序列一致。

通过 invocation 标记识别同一次 checkpoint 调用产生的 SAVE 输出,
直接传给后续 SAVE 时不再挂载多余的 recompute input handle。

RECOMPUTE→SAVE 边界继续通过延迟输入句柄触发重算,
并使用可微零元素 trigger 保证占位输出不参与求导时仍能建立边界节点。

同时合并输出边界处理和 SAVE 来源标记的递归遍历,
减少 Python Host 侧的重复结构遍历。

API 文档和 activation checkpoint 使用说明已同步更新。
本 PR 共修改 11 个文件,新增 1122 行,删除 50 行。


Which issue(s) this PR fixes:

Fixes #307


Test Plan and Test result:What scenarios were tested, and what were the verification results(Function, performance, reliability, etc.):

  • MindSpore activation checkpoint UT:59 passed,1 skipped。
  • Core activation checkpoint UT:23 passed。
  • 单卡连续 SAVE 链 ST 通过。
  • MindSpore activation checkpoint 并行 ST:8 个子场景全部通过。
  • 覆盖 RECOMPUTE→SAVE、SAVE→SAVE→SAVE、多输出及嵌套输出场景。
  • 覆盖默认 save_output=True 的兼容行为和非法调用校验。
  • MindSpore 2.10.0 全局 trigger 长稳运行 50 万步,
    Device allocated 稳定为 512 B,10 万至 50 万步 RSS 仅增加 76 KiB。
  • 每次新建 trigger 的对照实验运行 25 万步,
    Device 指标一致,10 万至 25 万步 RSS 仅增加 44 KiB。
  • 未观察到 lru_cache 引入的持续 Device 或 Host 内存泄漏。

Self-checklist:

likedislike
合并受阻
DavidFFFanDavidFFFan成员
8月9日 创建了 pull request,commit a82f251f
DavidFFFanDavidFFFan成员
8月9日 关联了issue:[RFC] checkpoint exclusion 边界激活优化:优先消除 RECOMPUTE→SAVE 冗余保存
atomgit-bot
atomgit-bot
8月9日 评论:

变更摘要

此 PR 为 activation checkpoint 的 checkpoint_exclude_wrapper 新增 save_output 参数,用于控制连续 SAVE 区域是否缓存中间输出。当相邻 SAVE 区域设置 save_output=False 时,通过 deferred input handle(_RecomputedInputHandle)在 saved-tensor pack 中保存输入引用而非完整张量数据,并在重放阶段使用零元素占位符替代实际输出,从而节省显存。同时引入 invocation ID 标记机制避免同一次 checkpoint 调用产生的 SAVE 输出被重复挂载 recompute input handle,并通过 _RecomputeBoundary 可微边界节点保证 RECOMPUTE→SAVE 边界的正确触发。输出结构遍历(_finalize_save_outputs)与 SAVE 来源标记合并在一次递归中完成,减少 Python Host 侧开销。

主要改动

  • checkpoint_exclude_wrapper 新增 save_output 参数:在 activation_checkpoint.py、platform.py 及 MindSpore 实现中,为接口增加 save_output: bool = True 关键字参数,默认值保持向前兼容;当设为 False 时不再缓存该区域的真实输出。

  • 引入 _RecomputedInputHandle 延迟输入句柄机制:新增 _RecomputedInputHandle 类,在 forward 阶段通过 _pack_saved_tensor 将输入张量替换为句柄存入 saved-tensor pack,重放时由 _materialize_recompute_inputs 按路径绑定重算产生的实际张量,避免保留冗余输入存储。

  • _ExcludeCache 重构为 _ExcludeCacheEntry 结构:将原来仅缓存输出的 _CheckpointExcludeCache 改为存储 _ExcludeCacheEntry(包含 output、input_bindings、output_tensor_count),支持 elided 输出场景下重放时构造零元素占位结果。

  • _finalize_save_outputs 合并边界与来源标记遍历:新增递归函数对输出中的 Tensor 叶子统一应用 _RecomputeBoundary 边界节点和 _SAVE_OUTPUT_SOURCE_KEY 来源标记,支持 tuple、list、dict 及 namedtuple 等嵌套结构,且在同次遍历中统计 tensor_leaf_count。

  • 新增 _RecomputeBoundary 可微边界节点:继承 _Function 的自定义 autograd 节点,通过零元素 requires_grad Tensor 作为 trigger 保存在 ctx 中,保证占位输出不参与求导时仍能触发外层 checkpoint hook。

  • invocation ID 标记避免重复挂载 handle:_mark_recompute_inputs 在标记输入时跳过 _SAVE_OUTPUT_SOURCE_KEY 等于当前 invocation_id 的张量,使同次 checkpoint 调用的 SAVE 输出直接传给下游区域而不额外挂载 recompute input handle。

  • 新增 ST 与 UT 测试覆盖:新增 checkpoint_exclude_matmul.py(含 20 层 RMSNorm+MatMul+SiLU 显存对比、相邻 SAVE 链测试、Host 性能对比等场景)及 test_checkpoint_exclude_save_chain.py;UT 中新增对 handle 机制、边界节点、输入标记回滚、多输出 elided 重放、非法参数校验等 10 余个测试用例。

likedislike
不准确?
atomgit-bot
atomgit-bot
8月9日 评论:

代码审查

经过全面审查,此 diff 质量很高,仅发现一处次要问题。


审查总结

按优先级统计

优先级 数量
P0 0
P1 0
P2 0
P3 1

总体风险判断

低风险。此变更为新功能 (save_output=False 优化连续 SAVE 区域的输出显存),实现质量良好:异常路径有正确的回滚机制(finally 恢复 user data、try/except 回滚 handle),缓存和 replay 路径对称,placeholder 机制保证了重放阶段 autograd 图结构的完整性。测试覆盖充分,包含单元测试(Tensor user data handle 生命周期、边界节点、输入标记回滚、嵌套路径解析、弱引用释放验证、多输出 replay)和系统测试(显存优化量对比、Host 性能回退检测、SAVE→SAVE 链端到端验证)。代码中唯一可改进之处是 _mark_recompute_inputs 中 except BaseException 过于宽泛,属于健壮性方面的可选改进。

各文件审查确认

文件 审查结论
hyper_parallel/core/activation_checkpoint/activation_checkpoint.py 无问题(仅添加 save_output 参数并透传)
hyper_parallel/platform/mindspore/activation_checkpoint/checkpoint_exclude_wrapper.py 1 个 P3 建议(见上方)
hyper_parallel/platform/mindspore/platform.py 无问题(透传 save_output)
hyper_parallel/platform/platform.py 无问题(更新基类签名)
tests/mindspore/st/activation_checkpoint/checkpoint_exclude_matmul.py 无问题(新 ST,显存/性能验证完备)
tests/mindspore/st/activation_checkpoint/test_checkpoint_exclude_save_chain.py 无问题(SAVE 链端到端 ST)
tests/mindspore/st/activation_checkpoint/test_ckpt_activation.py 无问题(添加新测试条目)
tests/ut/core/activation_checkpoint/test_activation_checkpoint.py 无问题(mock 验证 save_output 转发)
tests/ut/platform/mindspore/activation_checkpoint/test_checkpoint_exclude_wrapper.py 无问题(全面 UT 覆盖,包括 handle 生命周期、边界、回滚、多输出)
类型 数量
🔴 阻塞 0
🟡 建议 1

💬 仅评论

likedislike
不准确?
MindSpore-BotMindSpore-Bot成员
8月9日 添加了label:stat/needs-squash
此处折叠了43条消息 查看更多
MindSpore-BotMindSpore-Bot成员
9月21日 删除了label:mindspore-cla/yes
MindSpore-BotMindSpore-Bot成员
9月21日 添加了label:mindspore-cla/yes
司小南(机器人)
司小南(机器人)成员
9月21日 评论:

检测到Pull Request代码更新,即将终止当前正在执行的门禁任务(若存在),请基于当前版本的代码重新触发。

likedislike
MindSpore-Bot
MindSpore-Bot成员
9月21日 评论:

CLA Signature Pass

DavidFFFan, thanks for your pull request. All authors of the commits have signed the CLA. 👍

likedislike
MindSpore-Bot
MindSpore-Bot成员
8 天前 评论:

PR Merge Reminder from Scavenger:
This PR has been inactive for 42 days (as no new commits, comments, configurations) and will be closed as it becomes obsolete after 30 days of continued inactivity.
Please track the PR merging process in time, and respond according to the relevant prompts given by the robot to speed up the PR merging.
该PR已经闲置42天(因没有新的提交、评论、配置)且将因继续闲置30天后变得过时而被关闭。
请及时跟踪PR的合入流程并根据机器人给出的提示做出相应的响应以加速PR的合入。

likedislike