FP32 training is safe but slow and memory-hungry. Mixed precision runs most matmuls in float16 (or bfloat16) while keeping master weights in float32, often doubling throughput on modern GPUs with tensor cores.
PyTorch’s torch.cuda.amp (automatic mixed precision) wraps the training loop with autocast and GradScaler to prevent underflow.
scaler.unscale_. Module 6.3 dives deeper into FP16, BF16, and hardware.Learning Objectives
By the end of this lesson, students should be able to:
- Wrap forward pass in
torch.cuda.amp.autocast(). - Use
GradScalerfor scaled backward and optimizer steps. - Explain why float16 needs loss scaling to avoid gradient underflow.
- Choose float16 vs bfloat16 based on GPU generation.
- Combine AMP with gradient clipping correctly.
- Recognize layers that should stay in float32 (loss, softmax in some cases).
FP32 vs Mixed Precision
| Aspect | FP32 | Mixed (AMP) |
|---|---|---|
| Speed on Tensor Cores | Baseline | Often 1.5–2× faster |
| Memory | Higher | Lower activations |
| Numerical range | Wide | FP16 narrow; BF16 similar to FP32 exponent |
| Implementation | Default | autocast + GradScaler |
AMP Training Loop
autocast selects float16 for conv/linear ops; GradScaler multiplies loss before backward, then unscales gradients inside the optimizer step.
Validation in Mixed Precision
Inference can use autocast without GradScaler. Many teams validate in FP32 for metric stability on small validation sets.
scaler.update()After scaler.step(), always call scaler.update(). It adjusts loss scale when inf/NaN gradients appear. Omitting it freezes a bad scale and silently breaks training.
BFloat16 on Ampere and Newer
BF16 shares exponent range with FP32—often no GradScaler needed. Use autocast(dtype=torch.bfloat16) on A100/H100 class GPUs.
AMP speedups vary by model (attention-heavy vs MLP). Profile one epoch FP32 vs AMP on your hardware; confirm accuracy within tolerance.
Knowledge Check
- Short Answer: What does
autocastdo? Answer: Runs eligible ops in lower precision automatically. - True/False:
GradScaleris used during validation. Answer: False—only training backward needs scaling (FP16). - Multiple Choice: Gradients underflow in FP16 because: (a) range too small, (b) LR too low only, (c) no GPU. Answer: (a).
- Short Answer: Order after
scale(loss).backward()? Answer: unscale_, clip (optional), scaler.step, scaler.update. - Short Answer: BF16 advantage over FP16? Answer: Wider exponent range, often more stable without scaling.
- True/False: Master weights stay FP32 in standard AMP. Answer: True—optimizer updates FP32 copies.
- Multiple Choice: Tensor Cores accelerate: (a) mixed precision matmul, (b) data loading, (c) checkpoint I/O. Answer: (a).
- Short Answer: When is AMP disabled safely? Answer: CPU training or when
enabled=Falsein GradScaler/autocast. - Short Answer: Why clip after
unscale_? Answer: Clipping must use real gradient magnitudes. - Multiple Choice: Module 6.3 covers hardware details: (a) CPU vs GPU, (b) sklearn pipelines, (c) ETL. Answer: (a).
Key Takeaways
- AMP =
autocastforward +GradScalerbackward (for FP16). - Always
scaler.update()afterscaler.step(). - Consider BF16 on modern NVIDIA/TPU hardware for simpler training.
- Next: Distributed Training—scale across GPUs.
Hands-on idea: Measure images/sec and peak VRAM for ResNet-18 FP32 vs AMP on one GPU.
Discussion prompt: When would you refuse mixed precision (e.g. scientific simulation nets)?