Roadmap / Distributed Training

✓

ZeRO Memory Arithmetic

easydistributedmemory

The problem

Before training a large model, you need to know whether it fits in GPU (graphics processing unit) memory, and with how many GPUs. You will compute it for the four stages of ZeRO (Zero Redundancy Optimizer).

With mixed-precision Adam, each parameter costs 16 bytes of model states:

  • 2 bytes for its weight in FP16 (16-bit floating point);
  • 2 bytes for its gradient in FP16;
  • 12 bytes of optimizer states in FP32 (32-bit floating point): a master copy of the weight, the momentum and the variance, 4 bytes each.

Plain data parallelism stores all of it on every GPU. ZeRO shards it: it cuts one more piece per stage into NN parts, one per GPU (Rajbhandari et al., 2020).

The four stages

Stage Sharded Bytes per GPU for Ψ\Psi parameters
0 nothing (plain data parallelism) 16Ψ16\Psi
1 optimizer states 4Ψ+12Ψ/N4\Psi + 12\Psi / N
2 + gradients 2Ψ+14Ψ/N2\Psi + 14\Psi / N
3 + weights 16Ψ/N16\Psi / N

where Ψ\Psi (psi) is the number of parameters and NN the number of GPUs. Each row adds the pieces that stay whole, at full size, to the pieces that are sharded, divided by NN. At stage 2, for example, only the 2 bytes of weights stay whole, and the other 2+12=142 + 12 = 14 bytes are sharded.

Example. Ψ=7×109\Psi = 7 \times 10^9 parameters on N=8N = 8 GPUs:

  • stage 0: 16⋅7×109=11216 \cdot 7 \times 10^9 = 112 GB (gigabytes) per GPU;
  • stage 1: 28+10.5=38.528 + 10.5 = 38.5 GB;
  • stage 2: 14+12.25=26.2514 + 12.25 = 26.25 GB;
  • stage 3: 112/8=14112 / 8 = 14 GB.

The other way round: the largest model that fits

Every row is Ψ\Psi times a number of bytes per parameter that depends only on NN and the stage: 1616, 4+12/N4 + 12/N, 2+14/N2 + 14/N, 16/N16/N. So the largest model that fits in a given memory is the memory divided by that number, rounded down.

Example. 80 GB per GPU and N=8N = 8:

  • stage 0: 80×109/16=5×10980 \times 10^9 / 16 = 5 \times 10^9 parameters;
  • stage 1: 80×109/5.5≈14.5×10980 \times 10^9 / 5.5 \approx 14.5 \times 10^9;
  • stage 3: 80×109/2=40×10980 \times 10^9 / 2 = 40 \times 10^9.

What to implement

  • model_state_bytes(n_params, n_gpus, stage): the bytes per GPU, for stage in {0, 1, 2, 3}. Raise ValueError for any other stage.
  • max_params(gpu_bytes, n_gpus, stage): the largest number of parameters, an int rounded down, whose model states fit in gpu_bytes per GPU. Activations are ignored here.

Hint

Write one helper that returns the bytes per parameter for a stage and NN, and use it in both functions.

solution.py
Python idle

Press Run (⌘/Ctrl + Enter) to test your code.