Activation Checkpointing and Selective Rematerialization: Mathematical Foundations, Sub-Linear Memory Scaling, Recomputation Trade-Offs, and Megatron-LM Attention Partitioning
Training modern large language models requires orchestrating hundreds of billions of parameters across distributed GPU clusters. While parameter counts and optimizer states are fixed for a given model architecture, the activation memory generated during forward passes scales directly with sequence length, batch size, and network depth. In long-context pre-training, activation memory rapidly eclipses static parameter weights, frequently triggering out-of-memory (OOM) faults on modern accelerator hardware.
Activation checkpointing (also known as gradient checkpointing or rematerialization) trades compute for memory by discarding intermediate activation tensors during the forward pass and selectively recomputing them during backpropagation. This explainer covers the mathematical foundations of sub-linear memory scaling, optimal segment partitioning, transformer-specific activation dynamics, Megatron-LM selective recomputation, and compiler-level graph partitioning.

1. The Anatomy of LLM Training Memory
During distributed training using 16-bit mixed precision (BF16 or FP16) and the standard AdamW optimizer, total GPU high-bandwidth memory (HBM) is partitioned into static states and dynamic activations.
Static Memory Footprint
For a model with parameters:
- Model Parameters: 2 bytes per parameter ( bytes) in BF16/FP16.
- Parameter Gradients: 2 bytes per parameter ( bytes) in BF16/FP16.
- Optimizer States (AdamW): 12 bytes per parameter ( bytes), consisting of 4 bytes for FP32 master weights, 4 bytes for first-order momentum (), and 4 bytes for second-order uncentered variance ().
Under standard Data Parallelism, the static memory footprint equals bytes. With ZeRO-3 or FSDP sharding across ranks, this reduces to bytes.
Dynamic Activation Memory
Activation memory consists of all intermediate tensors generated during the forward pass that must be retained in HBM to evaluate vector-Jacobian products (VJPs) during the backward pass. For a standard transformer layer with hidden dimension , number of attention heads , head dimension , intermediate MLP dimension (SwiGLU), sequence length , and micro-batch size , the uncheckpointed activation memory per layer in 16-bit precision comprises:
- Multi-Head Attention Q, K, V Projections: bytes.
- Pre-Softmax Attention Matrix (): bytes.
- Post-Softmax Attention Probabilities: bytes.
- Attention Dropout Mask: bytes (or PRNG seed buffer).
- Attention Value Aggregation (): bytes.
- Attention Output Linear Projection: bytes.
- Attention LayerNorm / RMSNorm and Residual Buffer: bytes.
- SwiGLU MLP Gate and Up Projections: bytes.
- SiLU Activation Output Buffer: bytes.
- MLP Down Projection: bytes.
- MLP LayerNorm / RMSNorm and Residual Buffer: bytes.
Summing these terms yields the total activation footprint per transformer layer without FlashAttention or checkpointing:
Across transformer layers, total activation memory scales as . At long context windows (for example, or ), activation memory completely dwarfs static model weights.
2. Mathematical Foundations of Gradient Checkpointing
The fundamental formulation of gradient checkpointing was established by Chen et al. (2016) in "Training Deep Nets with Sublinear Memory Cost".
Consider a feedforward computational graph of sequential layers:
where and is the scalar training objective.
Standard Backprop (Store All Activations):
Forward: [x0] ---> [x1] ---> [x2] ---> [x3] ---> [x4] ---> [L]
Memory: x0, x1, x2, x3, x4 stored simultaneously -> O(N) memory
Backward: [dL/dx4] -> [dL/dx3] -> [dL/dx2] -> [dL/dx1] -> [dL/dx0]
Activation Checkpointing (Store Checkpoints Only):
Forward: [x0]* ---> [x1] ---> [x2]* ---> [x3] ---> [x4]* ---> [L]
Memory: x0, x2, x4 stored -> O(sqrt(N)) memory
Backward: Recompute x3 from x2 -> Backprop layer 4 & 3 -> Discard x3
Recompute x1 from x0 -> Backprop layer 2 & 1 -> Discard x1Standard Backpropagation vs. Full Recomputation
- Standard Backpropagation:
- Stores all activations .
- Memory Complexity: .
- Compute Complexity: One forward pass () and one backward pass (). Total FLOPs: .
- Naive Full Recomputation (Memory Minimal):
- Stores only the initial input .
- To compute gradients for layer , recompute forward from to .
- Memory Complexity: (one layer buffer).
- Compute Complexity: (computationally intractable).
Sub-Linear Uniform Partitioning
Chen et al. proposed partitioning the layers into equal segments of length .
During the forward pass:
- Store only the boundary states (checkpoints): .
- Discard all intermediate activations within each segment.
During the backward pass through segment (spanning layers from to ):
- Load checkpoint .
- Recompute the intermediate activations within segment using forward operators .
- Execute backward propagation through segment using the materialized activations.
- Free the intermediate activations immediately before moving to segment .
Optimal Segment Derivation
The peak activation memory is the sum of the stored checkpoints and the recomputed activations within the active segment:
To find the minimum memory configuration, differentiate with respect to and set to zero:
Substituting back into the memory objective yields:
By partitioning a network into segments of length , peak activation memory scales with the square root of network depth.
Exact FLOPs Overhead Analysis
Let denote the FLOPs required for a single forward pass over all layers. Each layer is executed exactly twice: once during the initial forward pass, and once during the segment recomputation pass in backward propagation.
Total computation required:
Relative to standard training without recomputation (), the compute overhead is:
Full activation checkpointing reduces activation memory by at the cost of a deterministic increase in total floating-point operations.
3. Binomial Tree Checkpointing and Multi-Level Schedules
For deeply recurrent or ultra-deep computation graphs, uniform single-level checkpointing can be generalized to multi-level recursive schedules.
Griewank and Walther (2000) introduced the Revolve algorithm, proving that for a computational graph of length with at most allowable memory slots, the optimal schedule follows a binomial tree structure.
Level 0: [x0] -----------------------------------------------------> [xN]
Level 1: [x0] --------------------> [x(N/2)] ----------------------> [xN]
Level 2: [x0] ---------> [x(N/4)] -> [x(N/2)] ----------> [x(3N/4)] -> [xN]The maximum number of forward steps that can be evaluated using checkpoints with at most recomputations per layer satisfies the binomial coefficient:
When is scaled proportionally, logarithmic memory complexity is achievable with total computation.
4. Megatron-LM Selective Activation Recomputation
While full activation checkpointing trades additional compute for memory, not all operations inside a Transformer layer share the same memory-to-compute ratio.
In "Reducing Activation Recomputation in Large Transformer Models" (Korthikanti et al., 2022), NVIDIA researchers analyzed the operational intensity (FLOPs per byte of activation memory) across individual Transformer components.
Operational Intensity Discrepancy
Transformer operations divide sharply into two categories:
- Matrix Multiplications (GEMMs):
- Linear projections ().
- Compute FLOPs per layer: .
- Activation Memory: elements.
- High operational intensity: millions of FLOPs per transferred byte. Recomputing GEMMs is computationally expensive.
- Elementwise and Normalization Operations:
- LayerNorm / RMSNorm, Softmax, Dropout, GELU / SwiGLU activations.
- Compute FLOPs per layer: (less than of total layer FLOPs).
- Activation Memory: Stores large intermediate tensors, including the attention score matrix and non-linear inputs.
- Low operational intensity: extremely small compute cost, but disproportionately large activation memory footprint.
Transformer Layer Operational Distribution:
+-----------------------------------+-----------------------------------+
| Operation Type | FLOP Share | Activation Mem Share |
+-----------------------------------+-----------------------------------+
| GEMMs (Projections, Linear layers)| ~96 - 98% | ~30% |
| Non-GEMMs (Norms, Softmax, Act) | ~2 - 4% | ~70% |
+-----------------------------------+-----------------------------------+The Selective Recomputation Policy
Selective activation recomputation targets only the low-intensity, high-memory non-GEMM operations:
- Checkpointed Tensors: Retain the output activations of all linear projections and attention context projections.
- Discarded / Recomputed Tensors: Discard and recompute RMSNorm/LayerNorm inputs, Attention Softmax distributions (), Attention Dropout bitmasks, and SwiGLU non-linear gating tensors.
By recomputing only non-GEMMs during the backward pass:
- Activation memory drops by over to per layer, completely removing the quadratic intermediate state.
- Compute overhead drops from down to approximately to .
Comparison of Memory Scaling per Transformer Layer:
- No Checkpointing: 34 b s h + 5 b a s^2 bytes (FLOP overhead: 0%)
- Selective Checkpoint: 10 b s h bytes (FLOP overhead: ~3%)
- Full Checkpointing: 2 b s h bytes (FLOP overhead: ~33.3%)5. Implementation in PyTorch: Reentrant vs. Non-Reentrant Autograd
Modern PyTorch provides native activation checkpointing via torch.utils.checkpoint. Understanding the underlying autograd mechanisms prevents subtle memory leaks and distributed synchronization bugs.
PyTorch Reentrant Checkpointing (use_reentrant=True)
In legacy PyTorch checkpointing, the recomputation pass executes inside a separate torch.autograd.backward invocation within a custom torch.autograd.Function.
- Forward Pass: Disables autograd tracking (
torch.no_grad()) inside the checkpointed block and saves only the input tensors. - Backward Pass: Executes a nested autograd forward pass from the saved inputs with gradients enabled, followed immediately by an internal backward pass.
Limitations:
- Breaks autograd hooks (such as
register_hook) attached to intermediate tensors. - Incompatible with PyTorch Distributed Data Parallel (DDP) find_unused_parameters logic.
- Adds Python interpreter recursion overhead.
PyTorch Non-Reentrant Checkpointing (use_reentrant=False)
Modern PyTorch (v2.0+) implements checkpointing using torch.autograd.graph.saved_tensors_hooks.
import torch
import torch.nn as nn
from torch.utils.checkpoint import checkpoint
class TransformerBlock(nn.Module):
def __init__(self, d_model: int, n_heads: int):
super().__init__()
self.norm1 = nn.RMSNorm(d_model)
self.attn = nn.MultiheadAttention(d_model, n_heads, batch_first=True)
self.norm2 = nn.RMSNorm(d_model)
self.mlp = nn.Sequential(
nn.Linear(d_model, 4 * d_model),
nn.SiLU(),
nn.Linear(4 * d_model, d_model)
)
def forward(self, x: torch.Tensor) -> torch.Tensor:
# Self-Attention sub-layer
norm_x = self.norm1(x)
attn_out, _ = self.attn(norm_x, norm_x, norm_x)
x = x + attn_out
# Feed-Forward sub-layer
norm_x2 = self.norm2(x)
x = x + self.mlp(norm_x2)
return x
class DeepTransformer(nn.Module):
def __init__(self, num_layers: int, d_model: int, n_heads: int):
super().__init__()
self.layers = nn.ModuleList([
TransformerBlock(d_model, n_heads) for _ in range(num_layers)
])
def forward(self, x: torch.Tensor) -> torch.Tensor:
for layer in self.layers:
# Execute layer forward pass with non-reentrant activation checkpointing
x = checkpoint(layer, x, use_reentrant=False)
return xUnder use_reentrant=False, PyTorch installs a pair of pack_hook and unpack_hook callbacks:
pack_hook: Intercepts intermediate tensors scheduled for preservation by autograd and substitutes them with a placeholder or weak reference.unpack_hook: When autograd requests an activation during backward propagation, triggers re-execution of the specific sub-graph, restoring the required tensor directly into the active computation stream.
6. Compiler-Level Min-Cut Rematerialization (AOTAutograd)
With graph-capturing compilers like torch.compile and PyTorch 2.0 AOTAutograd (Ahead-Of-Time Autograd), activation checkpointing moves from manual module-level annotations to automated graph-partitioning algorithms.
AOTAutograd traces the joint forward-backward computational graph, constructing a directed acyclic graph (DAG) where nodes represent primitive operators and edges represent tensor values.
[Input x]
/ \
[Operator A] |
| |
[Operator B] | <--- Min-Cut Partition Boundary
====================== (Tensors crossing cut are saved in memory)
| |
[Operator C] |
\ /
[Loss L]The Min-Cut Objective
Let be the computational DAG, where represents forward operators and represents backward operators. The compiler formulates an optimization problem:
Using max-flow min-cut formulations:
- Every edge crossing from the forward sub-graph to the backward sub-graph represents an activation tensor saved in memory.
- If an edge has a high memory cost but low recomputation cost (such as point-wise operations), the compiler cuts the edge and inserts a rematerialization node in the backward graph.
- If an edge represents a compute-heavy GEMM result, the compiler preserves the tensor across the forward-backward boundary.
7. Interaction with FlashAttention, FSDP, and Model Parallelism
Activation checkpointing interacts directly with distributed parallelism strategies and fused kernel primitives:
FlashAttention Integration
Dao et al. (2022) in FlashAttention implemented online softmax tiling within GPU SRAM. Standard attention writes the attention score matrix to HBM. FlashAttention never materializes this matrix in HBM during either forward or backward passes.
When FlashAttention is combined with selective activation checkpointing:
- FlashAttention eliminates the quadratic memory bottleneck at the kernel level via SRAM recomputation.
- Selective checkpointing eliminates linear projection and normalization memory overheads at the module level.
- Together, they allow scaling sequence lengths beyond tokens on standard hardware clusters without incurring full recomputation penalties across all layers.
Fully Sharded Data Parallelism (FSDP / ZeRO-3)
When using FSDP, model parameters are un-sharded (via all-gather) immediately before forward execution and freed immediately after.
If full activation checkpointing is applied without coordination:
- Backward pass recomputation requires an additional
all-gathercollective communication phase to reconstruct sharded parameters a second time. - Communication volume increases by per training step.
FSDP solves this via activation checkpointing wrappers (apply_activation_checkpointing) that hook directly into FSDP forward units, ensuring collective communication schedules overlap seamlessly with recomputation streams.
8. Summary Comparison of Activation Management Strategies
- Standard Forward-Backward:
- Peak Activation Memory:
- Compute Overhead:
- Best Used For: Small models, short sequence lengths (), and memory-unconstrained runs.
- Selective Activation Recomputation:
- Peak Activation Memory: (eliminates non-GEMM and quadratic attention terms)
- Compute Overhead:
- Best Used For: Standard LLM pre-training and fine-tuning with FlashAttention where memory constraints are moderate.
- Uniform Full Checkpointing ( Segments):
- Peak Activation Memory:
- Compute Overhead:
- Best Used For: Deep transformer models and large batch sizes where static + activation memory exceeds available HBM.
- Checkpointing + Activation Offloading (CPU / NVMe):
- Peak Activation Memory:
- Compute Overhead: PCIe transfer latency overhead (mitigated by asynchronous pinned memory streams)
- Best Used For: Extreme long-context fine-tuning on consumer or single-node GPU hardware.
Sources
- Chen, T., Xu, B., Zhang, C., & Guestrin, C. (2016). Training Deep Nets with Sublinear Memory Cost. arXiv preprint arXiv:1604.06174.
- Korthikanti, V. A., Casper, J., Dey, S., Andersch, M., Shoeybi, M., & Catanzaro, B. (2022). Reducing Activation Recomputation in Large Transformer Models. arXiv preprint arXiv:2205.05198.
- Griewank, A., & Walther, A. (2000). Algorithm 799: Revolve: An Implementation of Checkpointing for the Reverse or Adjoint Mode of Computational Differentiation. ACM Transactions on Mathematical Software, 26(1), 19-45. DOI: 10.1145/347837.347846.
- Dao, T., Fu, D. Y., Ermon, S., Rudra, A., & Ré, C. (2022). FlashAttention: Fast and Memory-Efficient Exact Attention with IO-Awareness. Advances in Neural Information Processing Systems (NeurIPS 2022). arXiv:2205.14135.
- PyTorch Documentation. Activation Checkpointing and torch.utils.checkpoint. PyTorch Autograd Tutorials.



