Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

ZeRO: Memory Optimization for Large Models

Introduction

Welcome to the first lesson in our module on memory optimization for large-scale models. In our previous module, we analyzed different architectures for managing distributed training, focusing on the communication patterns of the decentralized AllReduce model versus the centralized Parameter Server. We saw that for tightly-coupled GPU clusters, synchronous AllReduce is the dominant paradigm.

However, even with highly efficient communication, we face another, more fundamental barrier as models scale into the tens and hundreds of billions of parameters: memory. In standard data parallel training, every GPU holds a full copy of the model, its gradients, and the optimizer states. This redundancy consumes enormous amounts of memory, making it impossible to even fit these large models on a single device.

This lesson tackles this memory crisis head-on. We will explore the Zero Redundancy Optimizer (ZeRO), a breakthrough technique developed by Microsoft. You will learn how ZeRO systematically eliminates memory redundancy by partitioning the three key components of a model's state—optimizer states, gradients, and parameters—across a group of data-parallel GPUs. This is the foundational technique that enables the training of today's largest AI models.

The Memory Bottleneck: Where Does It All Go?

A common point of confusion when first encountering large model training is understanding where all the GPU memory goes. For example, a model with 1.5 billion parameters stored in 16-bit floating-point precision (FP16) should only occupy about 3 GB of memory. So why does training it often require a GPU with over 32 GB of memory?

The answer lies in the fact that the model parameters are only one piece of the memory puzzle. During training, we must also store the gradients and, most significantly, the optimizer states.

To understand this, let's analyze the memory requirements for a model with parameters, trained using the common Adam optimizer with mixed precision.

[PDF] ZeRO: Memory Optimizations Toward Training Trillion Parameter Models

The original ZeRO paper provides a definitive breakdown of memory consumption during training. This section precisely answers the question, 'Where did all the memory go?'

Please read Section 3, 'Where Did All the Memory Go?' (pages 7-8). Focus on the subsection 'Model States'. It details the memory footprint of parameters, gradients, and optimizer states, particularly for mixed-precision training with the Adam optimizer.

As the paper details, the memory consumption for the model states breaks down as follows:

  • Parameters: In mixed-precision training, we typically work with an FP16 copy of the parameters for faster computation.
    • Memory: bytes.
  • Gradients: These are computed during the backward pass and are also typically stored in FP16.
    • Memory: bytes.
  • Optimizer States: This is the largest component. For the Adam optimizer to work reliably in a mixed-precision setting, it maintains several states in full 32-bit precision (FP32):
    1. An FP32 master copy of the parameters for stable updates. Memory: bytes.
    2. The first-order momentum (a running average of gradients). Memory: bytes.
    3. The second-order momentum, or variance. Memory: bytes.
    • Total Optimizer State Memory: bytes.

Combining these, the total memory required for the model states is:

In standard data parallelism, this entire block of memory is replicated on every GPU. For our 1.5B parameter model (), this amounts to GB, and this is before accounting for activations and other buffers. This massive redundancy is the problem ZeRO was designed to solve.

The ZeRO Principle: Partitioning to Eliminate Redundancy

The core insight of ZeRO is simple yet powerful: if the model states are replicated on every device in data parallelism, this replication is a redundancy that can be eliminated. Instead of replicating, ZeRO partitions the model states across the available data-parallel devices.

If you have data-parallel devices (GPUs), each device becomes responsible for storing and updating only its slice of the model states.

The image below provides a high-level visual of this transformation. The top "Baseline" row shows the standard data parallel approach where all three model states (parameters, gradients, and optimizer states) are replicated on every GPU. The bottom row shows the final stage of ZeRO, where each state is partitioned, dramatically reducing the memory footprint on each individual GPU.

Memory Savings and Communication Volume for ZeRO Stages
This diagram illustrates the memory savings from ZeRO. The 'Baseline' shows full replication of parameters, gradients, and optimizer states on each GPU. The subsequent rows (`Pos`, `Pos+g`, `Pos+g+p`) show the progressive partitioning of these states, leading to a significant reduction in per-device memory, from 120 GB to 1.9 GB in this example.

ZeRO implements this partitioning strategy in three incremental stages, allowing a trade-off between memory savings and implementation complexity. Let's examine how each stage works.

Zero Redundancy Optimizer - DeepSpeed

The DeepSpeed documentation provides a concise summary of ZeRO's three stages. This will serve as a quick roadmap before we dive into each one.

Please read the 'ZeRO Overview' section. It briefly describes what is partitioned in Stage 1, Stage 2, and Stage 3.

The Three Stages of ZeRO Partitioning

Now, let's detail the mechanism behind each stage.

Stage 1: Optimizer State Partitioning (Pos)

  • What it partitions: Only the largest portion of the model states—the optimizer states (e.g., the FP32 master parameters, momentum, and variance for Adam). The FP16 parameters and gradients remain replicated on all GPUs.

  • How it works:

    1. The forward and backward passes proceed as in standard data parallelism.
    2. An AllReduce operation is performed on the gradients, so every GPU has a complete copy of the averaged gradients.
    3. Each GPU then uses the full gradient tensor to update only its assigned partition of the optimizer states. This is the key step. For example, GPU 0 updates parameters 1 to P/N, GPU 1 updates P/N+1 to 2P/N, and so on.
    4. After updating its local slice of the FP32 master parameters, each GPU has an updated version of a part of the model. An AllGather collective operation is then performed to broadcast these updated parameter partitions to all other GPUs.
    5. At the end of this step, every GPU once again has a complete and updated set of the FP16 parameters, ready for the next forward pass.
  • Memory Savings: The optimizer state memory drops from to . The total memory becomes . For a large number of GPUs, this approaches a 4x memory reduction compared to the original . Critically, the communication volume remains the same as in standard data parallelism.

