TAI BUI
Back to curriculum
BuildPython

Gradient Checkpointing and Activation Recomputation

Backprop keeps every intermediate activation. At 70B parameters and 128K context that is 3 TB of activations per rank. Checkpointing trades FLOPs for memory: recompute instead of save. The question is which segments to drop, and the answer is not "all of them."

TIME: ~70 minutesPREREQUISITES: Phase 10 Lesson 04 (Pre-Training Mini-GPT), Phase 10 Lesson 05 (Scaling & Distributed)

Learning Objectives

  • Explain why backprop stores activations and how checkpointing trades extra forward FLOPs for memory.
  • Compute activation memory and recompute overhead for a given model shape and segment size k.
  • Implement checkpoint-every-k in NumPy and verify its gradients match the full-activation backward.
  • Choose between full recompute, selective recompute and offload for a given model config.

The Problem

Training a transformer stores, for each layer, the inputs to every op that is differentiated in backward: the attention inputs, the Q/K/V projections, the softmax output, the FFN inputs, the norm outputs, and the residual stream. For a layer with hidden size d, sequence length L, batch B, this is on the order of 12 * B * L * d floats per layer.

For d=8192, L=8192, B=1, that's about 1.6 GB/layer in BF16. A 64-layer model is 103 GB of activations. That is before you multiply by microbatch size, add the attention-softmax intermediates (L^2 per head), or count tensor-parallel partial copies.

BF16 weights plus optimizer state might fit in 80GB, and activations are what push you past it. Gradient checkpointing (also called activation recomputation) is the standard fix: drop most activations, then redo the forward during backward to get them back. You pay extra FLOPs, and memory drops by the ratio of checkpoint segments to total layers.

Done naively, checkpointing costs roughly 33% more forward-pass FLOPs per step. Done well, with the selective scheme from Korthikanti et al., you save 5x memory for under 5% FLOP overhead. With FP8 matmuls, FSDP offload, and expert-parallel MoE the choice matters, because you can afford neither the memory nor the wasted compute.

Warm-up0/3
1. During standard backprop, why does the forward pass have to keep intermediate activations in memory?Warm-up
A generic forward step turning an input into an output, with an arrow into a backward step whose requirement is left blank. A question asks why the forward pass must keep something in memory for backward to use.
The forward-to-backward handoff is a generic setup; what backward needs is the question.
2. How many bytes does one BF16 value occupy in memory?Warm-up
A scenario card titled One tensor value, stored in BF16, subtitled Format given, size blank. Given: format: BF16; bytes per value: ?. A question asks: How many bytes does one BF16 value occupy in memory?
Every fact shown is the stem's own given setup; the question itself is left blank.
3. In reverse-mode backpropagation, in what order are the layers processed?Warm-up
Three layers L1, L2, L3 with a forward arrow running left to right, then the same three layers repeated below with no arrows drawn. A question asks in which order backward processes these layers.
The forward direction is the stem's own given order; backward's order is the question.
Check: The Problem0/1
1. BF16 weights plus optimizer state fit in 80 GB, yet training still runs out of memory. Why does checkpointing target activations?Explain
A scenario card titled A training run that still runs out of memory, subtitled BF16 weights and optimizer state already fit. Given: BF16 weights + optimizer state: fit inside 80 GB; training run: still runs out of memory. A question asks: Why does checkpointing target activations rather than weights or optimizer state?
Every fact shown is the stem's own given setup; the question itself is left blank.

The Concept

What Backward Actually Needs

output = layer(input). Backward wants grad_input and grad_params. To compute them it needs:

  • input (to compute grad_params = input.T @ grad_output for linear layers)
  • some activation derivative intermediates (the derivative of ReLU/GELU/softmax depends on the activation value)

The forward pass stores these automatically in the autograd graph: any op that needs its input in backward keeps a reference to it.

Naive Full Checkpointing

Split the network into N segments. During forward, store only the input to each segment. When backward needs intermediates, rerun the segment's forward pass to materialize them, then differentiate.

Example: 32-layer transformer split into 32 segments of 1 layer each.

  • Memory: 32 layer-inputs (small) vs 32 * (activation volume per layer) (huge).
  • Extra compute: 1 extra forward per segment, i.e., ~33% more forward FLOPs total (since backward is 2x forward, full step becomes 1 + 1 + 2 = 4 units instead of 1 + 2 = 3).

This is the original Chen et al. 2016 recipe: one checkpoint every sqrt(L) layers to balance memory and compute. For L=64, that's 8 checkpoints.

