skip to content

Search

← The Engine Room

Part II — Making Training Work (2014–2020)

Data Parallelism and Large Batches

Ring all-reduce, the linear scaling rule, and the gradient noise scale.

2017–2019 14 min read 3 papers

It is June 2017. ResNet-50 (owned by chapter 1) already trains on a single machine in a few days, but a few days per experiment means a few experiments per month, and every lab racing toward larger models wants more shots on goal. A Facebook team publishes a recipe for training the same network on 256 GPUs in one hour without losing accuracy, and a year and a half later an open-source library and a diagnostic statistic turn that recipe into a repeatable engineering discipline rather than a one-off stunt.

Where We Were

Splitting a single training run across more than one accelerator was not new by 2017. AlexNet (owned by chapter 2) had already split its layers across two GPUs in 2012 out of memory necessity, and by the mid-2010s it was routine to train on a handful of GPUs inside one server, connected by fast local interconnects. What was missing was a practical way to add the tenth GPU, or the hundredth — machines in different racks, connected by ordinary datacenter networking, coordinating on a single model.

The obstacle was communication, not compute. Every accelerator added to a training run also added an obligation: after each accelerator computed its slice of the gradient, all the slices had to be combined and every accelerator had to end the step with the same updated weights, or the model would drift into inconsistent replicas. The dominant pattern for this, inherited from earlier large-scale machine learning systems, was the parameter server: one or a few dedicated nodes that received gradients from every worker, summed them, and broadcast the update back out. As the number of workers grew, so did the traffic converging on those few nodes, and the server’s bandwidth — not the accelerators’ compute — became the limiting resource. Doubling the worker count did not halve the wall-clock time; it moved the bottleneck instead.

There was a second, subtler obstacle sitting underneath the first. Even with unlimited bandwidth, nobody had a principled rule for how to adjust the optimizer when the batch size grew by 10× or 100×. The optimizers in question were themselves recent: Adam (owned by chapter 5) had shipped in December 2014, and batch normalization (owned by chapter 6) in February 2015, both tuned and validated at the batch sizes of the day — typically 256 or fewer images. Simply feeding an optimizer a much larger batch without adjusting anything else tended to produce a network that trained fast in wall-clock terms but generalized worse, and nobody could say in advance where that trade-off would bite.

Six years turn "add more GPUs" from a leap of faith into a discipline Two 2018 papers answer the two halves of the same question within ten months of each other. Grey monospace text names the chapter or team behind each step. 2012 AlexNet Splits layers across 2 GPUs Chapter 2 2012 2014 Adam Ships in December Chapter 5 2014 2015 Batch normalization Ships in February Chapter 6 2015 Jun 2017 One-hour ImageNet 256 GPUs, linear scaling rule Goyal et al. Jun 2017 Feb 2018 Horovod Ring all-reduce replaces the parameter server Sergeev, Del Balso Feb 2018 Dec 2018 Gradient noise scale Measures when more GPUs stop helping McCandlish et al. Dec 2018 earlier chapter an optimizer or stabiliser fixes the statistics fixes the communication measures the ceiling
Six years turn distributed training from ad hoc GPU-splitting into two measured disciplines: fixing the statistics and fixing the communication. PNG ↓

The Breakthrough

Act one: the linear scaling rule. “Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour” (Goyal et al., 2017), submitted by a Facebook AI Research team in June 2017, attacked the optimizer half of the problem directly. The paper’s rule is stated in one sentence: “when the minibatch size is multiplied by k, multiply the learning rate by k,” holding every other hyperparameter — weight decay included — fixed. It is a hyperparameter-free prescription: no new tuning run is needed to find the right learning rate at a new batch size, because the rule derives it from the old one.

The rule alone was not sufficient. Applied naively from the first step of training, a learning rate scaled up 32× (to match a minibatch scaled from 256 to 8,192 images) was large enough to destabilize the network before it had learned anything. The paper’s second contribution was a warmup schedule: rather than jumping to the target learning rate immediately, gradually increase it from a small value over the first five epochs. A constant low-then-high warmup helped somewhat; a gradual, linear ramp helped more, and was the version the paper adopted. With gradual warmup and the linear scaling rule, a minibatch of 8,192 images spread across 256 GPUs matched the accuracy of the small-minibatch baseline — 23.60% top-1 error at minibatch 256 versus 23.74% at minibatch 8,192, a gap smaller than the run-to-run noise — and did so while training ResNet-50 on ImageNet in one hour instead of days. The paper also reported the edges of the recipe: results degraded past roughly 16,000 images per minibatch, and training diverged entirely beyond 64,000.

