Recap: why and how
Modern accelerators run BF16/FP16 multiplies 2-8x faster than FP32. Mixed precision keeps the model weights in FP32 (master copy) but does the heavy compute (matmuls) in lower precision. The result is faster training with the same final accuracy in 99% of cases.
BF16: same dynamic range as FP32, less precision; no GradScaler needed; preferred default in 2026. FP16: more precision, smaller dynamic range; needs GradScaler to handle small gradients without underflow.
What goes wrong when it goes wrong
NaN losses. The most common cause: a single underflow somewhere in the FP16 forward pass that propagates through the loss. Usually fixed by switching to BF16, or by adding a GradScaler if you're stuck with FP16.
Subtle accuracy degradation. Some operations (e.g. log-softmax, layer norm) are sensitive to lower precision. PyTorch autocast keeps these in FP32 automatically, but custom layers may not. If your model accuracy drops noticeably under autocast, profile which ops are running in low precision.
The numbers
BF16 training: 1.5-3x faster wall-clock vs FP32 on Tensor Cores, ~50% memory savings on activations. FP8 (H100 and newer) can give another 30-50% on top of that for transformer training, but the tooling is still maturing in 2026.