M12 · Model deployment, serving, and optimization12-0425 min read
Lesson 87 of 106 · Module 13 of 14 · Week 6
Threads:The measurement threadThe infrastructure threadThe efficiency thread
Distributed Training: Data vs Tensor vs Pipeline Parallelism, AllReduce, and NCCL
Distributed training splits a training job across GPUs in one of three ways: data parallelism replicates the whole model on every GPU and splits the batch, tensor parallelism splits individual layers across GPUs, and pipeline parallelism assigns different layers to different GPUs. Data parallelism requires that every replica's gradients be averaged into one identical update, which is what the AllReduce collective does — and NCCL is NVIDIA's library that implements AllReduce and the other collectives efficiently over NVLink, PCIe, and InfiniBand.
What distributed training is and why gradients must be synchronized
A single training step has four phases: forward pass, loss computation, backward pass producing gradients, and an optimizer step applying those gradients to the weights. On one GPU this is straightforward. On N GPUs, phase four becomes a problem.
Suppose you have 4 GPUs and a batch of 128 examples. Data parallelism gives each GPU 32 examples. Each GPU runs a forward and backward pass and ends up holding a gradient tensor — the same shape as the model's parameters — computed from its own 32 examples. Those four gradient tensors are all different, because they came from different data.
If each GPU now applies its own gradient to its own copy of the weights, you have created four divergent models. After one step they differ slightly; after a thousand steps they are four unrelated fine-tunes, and there is no meaningful checkpoint to save. The training run has silently turned into four smaller, worse training runs.
The fix is to make every GPU apply the same update. Since all four gradients are unbiased estimates of the gradient over the full 128-example batch, the correct combined estimate is their average. So before the optimizer step, every GPU must obtain the average of all four gradient tensors. That is precisely the operation AllReduce provides: every participant contributes a tensor, and every participant receives the reduced result. After AllReduce, all four GPUs hold identical averaged gradients, apply identical updates, and remain bit-identical replicas of one model.
This gives you the single sentence to remember: data-parallel training is mathematically equivalent to single-GPU training on the full batch, and AllReduce is what makes that equivalence true.
The corollary is the one that bites in practice. Adding GPUs under data parallelism does not just make training faster; it increases the effective batch size:
effective batch size = per_device_batch × number_of_devices × gradient_accumulation_steps
Change the GPU count and you have changed a hyperparameter. The learning rate that was tuned for the old effective batch is no longer the right one, which is why "we added GPUs and the loss curve changed" is a routine and entirely explicable event — a fact 12-03 needs and this lesson supplies.
How the three parallelism strategies and the collectives work
L1 — Intuition: three ways to split, three different constraints
Ask what is running out and the answer names the strategy.
- Time is running out. The model fits on one GPU; you just want to get through more data per second. → Data parallelism. Replicate the model, split the batch.
- Memory is running out because one layer is too big. A single weight matrix or attention block cannot fit. → Tensor parallelism. Split the matrix itself across GPUs, keep them tightly coupled.
- Memory is running out because there are too many layers. Any individual layer fits, but the stack does not. → Pipeline parallelism. Put layers 1–8 on GPU 0, 9–16 on GPU 1, and so on.
These are not mutually exclusive. Large-scale pretraining routinely combines all three — often described as 3D parallelism — plus optimizer-state sharding. That composition is beyond this exam's depth ceiling; the three identities are not.
L2 — Mechanism: what each strategy moves across the wire
Data parallelism. Every GPU holds the full model, the full optimizer state, and a slice of the batch. Communication happens once per step (or overlapped with the backward pass), and the volume is proportional to the parameter count — you are exchanging a full gradient tensor. Scaling is excellent as long as compute per step is large relative to that exchange. The memory cost is the catch: every GPU pays the full weights + gradients + optimizer state bill computed in 11-04. Four GPUs give you 4× the throughput and 1× the model capacity.
Tensor parallelism (also called intra-layer or model parallelism). A weight matrix is partitioned — for example, a feed-forward projection split column-wise across two GPUs — so each GPU computes a partial result on the same input, and a collective combines the partials before the layer's output is complete. Communication happens multiple times per layer, inside the forward and backward passes, and it is latency-sensitive. That is why tensor parallelism is normally confined to GPUs inside a single node connected by high-bandwidth NVLink, and rarely stretched across a network. It reduces per-GPU memory for weights, activations, and optimizer state proportionally.
Pipeline parallelism (inter-layer). The layer stack is cut into stages, one per GPU, and activations are passed from stage to stage. Communication volume is small — only the activations at the stage boundaries — but the naive version wastes most of the hardware: while GPU 0 works on the batch, GPUs 1–3 wait, and that idle time is the pipeline bubble. The standard remedy is micro-batching: split each batch into micro-batches and keep them in flight simultaneously so every stage is busy on a different micro-batch. More micro-batches means a smaller bubble and more in-flight activations to store.
| Data parallelism | Tensor parallelism | Pipeline parallelism | |
|---|---|---|---|
| What is split | The batch | Individual layers / weight matrices | The layer stack into stages |
| Each GPU holds | The whole model | A shard of every layer it participates in | A subset of layers, complete |
| Solves | Throughput | A single layer too large for one GPU | Too many layers for one GPU |
| Per-GPU memory for weights | Unchanged (full copy) | Reduced | Reduced |
| Communication frequency | Once per step (overlappable) | Several times per layer | Once per stage boundary |
| Communication volume | Proportional to parameter count | Moderate but very frequent | Small (activations only) |
| Interconnect sensitivity | Moderate | High — prefers intra-node NVLink | Lower — tolerates slower links |
| Signature inefficiency | Communication overhead at large scale | Frequent synchronization stalls | The pipeline bubble |
| Primary collective | AllReduce | AllReduce / ReduceScatter / AllGather within the layer | Point-to-point send/recv |
L3 — Collectives, ring-allreduce, and NCCL
A collective operation is a communication pattern involving a whole group of participants at once, as opposed to a point-to-point send between two. The ones worth knowing by name:
| Collective | What it does | Where it shows up |
|---|---|---|
| AllReduce | Every rank contributes a tensor; all ranks receive the reduced (usually summed or averaged) result | Gradient synchronization in data parallelism — the central one |
| Reduce | Every rank contributes; one rank receives the result | Aggregating metrics to rank 0 for logging |
| Broadcast | One rank's tensor is copied to all ranks | Distributing the initial weights so all replicas start identical |
| AllGather | Every rank contributes a shard; all ranks receive the full concatenation | Reassembling sharded weights or tensor-parallel outputs |
| ReduceScatter | Reduce across ranks, then each rank keeps only its shard of the result | Half of a sharded-optimizer step; also half of ring-allreduce |
| AllToAll | Every rank sends a distinct piece to every other rank | Mixture-of-experts routing |
| Barrier | All ranks wait until every rank arrives | Synchronization points, checkpointing |
Two identities are worth internalizing: AllReduce = ReduceScatter followed by AllGather, and Broadcast is what makes all replicas identical at step 0 while AllReduce is what keeps them identical at every step after.
Why ring-allreduce matters. The naive implementation of AllReduce sends every rank's tensor to one central rank, which sums and sends the result back. That central rank's link becomes a bottleneck whose traffic grows linearly with the number of participants — a design that stops scaling almost immediately.
Ring-allreduce arranges the N GPUs in a logical ring, each talking only to its neighbour, and runs two phases:
- Scatter-reduce. Each rank's tensor is conceptually divided into N chunks. Over N−1 steps, each rank sends one chunk to its right neighbour and reduces the chunk it receives from its left. At the end, each rank holds one fully-reduced chunk — a different one per rank.
- All-gather. Over another N−1 steps, those fully-reduced chunks are passed around the ring until every rank holds every chunk.
The properties that make this the standard algorithm: each rank sends and receives roughly 2 × tensor_size × (N−1)/N bytes, which approaches a constant 2× the tensor size regardless of how many GPUs participate; all links are used simultaneously rather than converging on one hub; and there is no central coordinator. The scaling behaviour is why ring-allreduce, or a bandwidth-optimal variant of it, is the algorithm behind essentially every large data-parallel training job.
NCCL (the NVIDIA Collective Communications Library, pronounced "nickel") is NVIDIA's implementation of these collectives for NVIDIA GPUs. Its identity, which is what the exam wants:
- It provides AllReduce, Broadcast, Reduce, AllGather, ReduceScatter, AllToAll and point-to-point primitives, topology-aware and optimized for NVIDIA interconnects.
- It works within a node over NVLink/NVSwitch or PCIe and across nodes over InfiniBand or Ethernet (RDMA where available).
- It is what PyTorch's
DistributedDataParalleland the distributed backends of the major frameworks call underneath when the backend is set tonccl. You almost never write NCCL calls yourself; you select it as a backend. - It is a communication library for multi-GPU/multi-node collectives — it is not a training framework, not a scheduler, and not a serving component. Distractors love to describe NCCL as a training library or a model-parallel framework. It is neither.
Gradient accumulation is the technique adjacent to all of this and frequently confused with it. Instead of synchronizing after every micro-batch, you run several forward/backward passes, accumulating gradients into the same buffers, and only then AllReduce and step. This raises the effective batch size without more GPUs and without more memory for activations beyond one micro-batch. Its two uses: reaching a large effective batch on limited hardware, and reducing communication frequency. It is a memory/throughput trick, not a parallelism strategy — there is nothing distributed about it, and it works perfectly well on one GPU.
Checkpointing is worth distinguishing carefully, because the word means two different things:
| Term | Meaning |
|---|---|
| Checkpointing (fault tolerance) | Periodically saving weights and optimizer state to durable storage so a run can resume after a failure. Essential in long multi-node runs, where a single node failure would otherwise cost the whole job |
| Activation / gradient checkpointing (memory) | Discarding intermediate activations during the forward pass and recomputing them during the backward pass, trading extra compute for much lower activation memory |
Both appear in distributed-training discussions and they solve unrelated problems. Confusing them is a common error.
Data vs tensor vs pipeline parallelism: the confusable table
The blueprint names data-versus-tensor parallelism as a confusable pair, so this is the table to memorize.
| Question asked | Answer |
|---|---|
| Which strategy replicates the entire model on every GPU? | Data parallelism |
| Which strategy splits a single weight matrix across GPUs? | Tensor parallelism |
| Which strategy puts different layers on different GPUs? | Pipeline parallelism |
| Which strategy does not reduce per-GPU model memory? | Data parallelism |
| Which strategy requires gradient synchronization via AllReduce? | Data parallelism |
| Which strategy is most sensitive to interconnect latency? | Tensor parallelism |
| Which strategy suffers from a "bubble"? | Pipeline parallelism |
| Which strategy is mitigated by micro-batching? | Pipeline parallelism |
| Which strategy would you use first, for a model that fits on one GPU? | Data parallelism |
| Which strategy is chosen because the model itself is too large? | Tensor and/or pipeline parallelism (collectively: model parallelism) |
| Which increases the effective batch size as you add GPUs? | Data parallelism |
| Which library implements the collectives on NVIDIA GPUs? | NCCL |
The umbrella-term trap: "model parallelism" is the umbrella covering tensor and pipeline parallelism — both split the model rather than the batch. An answer option offering "model parallelism" alongside "tensor parallelism" and "pipeline parallelism" is offering a category and two of its members, and the correct pick depends on how specific the question's constraint is.
Worked example: scaling one fine-tune from one GPU to eight
A constructed scenario, all figures derived from the stated assumptions. You are fine-tuning a 7B model. On a single GPU you have established: per-device batch 8, gradient accumulation 2, one step takes 1.0 second of compute, and the dataset is 40,000 examples for one epoch.
Step 1 — the single-GPU baseline.
effective batch = 8 × 1 GPU × 2 accumulation = 16 examples/step
steps per epoch = 40,000 / 16 = 2,500 steps
wall-clock = 2,500 × 1.0 s = 2,500 s ≈ 41.7 minutes
Step 2 — eight GPUs, data parallel, nothing else changed.
effective batch = 8 × 8 GPUs × 2 = 128 examples/step
steps per epoch = 40,000 / 128 ≈ 313 steps
compute per step = 1.0 s (unchanged — each GPU still does 8×2 examples)
Ignoring communication, one epoch now takes 313 s ≈ 5.2 minutes: an 8× speedup. But two things changed that you must account for.
Step 3 — the communication cost. Each step requires an AllReduce over the full gradient tensor. At BF16, gradients for 7.0 × 10⁹ parameters are 14.0 × 10⁹ bytes. Ring-allreduce moves approximately 2 × size × (N−1)/N bytes per rank:
per-rank traffic = 2 × 14.0e9 × (7/8) = 24.5e9 bytes ≈ 24.5 GB per step
Whether that is negligible or catastrophic depends entirely on the interconnect, and the arithmetic is a ratio: divide 24.5 GB by the achievable per-rank bandwidth. Over a fast intra-node link the transfer is a fraction of the 1.0 s compute and, because gradient AllReduce can be overlapped with the backward pass — each layer's gradients are ready before the layer below finishes, so you can start reducing them immediately — most of it disappears behind compute. Over a slow link it dominates and your 8× becomes 3×. I am deliberately not quoting bandwidth numbers for specific hardware: those are spec-sheet figures, they are generation-dependent, and the exam does not ask for them. What the exam asks is which strategy is bandwidth-sensitive and why, and the formula above is the why.
Step 4 — the hyperparameter you silently changed. Effective batch went from 16 to 128, an 8× increase. A larger batch produces a lower-variance gradient estimate, which generally supports a larger learning rate. Two conventional heuristics exist — scale the LR linearly with batch size, or scale it with the square root — and neither is a law. What is not optional is noticing: if you keep the old LR, the run will underfit relative to what the hardware could achieve, and if you scale aggressively without warmup you may destabilize the early steps. Add or lengthen warmup when you scale up the batch, and expect to re-read the loss curve with 12-03 in hand.
Step 5 — the alternative that needs no extra GPUs. If you wanted effective batch 128 on your single GPU, gradient accumulation gets you there: 8 × 1 × 16 = 128. Same effective batch, same gradient quality, 16× the wall-clock. Gradient accumulation buys batch size with time; data parallelism buys it with hardware. Recognizing that they are interchangeable in their effect on the math and opposite in their effect on the clock is the useful insight.
Step 6 — when this plan fails entirely. Data parallelism requires the model, its gradients, and its optimizer state to fit on one GPU. From 11-04's arithmetic, full fine-tuning a 7B model with Adam at mixed precision needs roughly 16 bytes per parameter — about 112 GB — before activations. No single current GPU holds that. So the realistic options are: use LoRA so the trainable parameter count collapses and data parallelism becomes viable (11-05), shard the optimizer state across the data-parallel ranks, or introduce tensor and pipeline parallelism. The decision about parallelism is downstream of the memory arithmetic, not a substitute for it.
Decision table: which parallelism, and which collective
| Constraint you actually have | Strategy | Notes |
|---|---|---|
| Model fits on one GPU; training takes too long | Data parallelism | The default. AllReduce per step, overlappable with backward |
| Model fits, training takes too long, interconnect is slow | Data parallelism + gradient accumulation | Accumulating reduces AllReduce frequency per example processed |
| Model fits, but you want a bigger effective batch and have one GPU | Gradient accumulation only | No distribution needed at all |
| A single layer does not fit on one GPU | Tensor parallelism | Keep it inside one node; it is latency-bound |
| The layer stack does not fit, individual layers do | Pipeline parallelism | Use micro-batching to shrink the bubble |
| Very large pretraining across many nodes | Combined data + tensor + pipeline | Beyond this exam's depth; know that it composes |
| Optimizer state is the binding memory constraint | Shard optimizer state across data-parallel ranks | Reduces the per-GPU optimizer bill; adds AllGather/ReduceScatter traffic |
| Activation memory is the binding constraint | Activation checkpointing | Recompute activations in the backward pass; trades compute for memory |
| A long multi-node run keeps dying on node failures | Checkpoint to durable storage on a schedule | Different meaning of "checkpointing" — fault tolerance, not memory |
| You need gradients averaged across ranks | AllReduce | The one collective to know cold |
| You need all ranks to start from the same weights | Broadcast | From rank 0 at initialization |
| You need one rank to collect metrics for logging | Reduce | Only rank 0 needs the answer |
| You need sharded tensors reassembled | AllGather | The second half of ring-allreduce |
| You are on NVIDIA GPUs and need any of the above | NCCL as the backend | Topology-aware, intra- and inter-node |
Why distributed training and NCCL are on the NCA-GENL exam
Distributed training is claimed by objectives 4.1 (assist in deployment and evaluation of model scalability, performance, and reliability) and 4.4 (identify system data, hardware, or software components required to meet user needs). More decisively, the official study guide's suggested-reading list names NCCL, AllReduce, and ring-allreduce explicitly — a reading the guide itself asks candidates to do, which makes these terms directly examinable. The course index rates this topic Tier 3 for frequency, so the correct study posture is recognition and identity, not configuration mastery.
There is also a stack-map dimension. NCCL is one of the NVIDIA components whose purpose you should be able to state in one clause: NCCL = multi-GPU and multi-node collective communication. When the exam presents a scenario and asks which NVIDIA component addresses it, the discriminating skill is knowing that NCCL communicates, TensorRT-LLM optimizes, Triton serves, NIM packages, NeMo builds, and RAPIDS processes data — the map 12-13 assembles in full.
Question phrasings:
- "Which operation synchronizes gradients across GPUs in data-parallel training?" — AllReduce.
- "What is NCCL used for?" — optimized collective communication primitives for multi-GPU and multi-node NVIDIA deployments.
- "A model is too large to fit on a single GPU. Which approach addresses this?" — model parallelism (tensor or pipeline), not data parallelism.
- "Why is ring-allreduce preferred over a centralized reduction?" — per-rank communication is independent of the number of GPUs and all links are used, so it scales.
- "What is the effect of adding GPUs under data parallelism, holding per-device batch constant?" — the effective batch size increases proportionally.
- "Which technique increases effective batch size without additional GPUs?" — gradient accumulation.
- "Which parallelism strategy is most affected by the pipeline bubble?" — pipeline parallelism.
Distractor families:
| Distractor | Why it is wrong |
|---|---|
| "Data parallelism lets you train a model too large for one GPU" | Data parallelism replicates the model, so per-GPU model memory is unchanged. It is the wrong tool for a capacity problem |
| "NCCL is a distributed training framework" | NCCL is a communication library. The framework (PyTorch DDP and equivalents) calls it |
| "AllReduce sends every gradient to a parameter server" | That describes a centralized parameter-server pattern, not AllReduce. AllReduce is peer-to-peer with every rank receiving the result |
| "Broadcast synchronizes gradients" | Broadcast copies one rank's tensor to all. Gradient synchronization needs a reduction |
| "Tensor and pipeline parallelism are the same thing" | Tensor splits within a layer; pipeline splits between layers |
| "Gradient accumulation is a form of data parallelism" | It works on a single GPU and involves no communication |
| "Activation checkpointing protects against node failure" | That is fault-tolerance checkpointing. Activation checkpointing recomputes activations to save memory |
| "Adding GPUs never changes hyperparameters" | It changes the effective batch size, which changes the appropriate learning rate |
Common mistakes with distributed training
| Mistake | Symptom | Cause | Fix |
|---|---|---|---|
| Reaching for data parallelism to fit a too-large model | Out-of-memory on every rank simultaneously | Data parallelism replicates rather than shards the model | Use LoRA, optimizer sharding, or tensor/pipeline parallelism |
| Not re-tuning the learning rate after scaling GPUs | Loss curve worse than the single-GPU run, or unstable early steps | Effective batch changed by the GPU-count factor | Record effective batch as a first-class hyperparameter; add warmup; re-tune LR |
| Comparing throughput without accounting for communication | Predicted 8× speedup, measured 3× | AllReduce traffic not overlapped or interconnect-limited | Enable gradient/backward overlap; consider gradient accumulation to reduce sync frequency; measure |
| Stretching tensor parallelism across nodes | Severe slowdown, GPUs mostly idle | Tensor parallelism synchronizes many times per layer and is latency-bound | Keep tensor-parallel groups within a node; use pipeline or data parallelism across nodes |
| Pipeline parallelism with one micro-batch | Most GPUs idle most of the time | The pipeline bubble is at its maximum | Split into many micro-batches |
| Logging one rank's local loss and reading it as global | Noisier curve than expected; misleading comparisons | Loss not reduced across ranks | Reduce the loss to rank 0 for logging, or state clearly that it is local |
| No durable checkpointing on a long multi-node run | A single node failure loses days of work | Fault tolerance not configured | Checkpoint weights and optimizer state on a schedule; test the resume path |
| Different random seeds or data order across replicas without care | Replicas process overlapping or duplicated data | Sampler not distributed-aware | Use a distributed sampler so each rank sees a disjoint shard of each epoch |
| Confusing the two meanings of "checkpointing" | An engineer enables one thing while a reviewer expects another | The word is overloaded | Say "activation checkpointing" or "fault-tolerance checkpointing" explicitly |
| Assuming replicas stay in sync without AllReduce | Divergent models; no meaningful artifact to save | Gradient synchronization missing or disabled | This is the core invariant: identical gradients → identical updates → identical replicas |
What is AllReduce in distributed training?
AllReduce is a collective communication operation in which every participant contributes a tensor and every participant receives the combined result — typically the sum, from which an average is derived by dividing by the participant count. In data-parallel training each GPU computes gradients from a different slice of the batch, so the gradients differ; AllReduce averages them so that every GPU applies an identical update and the replicas remain identical copies of one model. Without it, data-parallel training degenerates into N divergent training runs with no coherent checkpoint. AllReduce is distinguished from Reduce, where only one rank receives the result, and from Broadcast, where one rank's tensor is copied out to all. It is also decomposable: AllReduce equals a ReduceScatter followed by an AllGather, which is exactly how the ring implementation is structured.
What is NCCL and do I need to write NCCL code?
NCCL, the NVIDIA Collective Communications Library, is NVIDIA's topology-aware implementation of collective communication primitives — AllReduce, Broadcast, Reduce, AllGather, ReduceScatter, AllToAll, and point-to-point sends — for NVIDIA GPUs. It is optimized for the interconnects those GPUs actually use: NVLink and NVSwitch inside a node, PCIe where NVLink is absent, and InfiniBand or Ethernet with RDMA across nodes. In practice you do not write NCCL code. You select it as the communication backend in your training framework and the framework issues the collective calls on your behalf. The exam-relevant identity is one clause: NCCL is the multi-GPU and multi-node collective communication library — not a training framework, not a scheduler, and nothing to do with serving.
Why is ring-allreduce better than a centralized reduction?
Because its per-participant communication cost does not grow with the number of participants. In a centralized scheme every rank sends its full gradient tensor to one coordinator, so that coordinator's link carries traffic proportional to N and becomes the bottleneck as soon as N is more than a handful. Ring-allreduce arranges ranks in a ring and moves data only between neighbours, in two phases — scatter-reduce, then all-gather — each of N−1 steps. Every rank sends and receives about 2 × tensor_size × (N−1)/N bytes, which tends to a constant 2× the tensor size no matter how many GPUs join, and every link in the ring is active at once rather than idle while one hub saturates. There is also no coordinator to fail or to be provisioned specially. Those scaling properties are why ring-allreduce and its bandwidth-optimal relatives underpin large-scale data-parallel training.
What is the difference between data parallelism and tensor parallelism?
Data parallelism splits the batch; tensor parallelism splits the model's layers. Under data parallelism every GPU holds a complete copy of the model and processes different examples, then the gradients are averaged with AllReduce; per-GPU memory for weights and optimizer state is unchanged, so the model must already fit on one GPU. Under tensor parallelism a single weight matrix is partitioned across GPUs, each computing a partial result on the same input, with collectives combining the partials inside every layer; per-GPU memory drops proportionally, so a layer larger than one GPU becomes trainable. The consequences follow: data parallelism communicates once per step and tolerates slower interconnects, while tensor parallelism communicates many times per layer and needs high-bandwidth, low-latency links, which is why it is usually kept inside a single node. The decision rule is simply which resource ran out — time or memory.
Does gradient accumulation replace multiple GPUs?
It replaces them for the purpose of reaching a large effective batch size, and not at all for the purpose of finishing sooner. Gradient accumulation runs several forward and backward passes, summing gradients into the same buffers, and only applies the optimizer step after the last one. The resulting update is mathematically comparable to one computed on the combined batch, so it gives you the gradient quality of a large batch on hardware that cannot hold a large batch. What it does not give you is throughput: the passes run sequentially, so wall-clock time scales with the accumulation count. Its second, less obvious use is in distributed settings — accumulating for K micro-batches before synchronizing means one AllReduce per K micro-batches instead of one per micro-batch, which is a genuine remedy when the interconnect is the bottleneck.
Glossary recap: the distributed-training terms this lesson introduced
| Term | Definition |
|---|---|
| Data parallelism | Full model replicated per GPU, batch split across GPUs, gradients averaged by AllReduce |
| Tensor parallelism | A single layer's weight matrices split across GPUs; frequent intra-layer collectives; latency-sensitive |
| Pipeline parallelism | Different layers assigned to different GPUs as stages; activations passed between stages |
| Model parallelism | The umbrella term covering tensor and pipeline parallelism |
| Pipeline bubble | Idle stage time in pipeline parallelism, reduced by micro-batching |
| Micro-batching | Splitting a batch into smaller pieces kept in flight simultaneously to fill the pipeline |
| Collective operation | A communication pattern involving a whole group of ranks at once |
| AllReduce | All ranks contribute, all ranks receive the reduced result. Gradient synchronization |
| Reduce / Broadcast / AllGather / ReduceScatter / AllToAll | One receives / one sends to all / shards concatenated to all / reduce-then-shard / everyone sends distinct data to everyone |
| Ring-allreduce | Ring-topology AllReduce in scatter-reduce plus all-gather phases; per-rank traffic independent of GPU count |
| NCCL | NVIDIA Collective Communications Library — the collectives implementation for NVIDIA GPUs, intra- and inter-node |
| Rank / world size | A participant's index in the process group, and the total number of participants |
| Effective batch size | per_device_batch × devices × gradient_accumulation_steps |
| Gradient accumulation | Summing gradients over several passes before stepping; raises effective batch without more GPUs |
| Activation checkpointing | Discarding and recomputing activations to save memory |
| Fault-tolerance checkpointing | Periodically persisting weights and optimizer state so a long run can resume after a failure |
| Optimizer-state sharding | Splitting optimizer state across data-parallel ranks to cut per-GPU memory |
Key takeaways on distributed training, AllReduce, and NCCL
- Three strategies, three constraints: data parallelism for time, tensor parallelism for a layer too big, pipeline parallelism for a stack too deep.
- Data parallelism replicates the model, so it never solves a model-too-large problem. That is the single most-tested distinction here.
- Gradients from different data slices must be averaged into one identical update, or the replicas diverge into different models. AllReduce does that.
- AllReduce = every rank contributes, every rank receives. Reduce = one receives. Broadcast = one sends. AllReduce = ReduceScatter + AllGather.
- Ring-allreduce keeps per-rank traffic at roughly 2× the tensor size regardless of GPU count, and uses every link at once. That is why it scales.
- NCCL is the collective communication library for NVIDIA GPUs, intra- and inter-node. You select it as a backend; you do not write it.
- Adding GPUs under data parallelism multiplies the effective batch size, which is a hyperparameter change. Re-tune the learning rate and warmup.
- Gradient accumulation buys effective batch size with time rather than hardware, and also reduces AllReduce frequency.
- Tensor parallelism is latency-bound and belongs inside a node; pipeline parallelism tolerates slower links but pays a bubble.
- "Checkpointing" means two different things. Say activation checkpointing for memory and fault-tolerance checkpointing for durability.
Next: 12-05 crosses from training to serving, and it is the pivot of this entire module. Every optimization that follows — batching, PagedAttention, continuous batching, cost per token — depends on one mechanism: the KV cache, the reason an LLM generates tokens one at a time at all, and the reason single-request decoding is limited by memory bandwidth rather than arithmetic.