Selective Checkpointing (Korthikanti 2022)

Not all activations cost the same. The attention softmax output is B*L*L*heads and grows quadratically with sequence length. The FFN hidden activation is B*L*4d and grows linearly. For long sequences the softmax dominates.

Selective checkpointing keeps the cheap-to-store activations (linear projections, residuals) and recomputes only the expensive ones (attention). You pay minimal FLOPs to recompute but save the O(L^2) memory.

Megatron-Core implements this as "selective" activation recomputation, used in most 2024+ frontier training runs.

Offload

Alternative to recompute: ship activations to CPU RAM between forward and backward. It needs PCIe bandwidth, so it pays off when idle bandwidth exceeds the cost of rematerialization. You can mix the two: checkpoint some layers, offload others.

FSDP2 ships offload as a first-class option. Offload shines when GPU is bottlenecked on memory but CPU-GPU transfer has headroom.

Recompute Cost Model

Per-step FLOPs with naive checkpointing every k layers out of L:

flops_fwd_normal = L * f_layer
flops_bwd_normal = 2 * L * f_layer
flops_total_normal = 3 * L * f_layer

flops_fwd_ckpt = L * f_layer
flops_recompute = L * f_layer  # one extra forward per layer in the segment
flops_bwd_ckpt = 2 * L * f_layer
flops_total_ckpt = 4 * L * f_layer
overhead = 4 / 3 - 1 = 0.33 = 33%

With selective checkpointing you recompute only the attention kernel, not the whole layer:

flops_recompute_selective = L * f_attention ~= L * f_layer * 0.15
overhead_selective = (3 + 0.15) / 3 - 1 = 0.05 = 5%

Memory Savings Model

Activation volume per layer: A. For L layers, total activation memory: L * A.

Full checkpoint (segment size 1): store only L * input_volume (~L * 1/10 A for a standard transformer). Saves ~9 * L * A * 1/10.

Checkpoint every k layers: store L/k * A plus k-1 layers' worth within the active segment.

At k = sqrt(L), memory and recompute cost both scale with sqrt(L), which is the best tradeoff for uniform-cost layers.

When Not to Checkpoint

  • The innermost layers of a pipeline stage already in-flight. They have to finish anyway.
  • The first and last layers if they dominate the stage's compute (rare in transformers).
  • Attention kernels already using FlashAttention. Flash recomputes the softmax quickly, so additional layer-level checkpointing adds little on top.

Implementation Patterns

  1. Function wrapper: wrap a segment in torch.utils.checkpoint.checkpoint(fn, input). PyTorch stores only input, recomputes everything else on backward.

  2. Decorator-based: label layers as checkpointable; the trainer decides at config time which segments get wrapped.

  3. Manual explicit recompute: write the backward pass yourself, calling a custom recompute_forward that duplicates the forward with the stored input.

The three give the same result. Wrappers are the usual choice.

Interaction with TP / PP / FP8

  • Tensor parallel: checkpoint inputs must be gathered or rescattered on recompute; handle the communication cost.
  • Pipeline parallel: typical pattern is to checkpoint each pipeline-stage's forward so reverse-order microbatches can reuse activation memory.
  • FP8 recompute: amax histories updated during recompute must match the original forward's, or the FP8 scale drifts. Most frameworks snapshot the scale.
