技术指南

激活重新计算权衡

激活重算,也称为激活或梯度检查点,通过在前向传播中丢弃中间结果并在反向传播需要时重新计算,来节省神经网络训练中的 GPU 内存。

听听这个指南AI叙述 · ~8 min

在本页阅读时间 9 分钟
  1. 概述
  2. 主要要点
  3. 深入探讨
  4. 估算一个 GPT-3 大小层的激活内存
  5. 现实世界的实施
  6. 激活重新计算权衡的未来
  7. 付诸实践
  8. 资料来源与延伸阅读
  9. 不断探索
  10. 常见问题

概述

如果对每一层都使用,通常会额外消耗 30% 到 40% 的计算量,而选择重算哪些部分是训练大模型的关键杠杆。

主要要点

  1. 激活重算仅保存部分前向激活,在反向传播时重新计算其余部分,以额外计算换取更低的内存占用。
  2. Chen 等人在 2016 年展示,针对每 √n 层进行检查点可将激活内存降低至约 √n 量级。
  3. 在 NVIDIA 2022 年对大型 Transformer 模型的测量中,完全重算增加了 30% 到 40% 的执行时间。
  4. 对注意力操作进行选择性重算,在序列并行下将激活内存降低约五倍,并恢复约 30% 的吞吐量。
  5. 重算必须精确再现前向传播,因此必须恢复 dropout 的随机状态,且非确定性代码可能会破坏梯度。

深入探讨

Training a neural network with backpropagation has two phases. In the forward pass, the input flows through each layer and every layer produces an output, called an activation. In the backward pass, the training algorithm works from the loss back toward the input, computing a gradient for every weight. Most of those gradient calculations need the activations from the forward pass, so by default a framework such as PyTorch or JAX keeps every activation in memory until the backward pass uses it. Activation recomputation, also known as activation checkpointing, gradient checkpointing or rematerialization, changes that rule: it keeps only some activations, discards the rest, and recomputes the discarded ones from the nearest kept value when the backward pass needs them.

The reason this matters is that activation memory, unlike weight memory, grows with the size of each training batch and with sequence length. For large transformers it often dominates. Korthikanti and colleagues at NVIDIA give a formula for a single transformer layer with no model parallelism: activation memory in bytes is roughly s times b times h times (34 + 5as/h), where s is sequence length, b is microbatch size, h is hidden size and a is the number of attention heads. The 5as/h part comes from attention, which builds a score for every pair of tokens, so it grows with the square of the sequence length. For a GPT-3-sized configuration that term equals 80, larger than the 34 from everything else. Multiplied across nearly a hundred layers, the stored activations can exceed the memory of any single GPU even before the weights are counted.

The mechanism is simple to state. Pick a set of checkpoints, usually the inputs to certain layers or blocks. During the forward pass, save only those checkpoints and throw away everything computed between them. During the backward pass, when gradients reach a block, rerun that block's forward computation from its saved input to rebuild its internal activations, use them to compute gradients, and free them again before moving to the previous block. Only one block's worth of full activations needs to be in memory at a time, plus the checkpoints. The price is that most forward computation is done twice.

The idea was brought into mainstream deep learning practice by Tianqi Chen, Bing Xu, Chiyuan Zhang and Carlos Guestrin in the April 2016 paper Training Deep Nets with Sublinear Memory Cost. They showed that for a network of n layers, placing a checkpoint every square root of n layers cuts activation memory from proportional to n to proportional to the square root of n, at the cost of roughly one extra forward pass per mini-batch. They also showed a more extreme version that reduces memory to proportional to log n at the cost of order n log n extra forward computation. Their headline example reduced the memory for a 1,000-layer residual network from 48 GB to 7 GB with about 30 percent more running time. In 2019, the Checkmate paper by Paras Jain and colleagues at Berkeley, published at MLSys 2020, framed checkpoint selection as a mixed integer linear program that finds an optimal recomputation schedule for a given memory budget in under an hour with off-the-shelf solvers, and reported training with up to 5.1 times larger inputs.

For large language models, the key refinement is selective recomputation. Korthikanti and colleagues observed in May 2022 that not all activations are equally expensive to recompute. The attention operations, meaning the query-key product, the softmax, softmax dropout and the weighted sum over values, create large activations but require relatively few floating point operations per element. The large matrix multiplications in the feed-forward layers are the opposite. By recomputing only the attention pieces and storing everything else, combined with sequence parallelism, which splits certain layer operations across GPUs along the sequence dimension, they reduced activation memory by about five times and cut the time overhead of recomputation by more than 90 percent. For a single 22-billion-parameter layer, they measured full recomputation adding 39 percent execution time and the combined approach only 4 percent. End to end, training throughput rose by about 30 percent across models from 22 billion to 1 trillion parameters.