ZeRO & Fastest BERT: Increasing the scale and speed of deep learning training in DeepSpeed

The following video from Microsoft Research provides an excellent, animated walkthrough of how ZeRO Stage 1 modifies the training loop.

Please watch from 26:39 to 33:46. The first part (until 29:50) reviews the baseline data parallel approach. The second part (from 29:50 onwards) gives a step-by-step visual explanation of how ZeRO Stage 1 partitions the optimizer states and modifies the update step.

Stage 2: Gradient and Optimizer State Partitioning (Pos+g)

  • What it partitions: Stage 2 builds on Stage 1 by also partitioning the gradients.

  • How it works:

    1. During the backward pass, as gradients are computed, they are not collected for a final AllReduce. Instead, a ReduceScatter operation is performed. This collective operation both sums the gradients from all GPUs and scatters them, so that each GPU ends up with only the slice of the final gradients corresponding to the parameter partition it is responsible for.
    2. This avoids the need for each GPU to store the entire gradient tensor, saving bytes of memory.
    3. The update step and the final AllGather of parameters proceed as in Stage 1.
  • Memory Savings: With both optimizer states and gradients partitioned, the total memory is roughly . For a large , this approaches a 8x memory reduction compared to the original . Remarkably, this is also achieved with the same communication volume as standard data parallelism, as the ReduceScatter + AllGather combination is equivalent in volume to a single AllReduce.

Stage 3: Parameter, Gradient, and Optimizer State Partitioning (Pos+g+p)

  • What it partitions: This is the final and most aggressive stage. It partitions all three model states: parameters, gradients, and optimizer states.

  • How it works:

    1. At the beginning of a training step, each GPU holds only a slice of the FP16 parameters.
    2. During the forward and backward passes, as the computation proceeds from one layer to the next, the parameters for the current layer are broadcast from the GPUs that own them to all other GPUs just-in-time for the computation.
    3. Once the layer's computation is finished, the non-local parameters can be freed, minimizing the peak memory usage. This dynamic communication exploits the temporal nature of the training process—you only need the parameters for the layer you are currently computing.
    4. The gradient reduction and parameter updates proceed as in Stage 2, but on a per-partition basis.
  • Memory Savings: The memory for all model states is now partitioned. The total memory requirement becomes . This means the memory consumption per GPU scales linearly with the number of devices, an -fold reduction. This enables training models of arbitrary size, provided enough GPUs are available.

  • Communication Cost: This stage is the only one that increases the total communication volume, as parameters must be communicated during the forward and backward passes. However, the increase is modest—about 50% more than standard data parallelism—which is often a small price to pay for the enormous memory savings.

Ultimate Guide To Scaling ML Models - Megatron-LM | ZeRO | DeepSpeed | Mixed Precision

For a comprehensive overview that ties these stages together and quantifies the memory reduction, let's watch this segment.

Watch the clip from 01:05:30 to 01:12:42. The speaker walks through the same memory breakdown we discussed, explaining why K=12 for Adam. Crucially, he uses a diagram (the same one shown earlier) to illustrate how memory consumption decreases with each stage of ZeRO, from the 120 GB baseline to just 1.9 GB with full sharding.

Conclusion

In this lesson, we have dissected the ZeRO technique and understood how it addresses the memory wall in large-scale model training. By identifying the massive redundancy in standard data parallel training, ZeRO provides a systematic way to partition model states, enabling a dramatic reduction in per-device memory usage.

Key Takeaways:

  • The memory required to train a model is dominated by model states: parameters, gradients, and especially optimizer states, which together can consume the number of parameters in bytes for mixed-precision Adam.
  • Standard data parallelism replicates these model states on every GPU, creating a severe memory bottleneck for large models.
  • ZeRO (Zero Redundancy Optimizer) eliminates this bottleneck by partitioning the model states across data-parallel devices.
  • ZeRO is implemented in three stages, offering a trade-off between memory savings and communication overhead:
    • Stage 1 partitions optimizer states for an up to 4x memory reduction with no communication overhead.
    • Stage 2 adds gradient partitioning for an up to 8x memory reduction, also with no communication overhead.
    • Stage 3 partitions all model states (parameters, gradients, and optimizer states), achieving a full -fold memory reduction at the cost of a ~50% increase in communication volume.

Preview of the Next Lesson:

Now that we understand how ZeRO partitions each component of the model state, our next lesson will focus on a more direct and quantitative comparison of these three stages. We will analyze the specific memory savings and communication patterns in greater detail, helping you understand the practical design trade-offs involved in selecting the appropriate ZeRO stage for a given AI system and training workload.

Can't find a good explanation? Sign up and we'll make it for you

Sign up