Check: The Concept0/23
1. What is gradient checkpointing?Define
A term card reading Gradient checkpointing. Context note: Context: the memory-saving technique this lesson's Problem section opens with. A question asks: What is it?
The term as the lesson names it; its mechanism is the question.
2. How does activation recomputation relate to gradient checkpointing?Define
A term card reading Activation recomputation. Context note: Context: a second name appearing in the Key Terms table, directly below Gradient checkpointing. A question asks: How does it relate to gradient checkpointing?
The term as the lesson names it; its mechanism is the question.
3. In checkpoint-every-k training, what does the segment size k count?Define
A term card reading Segment size (k). Context note: Context: the parameter named k throughout the Build It section's checkpoint-every-k code. A question asks: In checkpoint-every-k training, what does segment size k count?
The term as the lesson names it; its mechanism is the question.
4. What does selective checkpointing recompute?Define
A term card reading Selective checkpointing. Context note: Context: Korthikanti et al.'s 2022 refinement, named in The Concept section. A question asks: What does selective checkpointing recompute?
The term as the lesson names it; its mechanism is the question.
5. What does full checkpointing recompute?Define
A term card reading Full checkpointing. Context note: Context: the naive checkpointing scheme named in The Concept section, before Selective Checkpointing. A question asks: What does full checkpointing recompute?
The term as the lesson names it; its mechanism is the question.
6. What is block checkpointing?Define
A term card reading Block checkpointing. Context note: Context: a term named in the Key Terms table, appearing after Full checkpointing. A question asks: What is block checkpointing?
The term as the lesson names it; its mechanism is the question.
7. How is FLOP overhead defined for checkpointing?Define
A term card reading FLOP overhead. Context note: Context: a ratio the Recompute Cost Model reports for every schedule choice, named in the Key Terms table. A question asks: How is FLOP overhead defined for checkpointing?
The term as the lesson names it; its mechanism is the question.
8. What is activation offload?Define
A term card reading Activation offload. Context note: Context: an alternative to recompute, named in The Concept section's Offload subsection. A question asks: What is activation offload?
The term as the lesson names it; its mechanism is the question.
9. What does the sqrt-L rule say?Define
A term card reading sqrt-L rule. Context note: Context: a classical result from Chen et al. 2016, named in The Concept section. A question asks: What does the sqrt-L rule say?
The term as the lesson names it; its mechanism is the question.
10. What is the attention-softmax volume?Define
A term card reading Attention-softmax volume. Context note: Context: a quantity discussed in the Selective Checkpointing subsection of The Concept section. A question asks: What is the attention-softmax volume?
The term as the lesson names it; its mechanism is the question.
11. Roughly how much compute does a transformer layer's backward pass cost relative to its forward pass?Define
A scenario card titled One transformer layer's forward pass, subtitled Cost given, backward's cost blank. Given: forward FLOPs: 1 unit; backward FLOPs: ? units. A question asks: About how much does backward cost, relative to forward?
Every fact shown is the stem's own given setup; the question itself is left blank.
12. Per the Recompute Cost Model, how much extra compute does full-layer checkpointing add to a training step?Explain
The Build It Step 4 cost model's three raw units for full-layer checkpointing: forward 1x, recompute 1x for every layer in every segment, backward 2x. A question asks what overhead this adds to a training step.
The three units are the lesson's own cost model; the resulting overhead is the question.
13. Why does selective checkpointing recompute attention but keep the FFN activations?Explain
A scenario card titled What selective checkpointing keeps and drops, subtitled Given directly by the question. Given: attention softmax: recomputed by selective checkpointing; FFN activations: kept, not recomputed. A question asks: Why does selective checkpointing recompute attention but keep the FFN activations?
Every fact shown is the stem's own given setup; the question itself is left blank.
14. When does offloading activations to CPU RAM beat recompute?Explain
Two plain boxes labelled offload and recompute, with no description of either and no comparison drawn between them. A question asks when offloading activations to CPU RAM beats recompute.
Only the two names are given; the condition that favors one over the other is the question.
15. Why does FlashAttention reduce the value of extra layer-level checkpointing around attention?Explain
A scenario card titled An attention kernel that already uses FlashAttention, subtitled No extra checkpointing added yet. Given: attention kernel: already using FlashAttention; extra layer-level checkpointing: being considered, around attention. A question asks: Why does this reduce the value of adding extra layer-level checkpointing around attention?
Every fact shown is the stem's own given setup; the question itself is left blank.
16. What extra complication does tensor parallelism add to checkpointed recompute?Explain
A scenario card titled Checkpointed recompute under tensor parallelism, subtitled TP is active on this run. Given: parallelism in use: tensor parallel (TP); operation: checkpointed recompute. A question asks: What extra complication does TP add here?
Every fact shown is the stem's own given setup; the question itself is left blank.
17. What is the typical checkpointing pattern under pipeline parallelism?Explain
A scenario card titled Checkpointing under pipeline parallelism, subtitled PP is active on this run. Given: parallelism in use: pipeline parallel (PP); checkpointing: in use on this run. A question asks: What is the typical checkpointing pattern here?
Every fact shown is the stem's own given setup; the question itself is left blank.
18. For a 64-layer network, where does the Chen et al. 2016 recipe in The Concept section place checkpoints?Apply
A plain 8 by 8 grid of 64 small layer boxes, none marked as a checkpoint. A question asks where the Chen et al. 2016 recipe places checkpoints across these 64 layers.
The 64 layers are the stem's own count; the checkpoint placement is the question.
19. If selective checkpointing recomputes only attention at about 15% of a layer's FLOPs, what step overhead results?Apply
The Build It Step 4 cost model's three raw units for selective checkpointing: forward 1x, recompute 0.15x for the attention kernel only, backward 2x. A question asks what overhead this adds to a training step.
The three units are the lesson's own cost model; the resulting overhead is the question.
20. An FP8 run recomputes a layer during backward and the loss curve starts to drift. What is the most likely cause?Analyze
A scenario card titled An FP8 run, mid-training, subtitled Recompute happened during backward. Given: precision: FP8; event: a layer gets recomputed during backward; symptom: the loss curve starts to drift. A question asks: What is the most likely cause?
Every fact shown is the stem's own given setup; the question itself is left blank.
21. Activation offload is on and step time jumps while GPU memory looks fine. PCIe is saturated by other traffic. What went wrong?Analyze
A scenario card titled Activation offload, under PCIe pressure, subtitled Memory looks fine; the link does not. Given: activation offload: switched on; GPU memory: looks fine; PCIe link: saturated by other traffic; step time: jumps. A question asks: What went wrong?
Every fact shown is the stem's own given setup; the question itself is left blank.
22. A 64-layer model OOMs on activations at long context, attention dominates memory, and you can spare only a few percent of extra compute. What fits best?Design
A scenario card titled A 64-layer model, long context, tight compute budget, subtitled Attention dominates the memory. Given: model: 64 layers; context length: long; memory bottleneck: attention-dominated; spare compute budget: only a few percent. A question asks: Which plan fits best?
Every fact shown is the stem's own given setup; the question itself is left blank.
23. Your GPU is memory-bound and CPU-GPU transfer has spare bandwidth, but you can afford only moderate extra FLOPs. Which plan fits?Design
A scenario card titled A memory-bound GPU with spare PCIe bandwidth, subtitled Only moderate extra FLOPs are affordable. Given: GPU: memory-bound; CPU-GPU transfer: has spare bandwidth; extra FLOPs affordable: only moderate. A question asks: Which plan fits?
Every fact shown is the stem's own given setup; the question itself is left blank.