Act two: the communication layer. Getting 256 GPUs to agree on a gradient in the first place was the second half of the problem, and it was solved by treating the parameter server itself as the thing to remove. “Horovod: fast and easy distributed deep learning in TensorFlow” (Sergeev and Del Balso, 2018), submitted by a team at Uber in February 2018, replaced the server-centric topology with ring all-reduce: workers are arranged in a logical ring, and gradients are summed by passing partial sums around the ring rather than converging on a central node. Sergeev and Del Balso cite the earlier analysis by Patarasuk and Yuan showing this algorithm is bandwidth-optimal — for a large enough message, every worker’s incoming and outgoing traffic is the same regardless of how many workers are in the ring, so adding workers stops adding a communication tax. Horovod packaged this as a library that needed, in the authors’ words, only “a few lines of modification to user code,” turning a systems-engineering problem into an import statement.

The measured effect was the point. Standard distributed TensorFlow of the period, using the parameter-server pattern, delivered roughly 50% scaling efficiency at 128 GPUs — half the compute added was lost to communication. Horovod’s ring all-reduce reached 88% scaling efficiency on Inception V3 and ResNet-101 over a standard 25GbE TCP network at the same GPU counts, and over 90% on RDMA networking. Together, the linear scaling rule and ring all-reduce answered the two halves of the same question: how to keep the statistics of training correct as the batch grows, and how to keep the communication cheap as the worker count grows.

One topology converges on a node; the other never does A parameter server's incoming bandwidth is shared across every worker; a ring's per-worker cost stops rising once the ring is long enough. Coral double arrows are the parameter server's two-way traffic; sage arrows are the ring's one-way pass-along. PARAMETER SERVER RING ALL-REDUCE Parameter server all traffic converges here Worker 1 Worker 2 Worker 3 Worker 1 Worker 2 Worker 3 bandwidth shared across every worker per-worker cost independent of ring size
A parameter server's incoming bandwidth is shared across every worker; a ring's per-worker cost stops rising once the ring is long enough to hide the latency term. PNG ↓

The Mathematics

The linear scaling rule follows from comparing two ways of consuming the same data. Take kk small steps of batch size nn each, or one large step of batch size knkn:

wt+k=wt−η 1n∑j<k∑x∈Bj∇w l(x,wt+j)w^t+1=wt−η^ 1kn∑j<k∑x∈Bj∇w l(x,wt)\begin{aligned} w_{t+k} &= w_t - \eta \, \frac{1}{n} \sum_{j<k} \sum_{x \in B_j} \nabla_w \, l(x, w_{t+j}) \\ \hat{w}_{t+1} &= w_t - \hat{\eta} \, \frac{1}{kn} \sum_{j<k} \sum_{x \in B_j} \nabla_w \, l(x, w_t) \end{aligned}
SymbolMeaning
wtw_tModel weights at step tt
η\etaBaseline learning rate, small-batch
η^\hat{\eta}Scaled learning rate, large-batch
nnSmall-batch size
kkNumber of small steps folded into one big step
BjB_jThe jj-th minibatch of size nn
l(x,w)l(x, w)Per-example loss

Ring all-reduce’s communication cost, the property Horovod exploited, has a standard closed form as a function of worker count:

Tring(p)=2(p−1) α+2 p−1p MβT_{\mathrm{ring}}(p) = 2(p-1)\,\alpha + 2\,\frac{p-1}{p}\,\frac{M}{\beta}
SymbolMeaning
TringT_{\mathrm{ring}}Time to complete one all-reduce across the ring
ppNumber of workers in the ring
α\alphaFixed latency per network message
MMSize of the gradient buffer being reduced, in bytes
β\betaAchievable network bandwidth

Neither result says how large a batch should be — only how to train correctly at a given size and how to communicate cheaply while doing it. “An Empirical Model of Large-Batch Training” (McCandlish et al., 2018), submitted by OpenAI in December 2018, supplied the missing instrument: a single statistic, measurable during training, that predicts the batch size beyond which adding more data per step stops helping.

Bsimple=tr⁡(Σ(θ))∥G(θ)∥2,Σ(θ)=Ex∼ρ ⁣[∇θLx(θ) ∇θLx(θ)⊤]−G(θ)G(θ)⊤\mathcal{B}_{\mathrm{simple}} = \frac{\operatorname{tr}\big(\Sigma(\theta)\big)}{\lVert G(\theta) \rVert^2}, \qquad \Sigma(\theta) = \mathbb{E}_{x \sim \rho}\!\left[\nabla_\theta L_x(\theta)\,\nabla_\theta L_x(\theta)^{\top}\right] - G(\theta)G(\theta)^{\top}
SymbolMeaning
G(θ)G(\theta)True gradient of the loss at parameters θ\theta
Σ(θ)\Sigma(\theta)Covariance of per-example gradients around GG
Lx(θ)L_x(\theta)Loss on a single example xx
ρ\rhoData distribution examples are drawn from
tr⁡(⋅)\operatorname{tr}(\cdot)Trace, summing variance across all parameter dimensions
Bsimple\mathcal{B}_{\mathrm{simple}}The measurable noise-scale statistic
Bcrit\mathcal{B}_{\mathrm{crit}}The empirical critical batch size it predicts

