Activation Checkpointing › The Memory Problem Activation Checkpointing Solves
Language AI HandbookAll chapters Activation Checkpointing › The Memory Problem Activation Checkpointing SolvesOne section · Sections in this chapter2 / 13 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
To understand why activation checkpointing is necessary, you first need a precise picture of where memory goes during training. GPU memory is a scarce, non-expandable resource. Unlike CPU RAM, you cannot simply add more of it mid-run. When an allocation fails, the entire training process crashes, wasting potentially hours of compute time accumulated to that point.
Activation Memory During the Forward Pass
As we examined in the Memory Management chapter, total GPU memory during training decomposes into four categories: model parameters, optimizer states, gradients, and activations. For large models with large batch sizes or long sequences, activations dominate.
The reason activations are so expensive comes down to the structure of the computation graph. Neural network training uses automatic differentiation, which traces through every operation performed during the forward pass and records it in a graph structure. Later, during backpropagation, the system walks this graph in reverse to compute gradients. For the gradient computation at each node to work, the system needs to know the values that existed at that node during the forward pass. So every intermediate tensor produced during the forward pass gets retained in memory until its gradient has been computed during the backward pass. For a deep network with many layers, "until the backward pass computes its gradient" effectively means "until the very end of the backward pass," because gradients flow from the output layer back to the first layer.
Consider a single transformer layer with hidden dimension , sequence length , and batch size . The inputs and outputs of each sublayer (attention, feed-forward, layer norm) all need to be stored for the backward pass. The activations for a single transformer layer scale approximately as:
where:
- is the batch size (number of sequences processed in parallel)
- is the sequence length (tokens per sequence)
- is the model hidden dimension
- the factor of 12 accounts for storing query, key, and value matrices, attention weight matrices, intermediate feed-forward activations, and residual stream tensors, each contributing a or tensor
This factor of 12 deserves more explanation because it surprises many practitioners who expect activations to be small. Within the attention sublayer alone, you store: the pre-norm input (one tensor), the query projection (), the key projection (), the value projection (), and the attention weight matrix (). The attention weights alone contribute a tensor proportional to , which is why long-context training is so memory-intensive. Within the feed-forward sublayer, the intermediate activation has shape , four times the hidden dimension width.
For a 32-layer model with , , , and using float16 (2 bytes per value), total activation memory across all layers is:
That is 64 GB just for activations, on a GPU that might have 40-80 GB total. The parameters themselves (at 16-bit precision) occupy roughly 14 GB for a 7B-parameter model, and the Adam optimizer states (maintained at 32-bit precision for numerical stability) add another 56 GB. You can see immediately why activation memory is not a footnote but the primary driver of training memory constraints. Without some intervention, a 7B model trained with Adam simply cannot fit in a single 80 GB A100.
Why Backpropagation Needs Activations
Backpropagation requires activations because gradient computation is not invertible in general. To compute gradients with respect to the inputs of a layer, you must know what values those inputs had during the forward pass.
The chain rule makes this explicit. The gradient flowing back through a layer depends on the activation at that layer's input or output. For a nonlinear activation function , the gradient at some position requires knowing the value of itself:
where:
- is the training loss
- is the derivative of the activation function, which depends on directly, not just on
For the GELU activation function specifically, has no simple closed form in terms of alone, so must be retained separately from . You cannot reconstruct from without inverting GELU, which is expensive and numerically unstable.
The same dependency appears in every major component of a transformer. The attention mechanism requires storing the attention weight matrix to compute gradient updates for the query, key, and value projection matrices , , and . The gradient of the softmax output with respect to its input is a Jacobian matrix, and computing it requires knowing the softmax output values themselves. The layer normalization sublayer must store its input mean and variance to correctly backpropagate through the normalization step.
Every nonlinear operation creates an activation dependency in the computation graph that must be resolved before the backward pass can continue. Without some form of checkpointing, the entire forward pass activation buffer must remain in memory until the corresponding backward pass gradient is computed, meaning activations from layer 1 must survive in GPU memory until after layer 32's backward pass completes.
The Compute-Memory Ledger for Training
It is helpful to think of training as maintaining a ledger of resources. On one side you have GPU memory capacity. On the other side you have compute budget in terms of FLOPs per second. The standard forward-backward cycle uses memory inefficiently: it reserves activation memory during the forward pass, holds it idle while the backward pass works layer by layer from the end, and only releases memory as each layer's gradients are computed.
This idle reservation is the waste that activation checkpointing targets. The forward pass activations from early layers sit in memory for the entire duration of the backward pass through later layers. If you have 32 layers, layer 1's activations are reserved while layers 32, 31, 30... 3, 2 all compute their gradients, finally being used only when the backward pass reaches layer 1. For a 32-layer model, early-layer activations are idle for roughly 97% of the backward pass. Discarding them and recomputing on demand turns idle memory into compute work, which is a much more efficient use of the available hardware budget.