Build It

Step 1: A Toy Model With Segments

python
import numpy as np
 
 
def linear_forward(x, w, b):
    return x @ w + b
 
 
def relu(x):
    return np.maximum(x, 0)
 
 
def layer_forward(x, w1, b1, w2, b2):
    h = relu(linear_forward(x, w1, b1))
    return linear_forward(h, w2, b2)
 
 
def model_forward(x, params):
    activations = [x]
    h = x
    for w1, b1, w2, b2 in params:
        h = layer_forward(h, w1, b1, w2, b2)
        activations.append(h)
    return h, activations

Step 2: Naive Backward Needing All Activations

python
def model_backward(grad_output, activations, params):
    grads = [None] * len(params)
    g = grad_output
    for i in range(len(params) - 1, -1, -1):
        w1, b1, w2, b2 = params[i]
        x_in = activations[i]
        h_pre = linear_forward(x_in, w1, b1)
        h = relu(h_pre)
        gh = g @ w2.T
        gw2 = h.T @ g
        gb2 = g.sum(axis=0)
        g_pre = gh * (h_pre > 0)
        gx = g_pre @ w1.T
        gw1 = x_in.T @ g_pre
        gb1 = g_pre.sum(axis=0)
        grads[i] = (gw1, gb1, gw2, gb2)
        g = gx
    return g, grads

Step 3: Checkpoint-Every-k Memory

python
def model_forward_checkpointed(x, params, k=4):
    saved_inputs = [x]
    h = x
    for i, (w1, b1, w2, b2) in enumerate(params):
        h = layer_forward(h, w1, b1, w2, b2)
        if (i + 1) % k == 0:
            saved_inputs.append(h)
    return h, saved_inputs
 
 
def model_backward_checkpointed(grad_output, saved_inputs, params, k=4):
    grads = [None] * len(params)
    g = grad_output
    segments = [(j * k, min((j + 1) * k, len(params))) for j in range(len(saved_inputs))]
    for seg_idx in range(len(saved_inputs) - 1, -1, -1):
        start, end = segments[seg_idx]
        if start >= end:
            continue
        x_in = saved_inputs[seg_idx]
        _, seg_acts = model_forward(x_in, params[start:end])
        g, seg_grads = model_backward(g, seg_acts, params[start:end])
        for j, gr in enumerate(seg_grads):
            grads[start + j] = gr
    return g, grads

Step 4: Cost Model

