The problem
In data-parallel training, every GPU (graphics processing unit) computes gradients on its own part of the batch, and then all of them need the sum (or the mean) of everyone's gradients. That operation is an all-reduce. The ring algorithm does it with little network traffic: the workers sit in a circle, and each one only ever sends to its right neighbour. You will simulate it.
There are workers. Worker sends only to worker , where wraps around: the last worker sends to worker 0. Each worker's array is cut into chunks, and chunks[i][c] is chunk as held by worker .
Phase 1: reduce-scatter
steps. In step , every worker sends its chunk to worker , which adds it to its own chunk . Afterwards, worker holds the complete sum of chunk .
Phase 2: all-gather
more steps. In step , every worker sends its chunk to worker , which replaces its chunk with it. Afterwards every worker holds every complete chunk.
Example. Three workers with
[1, 2, 3],[10, 20, 30]and[100, 200, 300]: three chunks of one number each.
after worker 0 worker 1 worker 2 start [1, 2, 3][10, 20, 30][100, 200, 300]reduce-scatter [1, 2, 303][11, 20, 30][100, 220, 300]reduce-scatter [1, 222, 303][11, 20, 333][111, 220, 300]all-gather [111, 222, 303][11, 222, 333][111, 220, 333]all-gather [111, 222, 333][111, 222, 333][111, 222, 333]
- Reduce-scatter, : worker 0 sends chunk (the 1) to worker 1, which adds it (); worker 1 sends chunk 1 to worker 2 (); worker 2 sends chunk 2 to worker 0 ().
- Reduce-scatter, : worker 0 sends chunk , the , to worker 1, which now has the complete . Likewise worker 0 completes chunk 1 () and worker 2 chunk 0 (): each worker holds the complete chunk .
- All-gather: two steps copy the complete chunks around the ring, replacing the partial ones.
What to implement
reduce_scatter(chunks)andall_gather(chunks): the two phases. Each returns a new nested list and does not modify its input.ring_allreduce(arrays): split each worker's 1-D array withnp.array_split(a, N), run both phases, concatenate each worker's chunks. Return the list of results, each equal to the sum of all inputs.
Requirements
- works (no steps at all).
- Copy the arrays you receive as input before changing them.
Hint
On real hardware all the sends of a step happen at the same time. In the simulation, the safe way is to first collect every message of the step (destination, chunk index, a copy of the data), and only then apply them all. Check your indices against the table above.