Recomputation competes with several alternatives, and real systems mix them. Doing nothing is fastest when memory allows. Shrinking the microbatch reduces activation memory linearly but hurts GPU efficiency. Offloading moves activations to CPU memory and back, trading compute for data transfer; PyTorch's selective checkpointing API and JAX's policies both include offload options. Model parallelism splits activations across GPUs at the cost of communication. Fused kernels such as FlashAttention, posted in May 2022 by Tri Dao and colleagues, never write the full attention matrix to GPU memory: they store the softmax normalization statistics and recompute attention blocks on-chip during the backward pass. The paper reports this makes memory linear in sequence length and speeds up the backward pass despite the extra arithmetic, because reading and writing GPU high-bandwidth memory was the real bottleneck.

The limitations are mostly about cost and correctness. Full recomputation adds roughly 30 to 40 percent of execution time in the NVIDIA measurements, which translates directly into training cost. Placing checkpoints poorly saves little memory: the JAX documentation notes that checkpointing the entire differentiated function, or only its last stage, saves nothing and wastes compute. Recomputation must also reproduce the forward pass exactly. Layers that use randomness, such as dropout, need the random number generator state restored, which PyTorch does by default through preserve_rng_state at some performance cost. The PyTorch documentation warns that if a checkpointed function behaves differently on the second run, for example because it reads a global variable, the result can be an error or silently incorrect gradients.

In practice, using recomputation requires little code but careful measurement. In PyTorch, wrapping each transformer block with torch.utils.checkpoint.checkpoint and passing use_reentrant=False, which the documentation recommends, is the usual starting point; selective policies can then save specific operations such as matrix multiplies. In JAX, jax.checkpoint with a policy does the same, and the documentation notes that under jax.jit the XLA compiler often makes these choices automatically. The right setting is found by profiling peak memory and step time together: the goal is the largest batch or sequence length that fits, at the lowest recomputation overhead, since every percent of overhead is paid on every training step.

04工作示例

估算一个 GPT-3 大小层的激活内存

  1. 取一个配置:序列长度 s = 2,048,微批量 b = 1,隐藏尺寸 h = 12,288,注意力头数 a = 96。

  2. 计算 sbh = 2,048 × 1 × 12,288 = 25,165,824,注意力项 5as/h = 5 × 96 × 2,048 / 12,288 = 80。

  3. 无重算时,每层内存为 sbh × (34 + 80) ≈ 2.87 十亿字节,约 2.9 GB。

  4. 选择性重算注意力时,注意力项消失:sbh × 34 ≈ 0.86 GB 每层。

  5. 完整重算时,仅保留层输入:2sbh ≈ 50 MB 每层。

  6. 将每个数字乘以 96 层,比较总量约 275 GB、82 GB 和 4.8 GB。

它显示了什么

学习者可以看到为何选择性重算是常用的折中方案:它去除约 70% 的激活内存,符合 NVIDIA 对 GPT‑3 的报告,而完整重算节省更多内存但几乎重复整个前向传播。算术可与 2022 年 NVIDIA 论文中的公式核对。

现实世界的实施

Chen 等人于 2016 年报告,重算将 ImageNet 上 1,000 层残差网络的训练内存从 48 GB 降至 7 GB,耗时增加约 30%。

NVIDIA 的研究人员使用选择性重算与序列并行,在 2,240 块 A100 GPU 上训练 530 十亿参数的 GPT‑3 风格模型,将模型 FLOPs 利用率从 42.1% 提升至 54.2%。

PyTorch 将该技术公开为 torch.utils.checkpoint,通过将诸如 Transformer 层之类的模块包裹起来,使 autograd 仅存储其输入,并在反向传播期间重新运行该模块。

JAX 提供了 jax.checkpoint,并带有诸如 dots_with_no_batch_dims_saveable 之类的命名策略,它会保留昂贵的矩阵乘法结果,并重新计算较廉价的逐元素操作。

FlashAttention (2022) 避免存储完整的注意力矩阵,并在反向传播过程中在片上重新计算它。作者报告称,这使得反向传播速度更快而非更慢,因为它减少了内存流量。