python
def checkpoint_cost(n_layers, segment_size, flops_per_layer=1.0):
    fwd = n_layers * flops_per_layer
    recompute = n_layers * flops_per_layer
    bwd = 2 * n_layers * flops_per_layer
    return {
        "fwd": fwd,
        "recompute": recompute,
        "bwd": bwd,
        "total": fwd + recompute + bwd,
        "overhead_vs_no_ckpt": (fwd + recompute + bwd) / (fwd + bwd) - 1.0,
    }
 
 
def selective_checkpoint_cost(n_layers, attention_fraction=0.15,
                              flops_per_layer=1.0):
    fwd = n_layers * flops_per_layer
    recompute = n_layers * attention_fraction * flops_per_layer
    bwd = 2 * n_layers * flops_per_layer
    return {
        "fwd": fwd,
        "recompute": recompute,
        "bwd": bwd,
        "total": fwd + recompute + bwd,
        "overhead_vs_no_ckpt": (fwd + recompute + bwd) / (fwd + bwd) - 1.0,
    }

Step 5: Memory Estimator

python
def activation_memory_mb(n_layers, hidden=8192, seq=8192,
                        batch=1, bytes_per_value=2):
    per_layer = 12 * batch * seq * hidden * bytes_per_value
    return n_layers * per_layer / 1e6
 
 
def memory_after_checkpoint(n_layers, segment_size, hidden=8192,
                           seq=8192, batch=1, bytes_per_value=2):
    n_seg = (n_layers + segment_size - 1) // segment_size
    saved = (n_seg + segment_size) * batch * seq * hidden * bytes_per_value
    return saved / 1e6

Step 6: Optimal Segment Size

python
def optimal_segment(n_layers):
    return max(1, int(round(np.sqrt(n_layers))))

Step 7: Selective Checkpoint Decision

python
def should_recompute(layer_type, activation_bytes, recompute_flops_ratio):
    if layer_type == "attention" and activation_bytes > 100 * 1e6:
        return True
    if layer_type == "ffn" and activation_bytes > 500 * 1e6:
        return recompute_flops_ratio < 0.1
    return False
Check: Build It0/8
1. Why must the checkpointed backward produce the same gradients as the full-activation backward?Explain
Two backward routes side by side, full-activation backward producing grads F and checkpointed backward producing grads C, with a blank F equals C question mark between them. A question asks why the two must match.
That both routes are expected to reach the same gradients is the setup; the reason is the question.
2. model_forward_checkpointed runs on 10 layers with k=4. How many tensors does saved_inputs hold afterward?Apply
Build It Step 3's own model_forward_checkpointed code, which appends the input and then the output every k layers, with n_layers at 10 and k at 4, and the final saved_inputs length left blank. A question asks how many tensors saved_inputs holds when this finishes.
The code and both numbers are the lesson's own Build It Step 3 pseudocode; tracing it is the question.
3. memory_after_checkpoint is called with n_layers=64 and segment_size=8. How many batch*seq*hidden-sized tensors does it count?Apply
main.py's own memory_after_checkpoint call with n_layers at 64 and segment_size at 8, with the counted tensors left blank. A question asks how many batch times seq times hidden sized tensors this call counts.
Both numbers are the stem's own; the tensor count is the question.
4. With the default arguments, about what does activation_memory_mb(1) return for one layer?Apply
main.py's own activation_memory_mb call with n_layers at 1 and its default hidden, seq, batch and bytes_per_value arguments, with the returned megabytes left blank. A question asks about what this call returns for one layer.
All five arguments are the function's own defaults; the result is the question.
5. Using should_recompute from Build It Step 7, what happens to an FFN layer with a 600 MB activation and a recompute FLOPs ratio of 0.3?Apply
main.py's own should_recompute call for an FFN layer with activation_bytes_mb at 600 and recompute_flops_ratio at 0.3, with the returned value left blank. A question asks what this call returns.
All three arguments are the stem's own; the return value is the question.
6. An attention layer holds 80 MB of activations and has a recompute FLOPs ratio of 0.05. What does should_recompute return?Apply
main.py's own should_recompute call for an attention layer with activation_bytes_mb at 80 and recompute_flops_ratio at 0.05, with the returned value left blank. A question asks what this call returns.
All three arguments are the stem's own; the return value is the question.
7. main.py prints 0% overhead for k=1, but the Step 4 cost model charges 33% whatever k is. What explains the gap?Analyze
Two given figures side by side: main.py reporting 0% overhead at k equals 1, and the Step 4 cost model reporting 33% overhead whatever k is. A question asks what explains the gap between them.
Both figures are the stem's own; the explanation for the gap is the question.
8. memory_after_checkpoint(64, k) returns the same value at k=1 and at k=64. What explains this?Analyze
main.py's own memory_after_checkpoint call with n_layers at 64, run once at segment size k equals 1 and once at k equals 64, both tensor counts left blank. A question asks why the two extremes return the same value.
n_layers is the stem's own; both tensor counts are the question.

