PyTorch/torch.utils.checkpoint

用反向重计算减少训练激活占用

PyTorch 的非重入 activation checkpoint 在反向传播需要中间张量时重新执行对应前向片段,以额外计算换取更低的激活存储需求。

v2.5.1内存管理核验 2026-10-09
相关概念

工程问题#

训练时大量中间激活必须活到反向传播,可能成为显存瓶颈;并非所有中间结果都需要一直保存。

实际实现#

checkpoint 用 saved_tensors_hooks 把原本要保存的中间张量替换为 holder,保留重新执行所需输入。反向解包 holder 时触发 recompute_fn,恢复所需张量;非重入实现默认支持所需张量齐备后提前停止重计算。

处理流程#

  1. 保存重放所需输入及相应执行状态
  2. 前向过程为待保存张量留下 holder,而非长期保留每个激活
  3. 反向首次请求这些张量时重新运行前向片段
  4. 拿到所需激活后继续计算梯度

源码片段#

固定版本 · 原文摘录
torch/utils/checkpoint.pyv2.5.1 · L1117–L1129
查看原文件
1117            if not frame.is_recomputed[gid]:1118                ctx = frame.input_saver.grad_fn1119                args = ctx.get_args(ctx.saved_tensors)11201121                try:1122                    with _recomputation_hook(1123                        weakref.ref(frame), gid1124                    ), torch.autograd.enable_grad():1125                        frame.recompute_fn(*args)1126                except _StopRecomputationError:1127                    pass1128                frame.is_recomputed[gid] = True1129                frame.check_recomputed_tensors_match(gid)
_checkpoint_hook.unpack_hook

首次解包时获取保存的输入,开启梯度记录并调用 recompute_fn;捕获提前停止信号后记录已完成重计算,并校验重计算张量的元数据。该校验不是一般意义上的数值完全相等证明。

torch/utils/checkpoint.pyv2.5.1 · L1500–L1515
查看原文件
1500    def recompute_fn(*inputs):1501        kwargs, *args = inputs1502        # This will be called later during recomputation. This wrapping enables1503        # the necessary global state to be captured.1504        rng_devices = []1505        if preserve_rng_state and had_device_in_fwd:1506            rng_devices = fwd_devices1507        with torch.random.fork_rng(1508            devices=rng_devices, enabled=preserve_rng_state, device_type=device_type1509        ):1510            if preserve_rng_state:1511                torch.set_rng_state(fwd_cpu_state)1512                if had_device_in_fwd:1513                    set_device_states(fwd_devices, fwd_device_states, device_type=device_type)15141515            device_autocast_ctx = torch.amp.autocast(
_checkpoint_without_reentrant_generator.recompute_fn

重计算包装器在配置允许时恢复前向的 CPU 和相关设备 RNG 状态,使 dropout 等随机运算的重放保持相容;设备状态覆盖仍有实现边界。

片段展示按需触发重计算与随机状态恢复;holder 的建立、autocast 上下文和实际函数调用也在同一源文件。

收益与取舍#

工程分析

带来的收益

  • 减少选定计算区域为反向保存的中间激活
  • 能在显存受限时扩大可训练模型或批次的选择空间

付出的代价

  • 额外前向计算与状态保存会增加训练开销;实际收益依分段和张量大小而定
  • 重放时的函数行为必须与原前向相容,副作用、可变全局状态或未覆盖的设备随机状态可能破坏等价性

可比较的选择

保存全部激活省去重计算,但活跃激活的内存峰值更高。

激活卸载到主存用传输与主存容量换显存,需要权衡带宽、同步和恢复延迟。

版本与适用范围#

对应 PyTorch v2.5.1 的 use_reentrant=False 路径;这里的 checkpoint 指训练激活重计算,不是把模型参数写入磁盘的 checkpoint,也不代表所有 torch.compile 后端的执行方式。

参考来源#

源码、官方文档与原始论文
01
pytorch · checkpoint / _checkpoint_hook / _checkpoint_without_reentrant_generator

torch/utils/checkpoint.py · checkpoint / _checkpoint_hook / _checkpoint_without_reentrant_generator

源码v2.5.1

相关实现与比较#

4 个相关案例
14 个匹配案例