激活重新计算权衡的未来

最近的工作将重新计算视为具有并行性、卸载和内核融合的联合计划中的一项决策,而不是一种切换。 Checkmate (2019) 表明可以针对内存预算解决最佳调度问题,2022 年的 NVIDIA 工作表明,按每 FLOP 的内存选择操作可以恢复大部分损失的吞吐量。框架 API 如下:PyTorch 的文档描述了具有每次操作保存、重新计算和 CPU 卸载策略的选择性激活检查点,并表示省略 use_reentrant 参数会从版本 2.9 开始引发异常,从而将用户推向更新的不可重入实现。 JAX 记录了保存矩阵乘法或将其卸载到主机内存的命名策略。开放问题包括在训练期间适应序列长度的自动策略、与已经自行重新实现值的编译器的交互以及长上下文训练,其中注意力项随着序列长度的平方而增长,使得存储内容的选择变得更加重要。 FlashAttention 的 2022 年结果表明,当内存带宽成为瓶颈时,重新计算可以比存储更快,这表明这些决策的成本模型取决于硬件,并将随着 GPU 内存和带宽的变化而不断变化。

付诸实践

为什么这很重要

  • 成本与预算. 多年来,架构决策决定着性能和运营成本。
  • 更清晰的判决. 技术教育帮助团队选择正确的堆栈,而不仅仅是最新的堆栈。
  • 质量控制. 更好的工程选择可以减少生产中的可靠性事故。

留意

  • 优化一项基准测试可以隐藏更广泛的系统弱点。
  • 基础设施和维护成本常常被低估。
  • 随着系统变得更加复杂,安全性和可观察性差距可能会扩大。

后续步骤

  1. 在实施之前定义延迟、质量和成本目标。
  2. 在实际负载和数据条件下进行基准测试。
  3. 仪器监控错误、漂移和用户影响。
  4. 在扩展之前准备回滚和事件响应路径。

资料来源与延伸阅读

  1. arXiv (Chen, Xu, Zhang, Guestrin)以亚线性内存成本训练深度网络
  2. arXiv (NVIDIA)减少大型 Transformer 模型中的激活重计算
  3. arXiv / MLSys 2020Checkmate:通过最优张量重计算打破内存墙
  4. arXiv (Dao et al.)FlashAttention:具有 IO 感知能力的快速且内存高效的精确注意力机制
  5. PyTorch documentationtorch.utils.checkpoint
  6. JAX documentation使用 jax.checkpoint (jax.remat) 进行梯度检查点设置

不断探索

免费通讯

获取每日AI简报

每个工作日早晨提供三条经过验证的AI故事,使用简明英文撰写。永久免费,无广告。

每个工作日发送一封邮件。一键退订。我们永不出售或分享您的地址。

测试一下自己

参加激活重计算权衡测验

每个答案即时反馈,课程通过后可获得可验证ID的可分享证书。

开始测验

支持免费AI教育。AI Understanding是一家501(c)(3)非营利组织——无广告,无付费墙,永不收费。 捐款

常见问题

什么是激活重新计算权衡?

激活重计算(也称为激活检查点或梯度检查点)通过在正向传播中丢弃中间结果,并在反向传播需要时重新计算它们,从而在神经网络训练期间节省 GPU 内存。当应用于每一层时,它通常会增加 30% 到 40% 的计算开销,而选择重计算哪些部分是训练大型模型的关键杠杆。

激活重新计算会牺牲什么来节省内存?

重新计算会丢弃存储的激活并在向后传递中重新生成它们,从而花费额外的计算来减少内存使用。

为什么前向传递激活通常会被存储?

向后传递使用前向激活来计算梯度,因此默认情况下它们会保留在内存中,直到向后传递运行。

为什么应该在实际模型上测量激活检查点(activation checkpointing)的开销?

重计算会消耗额外的计算资源,但观察到的运行时间取决于所选的操作和系统。

对于具有可比激活值的理想化 N 层链,平方根检查点放置策略可以实现什么样的存储扩展?

理论上的平方根结果涉及适当链式模型中的激活检查点,而非训练内存的每一个类别。

选择性(非完整)重新计算背后的想法是什么?

选择性重新计算的目标是使用大量内存但计算量很少的操作(例如 Softmax 或 Layernorm),同时缓存昂贵的 GEMM 结果以最大程度地减少浪费的 FLOP。