AI Knowledge Tree

Gradient checkpointing

Trade compute for memory by recomputing activations during the backward pass instead of storing them.

⏱ 22 minPrerequisites:Backpropagation

Training a deep network normally stores every intermediate activation during the forward pass, then reads them during backward to compute gradients. This memory grows linearly with depth and quickly becomes the limiting factor for large models. Gradient checkpointing drops most activations and recomputes them during the backward pass, trading extra compute for much less memory[1].

The memory problem

For a network with LL layers and activation size AA per layer, the backward pass needs all LL stored activations, costing O(LA)O(LA) memory.

For a 24-layer Transformer with 4096 hidden dim and batch 32 with sequence length 2048, activations alone consume tens of GB. Doubling the sequence length doubles activation memory; tripling batch size triples it.

This is often the bottleneck before parameter or gradient memory becomes the issue.

The basic idea

Conceptually:

  1. Forward: compute and store only checkpoint activations (every L\sqrt{L} layers, say).
  2. Backward: when you need a non-checkpointed activation, recompute it by running forward from the nearest earlier checkpoint.

This trades:

  • Memory: O(L A)O(\sqrt{L}\, A) instead of O(LA)O(L A) for LL layers with L\sqrt{L} checkpoints.
  • Compute: extra forward passes during backward, increasing training time by ~33%.

For most use cases, the memory savings are worth the time cost.

Why L\sqrt{L} checkpoints

If you keep KK checkpoints, memory is O(K+L/K)O(K + L/K) for the checkpoints plus the activations being recomputed for backward. The minimum is at K≈LK \approx \sqrt{L}, giving memory O(L)O(\sqrt{L})[1].

For a 100-layer network, this means keeping about 10 checkpoints and recomputing in 10-layer segments. Memory drops 10x; compute grows by the recomputation overhead.

In practice

Most frameworks have a built-in:

# PyTorch
from torch.utils.checkpoint import checkpoint

def transformer_block(x):
    return checkpoint(my_block, x)

The framework remembers which activations are needed, calls forward again at backward time, and stitches the resulting gradients into the overall backward pass.

Decisions:

  • Which sublayers to checkpoint: typically per-Transformer-block, not per-individual-op. Per-block is the right granularity.
  • Which layers to not checkpoint: usually the first and last layers, which the optimizer needs frequent access to.

Activation checkpointing in distributed training

Combined with data parallelism (DDP) and model parallelism (FSDP), gradient checkpointing is essential for training models too large to fit any other way.

For GPT-3-scale (175B parameters), checkpointing every Transformer block is non-negotiable: without it, activation memory exceeds any single GPU.

Selective recomputation

Modern recipes (selective gradient checkpointing) recompute only the expensive-to-store, cheap-to-recompute ops:

  • LayerNorm, dropout, GELU: cheap to recompute, modest memory savings.
  • Attention: expensive to recompute (quadratic), large memory savings.
  • FFN: medium on both axes.

By picking the right ops, you can save more memory per FLOP than uniform checkpointing.

Megatron-LM and DeepSpeed support this with config switches.

Reversible architectures

A different memory trick: design the network so the forward pass is reversible (every layer has a closed-form inverse). Then activations don't need to be stored at all; they can be exactly reconstructed from the output during backward.

RevNet and Reformer apply this idea. Limited adoption because the architectural constraints (each block must be invertible) reduce flexibility.

When to use checkpointing

  • Always when memory-limited: which is most large-model training.
  • Skip when memory is abundant: small models fit comfortably; the extra compute is wasted.
  • Skip when training is compute-limited: occasionally true on very fast hardware with abundant memory.

In practice, checkpointing is on by default in training pipelines for LLMs and large vision models.

Storing K evenly spaced checkpoints needs about K + L/K layers of activations, minimized at K ≈ √L, turning O(L) activation memory into O(√L) for one extra forward pass.
Storing K evenly spaced checkpoints needs about K + L/K layers of activations, minimized at K ≈ √L, turning O(L) activation memory into O(√L) for one extra forward pass.

The bigger context

