ZeRO Optimization › The Memory Anatomy of Training
Language AI HandbookAll chapters ZeRO Optimization › The Memory Anatomy of TrainingOne section · Sections in this chapter2 / 14 ↓
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
Before understanding ZeRO, you need to understand precisely what occupies GPU memory during training. The memory footprint has two main categories: model states and residual states.
Model States
Model states are the tensors directly associated with the model's learned parameters. These are the most important category because their size is fully determined by model architecture, and they grow linearly with parameter count.
The three components of model state are:
- Parameters (): The model weights themselves. At 16-bit (fp16 or bf16), each parameter takes 2 bytes. A 7B-parameter model needs 14 GB just for parameters.
- Gradients: One gradient tensor per parameter, matching the size of the parameters. Another 14 GB for a 7B model. These are computed during the backward pass and must persist until the optimizer step completes.
- Optimizer states: The most expensive component when using Adam. Adam maintains two additional tensors per parameter: the first moment (the exponential moving average of gradients) and the second moment (the exponential moving average of squared gradients). Both are stored in 32-bit precision to maintain numerical stability across many update steps. This is bytes per parameter, or 56 GB for a 7B model. Mixed-precision training also requires a 32-bit master copy of the parameters, adding another 4 bytes per parameter or 28 GB.
The reason Adam's moments are stored at 32-bit rather than 16-bit precision is subtle but important. The moment estimates accumulate small incremental updates over potentially millions of training steps. At 16-bit precision, the dynamic range is insufficient to represent the ratio between large and small gradient contributions without losing the small ones to rounding. The 32-bit master copy is similarly necessary because the optimizer step computes a small parameter delta, and adding a small 16-bit delta to a 16-bit parameter can lose precision at a critical scale where training dynamics matter.
Residual States
Residual states include activations, temporary buffers, and memory fragmentation. Activations are the intermediate outputs computed during the forward pass that must be retained for computing gradients during the backward pass. For a transformer with a sequence length of 2048 and a batch size of 4, the activation memory per layer can reach several gigabytes, and activations must be stored for all layers simultaneously. Gradient checkpointing (activation recomputation) trades activation memory for extra compute by discarding most activations and recomputing them during the backward pass. Since ZeRO targets model states specifically, it complements rather than replaces gradient checkpointing.
The Full Accounting
For mixed-precision training with Adam, the breakdown for a model with parameters is:
- 16-bit parameters: bytes
- 16-bit gradients: bytes
- 32-bit parameter copy for optimizer update: bytes
- 32-bit Adam first moment: bytes
- 32-bit Adam second moment: bytes
This totals to bytes per model. For a 7B model, that is 112 GB. For a 70B model, 1.12 TB. No single GPU can hold this, and in naive data parallelism, every GPU in the fleet holds this full amount. A training cluster with 256 A100s running a 7B model under standard data parallelism stores of model state, of which is pure redundancy.
def compute_training_memory(params_billions, precision_bits=16):
"""
Compute per-GPU memory requirements for mixed-precision Adam training.
Returns values in gigabytes.
"""
params = params_billions * 1e9
# Mixed-precision training state
fp16_params = params * 2 # 2 bytes per fp16 param
fp16_grads = params * 2 # 2 bytes per fp16 gradient
fp32_params = params * 4 # 32-bit master copy for optimizer
fp32_m = params * 4 # Adam first moment
fp32_v = params * 4 # Adam second moment
total_bytes = fp16_params + fp16_grads + fp32_params + fp32_m + fp32_v
total_gb = total_bytes / 1e9
return {
"fp16_params_gb": fp16_params / 1e9,
"fp16_grads_gb": fp16_grads / 1e9,
"fp32_master_gb": fp32_params / 1e9,
"fp32_m_gb": fp32_m / 1e9,
"fp32_v_gb": fp32_v / 1e9,
"total_gb": total_gb,
}
model_sizes = [1, 7, 13, 30, 70]
memory_profiles = {size: compute_training_memory(size) for size in model_sizes} Model Params Grads FP32 Master Adam m Adam v Total
------------------------------------------------------------------------
1B 2.0G 2.0G 4.0G 4.0G 4.0G 16.0G
7B 14.0G 14.0G 28.0G 28.0G 28.0G 112.0G
13B 26.0G 26.0G 52.0G 52.0G 52.0G 208.0G
30B 60.0G 60.0G 120.0G 120.0G 120.0G 480.0G
70B 140.0G 140.0G 280.0G 280.0G 280.0G 1120.0GThis table shows the per-GPU memory requirement under naive data parallelism, where each device holds a complete copy of all training state. Every row represents memory that is perfectly duplicated across every GPU in the training cluster, consuming resources that contribute zero additional model capacity. Notice that the Adam optimizer states (FP32 Master + Adam m + Adam v) account for bytes out of the total , making them the dominant memory component and the natural first target for ZeRO.