Use It

  • torch.utils.checkpoint: from torch.utils.checkpoint import checkpoint is the standard wrapper in PyTorch. It wraps a function, stores only the inputs, and recomputes on backward.
  • Megatron-Core activation recomputation: supports selective, full, and block modes. Standard in 2024+ frontier training.
  • FSDP2 offload: module.to_empty(device="cpu") with offload_policy in FSDP2 shards activations to CPU instead of recomputing.
  • DeepSpeed ZeRO-Offload: CPU offload for optimizer states and activations, complementing checkpointing.
Check: Use It0/1
1. Which tools does Use It name for activation recomputation or offload in production?Define
A single blank panel standing in for the Use It section's list of tools, with no names shown. A question asks which tools Use It names for activation recomputation or offload in production.
That Use It names tools for this is the setup; which ones is the question.

Ship It

This lesson produces outputs/prompt-activation-recompute-policy.md, a prompt that takes your model config (layers, hidden, seq, batch) and available GPU memory and emits a per-layer recompute policy (none / selective / full / offload).

Author's Note

I'd run main.py before trusting any of the numbers above. verify_equivalence() runs the plain backward and the checkpointed backward on the same weights and the same upstream gradient, and reports whether the outputs match and the largest gradient difference. That check is the whole point of the technique: recomputing a segment has to give back the activations you dropped.

The cost model deserves a skeptical read. The checkpoint_cost in main.py scales non-selective recompute by (segment_size - 1) / segment_size, so k=1 prints 0% overhead, while the Step 4 version above ignores segment_size and always charges a full extra forward (33%). The checkpointed backward behaves like neither. It reruns model_forward over every layer in each segment, including when the segment is one layer. Treat the cost model as the textbook approximation and the code as the thing that actually runs.

memory_after_checkpoint is a rough estimate too. It counts each saved input and each layer inside the live segment as one batch * seq * hidden tensor, while activation_memory_mb charges a full layer 12 of them. That gap is why I'd sweep k in the exercises and look for where the curve flattens, rather than just plugging in sqrt(L). For a real model I'd measure peak memory with the PyTorch wrapper and use Megatron's selective mode once attention dominates.

Exercises

  1. Verify correctness. Run model_forward + model_backward (full activations) vs model_forward_checkpointed + model_backward_checkpointed (segments). Parameter gradients must be identical to machine precision.

  2. Sweep segment size k from 1 to L. Plot FLOP overhead and memory. Find the knee of the curve.

  3. Implement selective checkpointing: store the attention-module input but not its intermediates. Measure the FLOP overhead vs full-layer checkpointing for a 32-layer model at seq=8192.

  4. Add offload. Save segment inputs to a simulated "CPU buffer" (a separate list). Measure "PCIe bandwidth" as bytes/time and find the breakeven point between offload and recompute.

  5. Benchmark a real PyTorch transformer with and without torch.utils.checkpoint. Measure memory (via torch.cuda.max_memory_allocated) and step time.

Key Terms

TermWhat people sayWhat it actually means
Gradient checkpointing"Save memory by redoing forward"Store segment inputs only; recompute intermediates during backward to get gradient-support tensors
Activation recomputation"Same as checkpointing"The HPC-flavored name for the same technique
Segment size (k)"How many layers per checkpoint"Number of layers whose intermediates are dropped and rematerialized together
Selective checkpointing"Korthikanti's trick"Recompute only expensive-to-store activations (attention softmax); keep cheap ones
Full checkpointing"The naive version"Recompute every layer's intermediates in every segment
Block checkpointing"Coarse-grained"Checkpoint whole transformer blocks; largest granularity
FLOP overhead"The compute tax"Extra FLOPs per step = (recompute FLOPs) / (fwd + bwd FLOPs); 33% naive, 5% selective
Activation offload"Ship to CPU"Move activations to CPU RAM across forward->backward; alternative to recompute
sqrt-L rule"The classical optimum"For uniform-cost layers, optimal checkpoint spacing is sqrt(L) layers
Attention-softmax volume"The O(L^2) problem"L^2 * heads * batch floats; dominates activation memory at long contexts

Further Reading

Code

Ships With