The standard for multi-GPU
DistributedDataParallel (DDP) is the way to do multi-GPU training in PyTorch. The mental model: one process per GPU, each process has its own copy of the model and runs its own forward/backward on its slice of the data. After backward, the gradients are synchronized across processes (all-reduce); each optimizer step then applies the same averaged gradient to its local copy of the weights, keeping them in lockstep.
What you have to add to a single-GPU script
- Initialize a process group (
dist.init_process_group("nccl")). - Set the per-process device (
torch.cuda.set_device(rank)). - Wrap the model with DDP (
model = DDP(model, device_ids=[rank])). - Use a DistributedSampler so each process sees a different slice of the data.
- Launch with
torchrun(the modern launcher, not the oldtorch.distributed.launch).
The DistributedSampler gotcha
Without DistributedSampler, every process iterates the full dataset — you waste compute on redundant work. set_epoch(epoch) on the sampler at the top of each epoch is mandatory; without it, the shuffle is the same every epoch and your training plateaus mysteriously.
torchrun — the modern launcher
torchrun --nproc_per_node=4 train.py spawns four processes, each with environment variables (LOCAL_RANK, WORLD_SIZE, RANK) set so your script can self-identify. The old torch.distributed.launch still works but torchrun is preferred.