The paper also defines a Hessian-weighted version of the same quantity, Bnoise=tr⁡(HΣ)/(G⊤HG)\mathcal{B}_{\mathrm{noise}} = \operatorname{tr}(H\Sigma) / (G^{\top} H G), which reduces to the simple form above when the loss curvature HH is well approximated by a scaled identity matrix — a condition close enough to true in practice that the simple version is the one used for measurement.

Critically, McCandlish et al. found the noise scale is not a fixed property of a model or dataset: it grows as training proceeds and the network gets more accurate, and it is larger for harder tasks. Measured across domains, both the noise scale and the critical batch size it predicts span many orders of magnitude:

TaskSimple noise scale (examples)Critical batch size (examples)
MNIST50–90020–200
SVHN300–4,00050–500
CIFAR-10400–2,000300–900
ImageNet4,000–30,0001,000–15,000
Billion Word (per token)1,000–150,000700–100,000
Atari (per frame)100–20,000100–8,000
Dota 1v1 (per frame)100,000–300,00050,000–3,000,000
Dota 5v5 (per frame)up to 24,000,000not measured

What It Enabled

The immediate effect was that “how many GPUs” stopped being an engineering leap of faith. Before Goyal et al. and Horovod, scaling a run past a handful of accelerators risked losing accuracy, communication overhead, or both, with no diagnostic to tell you which. After them, both failure modes had a fix — the linear scaling rule plus warmup for the first, ring all-reduce for the second — and the gradient noise scale gave a third answer: a number that told you when to stop adding workers before you started paying for hardware that made no difference.

ConfigurationGPUsScaling efficiencySource
Standard distributed TensorFlow, parameter server128~50%Sergeev and Del Balso, 2018
Horovod, ring all-reduce, TCP 25GbE12888%Sergeev and Del Balso, 2018
Horovod, ring all-reduce, RDMA128over 90%Sergeev and Del Balso, 2018
Goyal et al. distributed SGD, linear scaling + warmup8 to 256~90%Goyal et al., 2017

Ring all-reduce did not stay a Horovod-only technique. NVIDIA’s NCCL library implemented the same collective operation as a GPU-aware primitive, and PyTorch’s built-in DistributedDataParallel adopted ring all-reduce as its default gradient-synchronization strategy, making the pattern from this chapter the invisible default for essentially every multi-GPU training job that followed rather than an opt-in library. Data parallelism this chapter describes is only half of how a modern run is split, however — once a single model no longer fits on one accelerator regardless of batch size, the model itself has to be partitioned, which is the subject of chapter 9, splitting the model, and the memory accounting that decides when that partitioning becomes necessary is covered in chapter 10, ZeRO and the memory tricks. In practice, frontier training runs combine both — a topic taken up directly in chapter 11, training runs in practice.

The gradient noise scale’s longer legacy was conceptual as much as practical: it reframed batch size as something with a measurable ceiling rather than a hyperparameter to search over. That same instinct — that a resource has a knowable, fitted relationship to training outcomes rather than an empirically groped-for setting — is the premise the field generalized two years later into predicting loss itself from parameters, data, and compute, the subject of scaling laws. The connection is not incidental: the gradient noise scale is, in effect, a scaling law for the batch-size axis alone, published by three of the same authors — McCandlish, Kaplan, and Amodei — who wrote the language-model scaling laws paper thirteen months later. Both papers ask the same underlying question, “what is the exchange rate between more hardware and less wall-clock time,” and both answer it with a curve fitted to small, cheap experiments rather than a rule of thumb.

A library for one collective operation becomes the default nobody sees Ring all-reduce moves from an opt-in library to a hidden default, then two more axes of parallelism are layered on top of it. Grey monospace text is the year or chapter for each step. Ring all-reduce Horovod's communication 2018 NCCL GPU-native collectives vendor library PyTorch DDP Ring all-reduce becomes the default invisible by default Megatron-LM Tensor parallel splits the model 2019 ZeRO Shards optimizer state and gradients 2019 Combined 3D parallelism data, tensor, ZeRO together Frontier training runs at scale Chapter 11
Ring all-reduce stops being an opt-in library and becomes the invisible default, while two more axes of splitting the model and its state get layered on top. PNG ↓

Large-batch training also intersected with the hardware roadmap. Bigger batches only pay off if there is enough accelerator memory and interconnect bandwidth to hold and synchronize them, which is why the memory wall and the pace of GPU generations described in the co-evolution thesis set a practical ceiling on how far the linear scaling rule can be pushed before communication or memory, not statistics, becomes the binding constraint again.

Key Papers

PaperAuthorsYearLinkWhy it matters
Accurate, Large Minibatch SGD: Training ImageNet in 1 HourGoyal et al.2017arXiv:1706.02677Linear scaling rule plus warmup made large-batch training accuracy-preserving
Horovod: fast and easy distributed deep learning in TensorFlowSergeev and Del Balso2018arXiv:1802.05799Ring all-reduce replaced parameter servers as the default communication pattern
An Empirical Model of Large-Batch TrainingMcCandlish et al.2018arXiv:1812.06162Gradient noise scale predicts the batch size beyond which more workers stop helping

PM Lens

Papers referenced