08 / THE ARC

ZeRO stages 1, 2 and 3

Look again at what data parallelism stores. Every GPU holds the full 16 bytes for every weight, and the copies are identical. Eight GPUs therefore hold eight identical copies of 447 GiB of state, which is 3,576 GiB of memory to store 447 GiB of information.

eight cards, eight identical copies 447447447447 447447447447 3,576 GiB of memory to store 447 GiB of information
Not eight parts of something large. Eight copies of the same thing.

Most of that is never needed in eight places. During the update, each GPU applies the same average to the same weights and produces the same answer, so seven of the eight are repeating work already being done. The idea is to give each GPU responsibility for one slice of the weights, let it keep only the state for that slice, and have it fetch anything else it needs when it needs it. Every GPU receives a different slice, so all eight hold the same amount of state and none of them sits idle.

That idea is called ZeRO, which stands for Zero Redundancy Optimizer. It was published by Microsoft in 2019. It describes an arrangement of storage rather than a change to the mathematics — the model learns exactly what it would have learned under plain data parallelism.

Redundancy is not the same as replication

Data parallelism replicates the weights for a reason: every card runs a full forward pass and needs them. What it also replicates, without a reason, is the optimizer state, which is touched once per step by an update that produces the same answer on every card. ZeRO removes the part that had no reason.

Three stages, each removing one more class of duplicate

Stage 1 splits the optimizer state, which is the 32-bit weight copy and the two running averages, twelve of the sixteen bytes. Each GPU keeps one slice and updates only that slice. The updated slices are then shared out so every GPU has the current weights again.

Stage 2 splits the gradients as well. A GPU only ever needs the gradients for the slice of weights it is responsible for updating, so the others are discarded as soon as they have been sent where they are needed.

Stage 3 splits the weights themselves. Each GPU stores one slice of the model. When the forward pass reaches a layer, the GPUs collect that layer's weights from each other, use them, and discard them again immediately.

what one card holds as the forward pass moves through the model layer 1 layer 2 layer 3 layer 4 its own slice of every layer — always resident, 16/N bytes per weight all-gatherlayer 1 all-gatherlayer 2 all-gatherlayer 3 all-gatherlayer 4 released released released released only one layer is ever fully assembled at a time — the peak is a layer, not a model
The cream strip is what the card keeps. The copper blocks appear and vanish, one layer at a time, and never overlap.

That gather-use-discard cycle is what makes the memory saving real rather than notional. A card never holds the whole model, only its slice plus whichever single layer is currently in use. It is also where the extra communication comes from: the weights have to be fetched before every layer of the forward pass and again during the backward pass, which is the difference between ZeRO-3's 3P and the 2P of the earlier stages.

The limit this exposes

The peak is one assembled layer, so ZeRO-3 needs the largest single layer of the model to fit on one card. If a layer on its own exceeds the card, no amount of sharding state helps — the model has to be cut across cards rather than merely its state, which is tensor parallelism and a different session. This is the boundary where ZeRO stops being enough.

What each stage leaves on a card

Eight GPUs, eight weights, four bands. Switch the arrangement and watch which cells stay solid and which become dashed gaps — a dashed cell is state some other card is holding on this weight's behalf.

ARRANGEMENT
A solid cell is state this GPU stores. A dashed cell is state another GPU stores for that weight. GPU k owns weight k, marked by the tick under its column.
MEMORY ONE GPU NEEDS AGAINST WHAT ONE CARD HOLDS
one 80 GB card, 74.5 GiB

        
WHERE EACH BAND LIVES

The bands from the first page, now with a divisor applied to whichever of them the stage has sharded. N is the number of GPUs; the figures are for eight.

bytes per weight, per GPU at 30B params, N = 8 data parallel 2 2 12 — optimizer state 447 GiB ZeRO-1 2 2 12/N 153.7 GiB optimizer state sharded ZeRO-2 2 104.8 GiB gradients sharded as well ZeRO-3 55.9 GiB parameters sharded too — 16/N an 80 GB card holds 74.5 GiB only ZeRO-3 fits, and only just — before activations are counted
The dashed outline is what used to be there. Each stage divides one more band by the number of GPUs.
Memory per GPU, 30 billion parameters, eight GPUs
Bytes per weight, 8 GPUs30B model per GPUCommunication
data parallelism16.00447.0 GiB2P
ZeRO-15.50153.7 GiB2P
ZeRO-23.75104.8 GiB2P
ZeRO-32.0055.9 GiB3P

Stages 1 and 2 return ten of the sixteen bytes at the communication volume data parallelism was already paying. The reason is the equivalence from the collectives page. Data parallelism performs an all-reduce, which is internally a reduce-scatter and an all-gather. Stages 1 and 2 perform those same two phases and simply keep the intermediate slice instead of discarding it. Stage 3 adds a further all-gather of the weights in the forward pass and again in the backward pass, which raises the total from 2P to 3P.

the same two phases, in both schemes data parallel reduce-scatter all-gather 2P the slice each card owned here is thrown away ZeRO-1 and 2 reduce-scatter all-gather 2P that same slice is kept, and the card updates it identical traffic — the only difference is whether the intermediate is discarded
Stages 1 and 2 are free because the operation data parallelism already ran produced the sharded state as a by-product, and then threw it away.
Carry this forward: stages 1 and 2 cost nothing extra in communication, and stage 3 costs half as much again.
BACKThe cost of communication