ZeRO Sharding
Data parallelism replicates the optimiser state N times for no reason. ZeRO shards it, then the gradients, then the parameters themselves.
Standing
Current standardPart of the default recipe. Present in most frontier models trained today, and the thing a new design departs from rather than argues for.
Stage 3 or an equivalent full shard is how large models are trained. The alternatives differ in packaging, not in principle.
judged as of 2026-09 · what the labels mean
Theory
Mixed-precision Adam holds, per parameter: an fp16 weight and gradient (2 + 2 bytes) plus fp32 weight, momentum and variance (12 bytes) — sixteen bytes where the model itself needs two. Replicating that across ranks wastes bytes.
Stages 1 and 2 keep the communication volume of plain data parallelism: a reduce-scatter of gradients plus an all-gather of updated weights is exactly one all-reduce in disguise. Stage 3 additionally all-gathers each layer’s parameters immediately before use and frees them after, adding one further of traffic per step.
Implementation
import torch
from torch.distributed.fsdp import fully_shard, MixedPrecisionPolicy
policy = MixedPrecisionPolicy(
param_dtype=torch.bfloat16,
reduce_dtype=torch.float32, # reduce grads in fp32
)
# Shard each block separately so parameters are gathered
# per-block and freed again, not held for the whole model.
for block in model.blocks:
fully_shard(block, mp_policy=policy)
fully_shard(model, mp_policy=policy)Reducing gradients in bf16 to save bandwidth is a false economy at scale: the
reduction is a sum over ranks, and bf16 has eight mantissa bits. Keep
reduce_dtype at fp32. Wrapping only the top-level model rather than each block
is the other common mistake — it collapses stage 3 back into a single enormous
all-gather.