Gradient checkpointing is one of several memory optimization techniques used in large-scale training:

  • Activation recomputation (this lesson).
  • Mixed precision (previous lesson).
  • Optimizer state sharding (FSDP, ZeRO, next lessons).
  • CPU offload: keep optimizer state in CPU memory, transfer to GPU for the update.
  • Activation offload: similarly for activations.

Each saves memory at some compute cost. The combination is what makes billion-parameter and trillion-parameter training possible on real-world hardware.

Exercises

Exercise 1. A network has L=48L = 48 transformer blocks. Each block, when stored, holds A=0.5A = 0.5 GB of activations for the current batch. Compare the peak activation memory of full storage against L\sqrt{L} checkpointing, and state the speed cost.

Solution

Step 1. Full storage keeps every block's activations: L⋅A=48×0.5=24L \cdot A = 48 \times 0.5 = 24 GB.

Step 2. With K=LK = \sqrt{L} checkpoints, 48≈6.93\sqrt{48} \approx 6.93, so keep K=7K = 7 checkpoints. Peak memory is the KK stored checkpoints plus one segment recomputed for backward, of length L/K≈48/7≈7L / K \approx 48/7 \approx 7 blocks:

(K+L/K)⋅A≈(7+7)×0.5=7 GB.(K + L/K) \cdot A \approx (7 + 7) \times 0.5 = 7 \text{ GB}.

Step 3. Memory drops from 24 GB to about 7 GB, roughly 3.4×3.4\times less. The cost is one extra forward pass over the recomputed segments during backward, which adds about 33% to step time (the recomputation runs one extra forward worth of FLOPs across the network).

Exercise 2. Derive that K=LK = \sqrt{L} minimizes the checkpoint memory. Treat memory as M(K)=K+L/KM(K) = K + L/K (in units of one block's activations) and minimize over the number of checkpoints KK.

Solution

Step 1. M(K)=K+L/KM(K) = K + L/K sums the KK stored checkpoints and the L/KL/K blocks of one recomputed segment held during backward.

Step 2. Differentiate with respect to KK and set to zero:

dMdK=1−LK2=0⇒K2=L⇒K=L.\frac{dM}{dK} = 1 - \frac{L}{K^2} = 0 \quad\Rightarrow\quad K^2 = L \quad\Rightarrow\quad K = \sqrt{L}.

Step 3. The second derivative 2L/K3>02L/K^3 > 0 confirms a minimum. At K=LK = \sqrt{L} the memory is M=L+L/L=2LM = \sqrt{L} + L/\sqrt{L} = 2\sqrt{L}, which is O(L)O(\sqrt{L}) instead of the O(L)O(L) of full storage.

Exercise 3. A team trains a 100-layer model. Plain training needs 80 GB of activation memory but only 60 GB fits on the GPU. They consider uniform L\sqrt{L} checkpointing (memory ∝2L/L\propto 2\sqrt{L}/L of full) versus selective checkpointing that recomputes only attention (cheap to recompute, half the activation footprint) and stores everything else. Estimate whether each option fits, and name the tradeoff that decides between them.

Solution

Step 1. Uniform L\sqrt{L} checkpointing scales full memory by roughly 2L/L=2/100=0.22\sqrt{L}/L = 2/\sqrt{100} = 0.2. So 80×0.2=1680 \times 0.2 = 16 GB, well under 60 GB. It fits with large margin.

Step 2. Selective attention-only checkpointing recomputes the attention activations (about half the footprint here) and stores the rest, so memory is about 80×0.5=4080 \times 0.5 = 40 GB. This also fits under 60 GB, with less margin.

Step 3. Both fit, so the deciding factor is compute cost, not memory. Uniform checkpointing recomputes the whole network (about +33% step time); selective attention-only checkpointing recomputes only the attention sublayers, paying a smaller recomputation tax for the part that is expensive to store and (relatively) cheap to redo. With 60 GB available and only 40 GB needed by the selective scheme, the team would pick selective checkpointing to keep the speed penalty as small as possible while still fitting.

The next lesson covers the main scaling axis at the cluster level: data parallelism.


References

  1. [1]Chen, T., Xu, B., Zhang, C., & Guestrin, C. (2016). "Training deep nets with sublinear memory cost". arXiv:1604.06174. The source of the O(L)O(\sqrt{L})-memory checkpointing strategy.↩