Data Parallelism › The All-Reduce Operation
Language AI HandbookAll chapters Data Parallelism › The All-Reduce OperationOne section · Sections in this chapter4 / 12 ↓
Reading tools Definitions & inline links
Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.
Article links
Make inline references clickable
All-reduce is the communication primitive at the heart of DDP. Understanding how it works explains both why DDP is efficient and what its scaling limits are. All-reduce is not a single algorithm but a family of algorithms with different performance characteristics. Choosing the right one for your hardware topology can make a substantial difference in training speed.
The Reduce-Broadcast Baseline
The simplest correct all-reduce is a two-step reduce-broadcast:
- One designated root rank aggregates all tensors from all other ranks (reduce to root)
- The root broadcasts the result to all other ranks
This approach has the same parameter server bottleneck problem we described earlier. The root rank must receive data from other ranks (inbound traffic bytes) and send data to ranks (outbound traffic bytes). The root's required bandwidth scales linearly with . For large , this approach is impractical.
Ring All-Reduce
The standard solution is ring all-reduce, popularized by Baidu Research (Gibiansky, 2017) for deep learning. In ring all-reduce, the ranks are arranged in a logical ring topology. The algorithm has two phases, each consisting of communication steps.
Phase 1: Reduce-Scatter
In the reduce-scatter phase, each rank splits its gradient tensor into equal chunks: . Over communication steps:
- Each rank sends one chunk to its right neighbor in the ring
- Each rank receives one chunk from its left neighbor and adds it to its local copy of that chunk
After steps, each rank holds one chunk that contains the sum of that chunk across all ranks. Specifically, rank holds , the fully summed version of chunk .
Phase 2: AllGather
In the all-gather phase, each rank sends its fully-summed chunk to its right neighbor over steps. By the end:
- Every rank holds every chunk of the fully summed gradient
- The complete synchronized gradient is on every rank
The total data transferred by each rank across both phases is:
where:
- is the total size of the gradient tensor in bytes
- approaches 1 as grows, so each rank transfers approximately bytes regardless of the number of GPUs
- The factor of 2 accounts for both phases: one reduce-scatter send and one all-gather send, each of approximately bytes total
The defining property of ring all-reduce is that the per-rank communication volume is independent of . Adding more GPUs does not increase the amount of data each GPU must send or receive. This is what makes ring all-reduce bandwidth-optimal: it achieves the theoretical minimum data transfer for the all-reduce problem.
To understand why this is remarkable, compare it to the naive reduce-broadcast: a single root rank must send and receive approximately bytes, which grows linearly with . Ring all-reduce eliminates this growth by distributing the aggregation work evenly.


Tree All-Reduce
Ring all-reduce is optimal for large messages where bandwidth is the bottleneck. For small messages (small models, small gradient tensors), the latency of communication steps becomes significant even if each step transfers little data. In this regime, a tree topology performs better.
In a binary tree all-reduce, ranks are organized as a binary tree. The reduce phase propagates data up the tree from leaves to root, with each internal node summing the values it receives from its children. The broadcast phase propagates the result back down from root to leaves. The total number of communication steps is rather than steps, which is dramatically fewer for large .
The tradeoff is bandwidth: the root of the tree must process and retransmit times as much data as leaf nodes, creating mild hotspots. For the large gradient tensors typical in language model training, ring all-reduce generally wins on throughput because bandwidth, not latency, is the bottleneck. For very small tensors (such as bias gradients in individual layers), tree-based all-reduce can be faster.
NCCL and Hardware Topology
In practice, PyTorch uses NVIDIA Collective Communications Library (NCCL) rather than implementing ring all-reduce directly in Python or CUDA. NCCL is topology-aware: it detects whether GPUs are on the same PCIe bus, connected via NVLink, or spread across multiple nodes connected by InfiniBand or RoCE, and chooses the optimal communication algorithm for each case. NCCL also handles buffer management, stream synchronization, and error recovery, all of which are tedious to implement correctly.
NVLink (the high-bandwidth GPU interconnect available on NVIDIA A100 and H100 servers) provides roughly 600 GB/s aggregate bidirectional bandwidth on modern 8-GPU nodes, compared to roughly 32 GB/s for PCIe. For multi-node training, InfiniBand HDR provides roughly 200 Gb/s per link (about 25 GB/s). The bandwidth difference between NVLink and InfiniBand is enormous: NVLink is roughly 24 times faster per GPU. This means that gradient communication that takes 20 ms on NVLink takes nearly 500 ms on InfiniBand, completely dominating compute time.
The topology distinction is particularly important for multi-node training. Within a single node with 8 GPUs connected via NVLink, NCCL uses a ring or tree topology that fully exploits the high NVLink bandwidth. Across nodes, NCCL routes traffic through the node's InfiniBand host channel adapter (HCA), which has far lower bandwidth per GPU than NVLink. A typical multi-node DDP job therefore has a two-level communication hierarchy: intranode communication using the fast NVLink fabric, and internode communication using the slower InfiniBand fabric.
Understanding this hierarchy helps you make informed decisions about how to partition GPUs. If you have a cluster of 8-GPU nodes, it is almost always better to fill entire nodes before spreading to additional nodes. Keeping communication within a single node maximizes the use of NVLink and minimizes InfiniBand traffic. Once you must cross nodes, you want to keep the cross-node gradient transfers as small as possible, which is one motivation for combining DDP with ZeRO (which reduces the gradient tensor that must be communicated across nodes).
PyTorch's dist.init_process_group supports multiple backends. NCCL is the correct choice for GPU training: it is tightly integrated with NVIDIA hardware and provides the best performance. Gloo is the alternative backend that runs on CPU and works across platforms including macOS and Windows. Gloo is useful for debugging and for single-machine multi-process experiments where GPU communication is unavailable. MPI is a third option for clusters that have MPI already configured, but NCCL is generally preferred for pure GPU training. When you see code examples using "gloo", that is always for portability or demonstration, not for production performance.