Gradient checkpointing
Trade compute for memory by recomputing activations during the backward pass instead of storing them.
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 layers and activation size per layer, the backward pass needs all stored activations, costing 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:
- Forward: compute and store only checkpoint activations (every layers, say).
- Backward: when you need a non-checkpointed activation, recompute it by running forward from the nearest earlier checkpoint.
This trades:
- Memory: instead of for layers with 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 checkpoints
If you keep checkpoints, memory is for the checkpoints plus the activations being recomputed for backward. The minimum is at , giving memory [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.
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 transformer blocks. Each block, when stored, holds GB of activations for the current batch. Compare the peak activation memory of full storage against checkpointing, and state the speed cost.
Solution
Step 1. Full storage keeps every block's activations: GB.
Step 2. With checkpoints, , so keep checkpoints. Peak memory is the stored checkpoints plus one segment recomputed for backward, of length blocks:
Step 3. Memory drops from 24 GB to about 7 GB, roughly 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 minimizes the checkpoint memory. Treat memory as (in units of one block's activations) and minimize over the number of checkpoints .
Solution
Step 1. sums the stored checkpoints and the blocks of one recomputed segment held during backward.
Step 2. Differentiate with respect to and set to zero:
Step 3. The second derivative confirms a minimum. At the memory is , which is instead of the 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 checkpointing (memory 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 checkpointing scales full memory by roughly . So 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 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]Chen, T., Xu, B., Zhang, C., & Guestrin, C. (2016). "Training deep nets with sublinear memory cost". arXiv:1604.06174. The source of the -memory checkpointing strategy.↩