05 / THE ARC

Data parallelism

The simplest way to use eight GPUs is to give each of them a complete copy of the model and a different portion of the data. Each GPU reads its own examples, runs them through its own copy, and produces its own gradients. Those gradients differ from each other, because each GPU saw different text.

The copies then have to be brought back into agreement. Every GPU sends its gradients to every other GPU, all of them compute the average, and each applies that same average to its own copy. Because they started identical and applied an identical update, they remain identical. This arrangement is called data parallelism.

different text on each card shard 0shard 1 shard 2shard 3 shard 4shard 5 shard 6shard 7 identical model on each card different gradients come out g₀g₁ g₂g₃ g₄g₅ g₆g₇ all-reduce — average every card applies the same average, so every card stays identical
Data differs, gradients differ, the average does not. That is the whole mechanism.

Watch it happen

Four GPUs hold one copy each of the same four weights, and a batch of eight samples is split two per GPU. The loss on a sample is L = 0.5 · ‖w − x‖², so that sample's gradient is w − x, and a GPU's gradient is the mean over its two samples. The update is w := w − 0.1g.

The batch of eight is split, not copied: samples 1 and 2 go to GPU 0, samples 3 and 4 to GPU 1, and so on. Each sample is seen by exactly one card, which is why the eight gradients that exist across the cluster are four means of two rather than eight copies of anything. The strip at the top of the widget shows the split for the current batch.

Each batch runs in three phases and the button walks one phase at a time. The working underneath the panels shows the actual arithmetic at each phase — which numbers are being subtracted from which, what is being averaged with what, and where the result lands.

batch 0 · not yet stepped
  1. 1  each card computes its own gradient
  2. 2  the four gradients are averaged
  3. 3  every card subtracts the same thing
largest difference between any two weight copies 0.000 all four copies agree on every weight

So the answer to where the average goes is: back to everyone. All-reduce is not a gather-to-one-card operation. Every card ends the exchange holding the same averaged vector, and then every card does its own subtraction locally. No card is in charge, and no card has anything the others lack.

That is what keeps the copies identical. They began identical, and they applied the same number to the same starting value, so they end identical — not approximately, exactly. The drift figure stays at 0.000 however many batches you run.

Turn averaging off and phase 2 exchanges nothing. Each card applies its own gradient, the bottom rows stay different, and the copies separate on the first step. They are then four different models that happen to share a starting point.

Why the averaging is what makes it correct

The averaging step is not bookkeeping — it is the thing that makes the arrangement mathematically defensible. Averaging the gradients from eight GPUs, each of which processed 32 sequences, produces exactly the gradient that a single GPU would have produced from all 256 sequences at once.

32sequences per GPU
×
8GPUs
=
256sequences, one gradient

The distributed run is therefore identical to a single-GPU run on a batch eight times larger. This is the property that lets a training recipe move from one GPU to many without changing what the model learns. Nothing about the result depends on how many cards were involved.

Why this matters more than it sounds

If the result depended on the card count, every change to the cluster would mean retuning the learning rate and revalidating the recipe. Because it does not, the number of GPUs becomes a scheduling decision rather than a modelling one.

The batch the optimizer sees

It is the product of three numbers, and it is worth being able to state which one you are turning.

Global batch

global batch = sequences per GPU × GPUs × accumulation steps

The three dials
DialLimited byOur run
sequences per GPUactivation memory on one card32
GPUshow much hardware you have8
accumulation stepsnothing but time1
global batch256

Accumulation steps are repeats of the forward and backward pass before the weights are updated, used when the desired batch is larger than what fits in memory at once. Gradients from each repeat are added up, and only then is the update applied.

accumulation steps = 4, so the optimizer sees 1,024 sequences fwd + bwdfwd + bwd fwd + bwdfwd + bwd update gradients accumulate across all four — no weights change until the end 32 × 8 × 4 = 1,024
Accumulation buys batch size with time instead of memory. The weights sit untouched until the last repeat finishes.

So the three dials trade against different resources. Sequences per GPU costs activation memory, GPUs cost hardware, accumulation costs wall-clock time. Any of them can be turned to reach a target global batch, and the optimizer cannot tell which one you used.

What data parallelism does not touch is the memory from the first page. Every one of those eight cards is still carrying the full sixteen bytes per weight, and seven of the eight copies are redundant. That is the next page.

BACKWhat multiplies