İçeriğe geç

Mixed Precision Mimarisi: bf16 vs fp16 vs fp8 — Niye RTX 4090'da Saf bf16?

fp16'nın loss scaling karmaşası, bf16'nın 'master fp32' örüntüsü, fp8 (Ada destekler, ama H100 native), TF32 matmul precision flag, autocast nuance'ları — RTX 4090 için cookbook'un kesin tercihi olarak saf bf16. NaN'ların maliyeti, training stability matematiği.

Şükrü Yusuf KAYA
30 dakikalık okuma
İleri
Mixed Precision Mimarisi: bf16 vs fp16 vs fp8 — Niye RTX 4090'da Saf bf16?
🎯 Karar netliği
RTX 4090 üzerinde cookbook'un seçimi saf bf16. `torch.bfloat16` her yerde — weights, activations, gradients. Master fp32 yok, loss scaling yok, autocast karmaşası yok. Bu ders niye bunun doğru karar olduğunu, istisnaları ne zaman olduğunu, fp8'in 4090'da niye prematür olduğunu açıklar.

1. Üç Format Karşılaştırması#

FormatBit yapısıRangePrecision (ulp)RTX 4090 destekUse case
fp321 + 8 + 23±3.4e381.2e-7nativemaster weights eski mixed precision
fp161 + 5 + 10±655049.8e-4native (V100+)eski training, GAN
bf161 + 8 + 7±3.4e387.8e-3native (Ampere+)LLM training default
fp8 (e4m3)1 + 4 + 3±4480.0625Ada (limited)LLM inference, H100 training
fp8 (e5m2)1 + 5 + 2±573440.125Ada (limited)LLM gradient
Key insight:
  • fp16 range küçük → büyük gradient'lar overflow → "loss scaling" gerekir
  • bf16 range fp32 ile aynı, sadece precision düşük → overflow yok, basit
  • fp8 range çok küçük → per-tensor scaling factor zorunlu (Transformer Engine)

2. fp16'nın Yaşattığı Acı: Loss Scaling#

fp16 range
±65504
. Gradient'lar küçük (genelde 1e-4 — 1e-6 mertebesinde) → fp16'da underflow → sıfır → no update.
Klasik çözüm — dinamik loss scaling:
  1. Forward'da loss'u büyük bir
    S
    ile çarp (örn. 2^15 = 32768)
  2. Backward grad'lar S × normal_grad → fp16'da temsil edilebilir
  3. Optimizer step'ten önce grad'ları S'e böl
  4. Eğer
    inf/NaN
    gözlemlenirse S'i yarıya indir, step'i atla
from torch.cuda.amp import GradScaler, autocast scaler = GradScaler() with autocast(dtype=torch.float16): loss = model(x).loss scaler.scale(loss).backward() scaler.step(optimizer) scaler.update()
Pratik sorun: Loss scaling'in 'doğru' sayısını bulmak işkence. Çok büyük → grad inf. Çok küçük → underflow. Modern LLM dynamics'inde aşırı hassas.

3. bf16'nın Sade Reçetesi#

bf16 range fp32 ile aynı → loss scaling yok. Cookbook'un her Lab'ında:
model.to(torch.bfloat16) # weights bf16 with torch.autocast(device_type="cuda", dtype=torch.bfloat16): out = model(x) loss = compute_loss(out) loss.backward() # grad'lar bf16 optimizer.step()
Veya HF Trainer ile:
TrainingArguments(bf16=True, ...) # her şey halloluyor
Niye master fp32 yok?
  • Modern LLM'lerin loss surface'ı bf16'ya gayet uyumlu
  • AdamW 8-bit zaten internal state'i quantize ediyor; master fp32 marginal yarar
  • ~%30 memory tasarrufu (W + G + grads bf16, fp32 copy yok)

4. TF32 Matmul Precision Flag#

PyTorch 2.0+'ta fp32 matmul'lar TF32 (19-bit precision) ile koşulabilir:
torch.set_float32_matmul_precision("high") # = TF32 (Ada/Ampere native) # "highest" = saf fp32 # "high" = TF32 (default cookbook) # "medium" = bf16 matmul (loss surface'a göre riskli)
Çoğu LLM kodunda matmul'lar zaten bf16'da (autocast). Ama HF Trainer'ın
evaluate
çağrısı fp32 path'i kullanabilir → TF32 ile %30-50 hızlı.
Cookbook varsayılan:
high
(TF32 aktif).

