Numbers in hardware have finite precision. Choosing the right format trades off range, precision, memory, and speed.
Common formats:
| Format | Bits | Exponent | Mantissa | Range | Use |
|---|---|---|---|---|---|
| FP32 | 32 | 8 | 23 | Master weights, loss scaling | |
| FP16 | 16 | 5 | 10 | Training with loss scaling | |
| BF16 | 16 | 8 | 7 | Training default on modern GPUs | |
| FP8 (E4M3) | 8 | 4 | 3 | Forward pass in latest hardware | |
| INT8 | 8 | — | — | Post-training quantization | |
| INT4 | 4 | — | — | Aggressive inference quantization |
BF16 vs FP16: BF16 has the same exponent range as FP32 (no overflow issues) but less precision. FP16 has more precision but can overflow → requires loss scaling. BF16 is the standard for training.
Mixed-precision training:
- Keep FP32 master copy of weights
- Cast to BF16/FP16 for forward and backward pass (2x speed on Tensor Cores, half memory)
- Accumulate gradients in FP32
- Update master weights in FP32
Gradients must land in FP32 because BF16 has fine resolution near 0 (it can represent a tiny gradient like 0.0001) but cannot represent the updated weight (1.0001) — adding a small gradient to a large weight would be lost to rounding. Matmuls tolerate rounding noise, so BF16 forward/backward is fine.
# autocast: weights stay FP32, ops selectively run in BF16 (matmul) or FP32 (softmax, layernorm)
with torch.autocast(device_type='cuda', dtype=torch.bfloat16):
output = model(x)
# or load weights directly in BF16 (simplest, great for inference):
model = AutoModel.from_pretrained(name, torch_dtype=torch.bfloat16)
# 8-bit weights via bitsandbytes (weights INT8, activations FP16):
model = AutoModel.from_pretrained(name, load_in_8bit=True)Quantization for inference:
- Post-training quantization (PTQ) — quantize a trained model. Calibrate scale/zero-point on a small dataset
- Quantization-aware training (QAT) — simulate quantization during training via straight-through estimator
- GPTQ, AWQ, GGML — specialized LLM quantization methods
- Going from FP16 to INT4 → 4x memory reduction, enabling large models on consumer GPUs
Numerical pitfalls in ML:
- Subtracting nearly equal numbers → catastrophic cancellation
- Softmax overflow → subtract first (log-sum-exp trick)
- Gradient underflow in FP16 → dynamic loss scaling multiplies loss by a large factor, scales gradients back down after
See also: GPU Architecture and CUDA, Memory Hierarchy and IO-Awareness, LoRA