5. fp8 — Ada'da Hazır Değil mi?#

RTX 4090 (AD102) fp8 GEMM destekler (FP8 Tensor Cores). Ancak:
  • PyTorch native fp8 training pipeline (NVIDIA Transformer Engine) H100'e optimize
  • Ada üzerinde fp8 kernel'lar var ama fallback ortak
  • Cookbook test'lerinde: 4090 + TE + fp8 → throughput %15-25 daha hızlı ama scaling factor management buggy bazı modellerde
Cookbook'un kararı (2026 başı):
  • Training: bf16 (stable, hızlı, test edilmiş)
  • Inference: fp8 dene (vLLM 0.6+ fp8 quant 4090 destekler, +%30-40 throughput)
  • Fp8 training'i Part X'te (advanced quantization engineering) anlatılır
python
# === Training stability check — bf16 ile fp16 karşılaştırma ===
import torch
from torch import nn
 
torch.manual_seed(42)
 
def measure_grad_stats(dtype):
model = nn.TransformerEncoderLayer(d_model=512, nhead=8, dim_feedforward=2048).to("cuda", dtype=dtype)
x = torch.randn(8, 128, 512, device="cuda", dtype=dtype)
out = model(x)
loss = out.sum()
loss.backward()
 
grads = [p.grad.float() for p in model.parameters() if p.grad is not None]
flat = torch.cat([g.flatten() for g in grads])
return {
"dtype": str(dtype),
"grad_min": flat.min().item(),
"grad_max": flat.max().item(),
"grad_abs_mean": flat.abs().mean().item(),
"n_inf": (~torch.isfinite(flat)).sum().item(),
"n_zero": (flat == 0).sum().item(),
}
 
print(measure_grad_stats(torch.float16))
# fp16: bazı grad'lar zero (underflow) veya inf (overflow)
print(measure_grad_stats(torch.bfloat16))
# bf16: tüm grad'lar finite ve mantıklı
print(measure_grad_stats(torch.float32))
# fp32: reference
stability check — bf16 niye fp16'dan rahat
🐛 FMD — 'bf16 ile train ediyorum, loss NaN olarak başlıyor'
Hipotezler: (a) Model checkpoint fp16'da kayıtlı, bf16'ya cast'te değer aralıkları taşmış (range aynı ama precision rounding). Çözüm: `AutoModelForCausalLM.from_pretrained(..., torch_dtype=torch.bfloat16)` ile load et, sonradan cast etme. (b) Tokenizer pad_token_id model'in vocab'ında değil → embedding lookup garbage → NaN propagate. Çözüm: `model.resize_token_embeddings(len(tokenizer))`. (c) Custom loss'ta log(0) → NaN. Çözüm: `torch.clamp(p, min=1e-7).log()`. (d) FlashAttention v2.5- versiyonda bf16 grad buggy → güncelle. Drill: 4 hipotez için tek tek elimine et.

6. Bench (RTX 4090, Llama 3.1 8B QLoRA)#

Precisionstep/sPeak GBFinal loss (1 epoch)NaN encountered?
fp320.4224 GB (OOM bazen)1.84hiç
fp16 + AMP + loss-scale1.5112.1 GB1.8612 step (scale adapt)
bf16 (cookbook)1.7812.4 GB1.85hiç
bf16 + TE fp8 (4090 native)2.0411.8 GB1.873 step (scale issue)
Sonuç: bf16 saf — daha yavaş değil (TE fp8'den ufak fark), stable, sıfır loss-scaling acısı. Cookbook'un default'u.
✅ Teslim
  1. Yukarıdaki `measure_grad_stats`'ı kendi modeli üzerinde çalıştır. 2) fp16 vs bf16 karşılaştırma tablosunu görsel olarak elde et. 3) Sonraki ders: 1.5 — PCIe vs NVLink vs InfiniBand: Bandwidth Matematiği.

Sık Sorulan Sorular

Genellikle TR-MMLU üzerinde 0.3-1.0 puan kayıp (vLLM fp8 quant ile). MT-Bench score'da fark <%2. Bu kayıp çoğu use-case için kabul edilebilir. Cookbook'un Part X'te detaylı.

Yorumlar & Soru-Cevap

(0)
Yorum yazmak için giriş yap.
Yorumlar yükleniyor...

İlgili İçerikler