Skip to content

The Anatomy of GPU Memory Budgeting: W + G + O + A + B — Managing the 24GB on RTX 4090 at the Atom Level

The most common phrase in fine-tuning: 'OOM'. This lesson ends random OOMs forever. Break down the Weights/Grads/Optimizer/Activations/Buffers budget; understand mathematically why AdamW needs 8 bytes/param, Lion 4, and NF4 fits at 0.5. Fit Llama 3.1 8B into 24GB with 4 different methods.

Şükrü Yusuf KAYA
42 min read
Advanced
GPU Bellek Bütçesinin Anatomisi: W + G + O + A + B — RTX 4090'daki 24GB'ı Atomları Görerek Yönet
🎯 Ders sonunda
Bir model + hyperparam kombinasyonu önünde durunca 'sığar mı?' sorusunu kâğıt-kalem ile cevaplayabileceksin. `nvidia-smi`'ya bakmadan tahmin edeceksin, gerçek peak ile %10 içinde tutturacaksın. OOM yediğinde niye yediğini, hangi terimi azaltacağını saniyede bulacaksın.

1. Bütçe Formülü#

mem_total = W + G + O + A + B
SembolNeBirim
WModel weights (parameters in GPU memory)bytes
GGradient tensörleri (training-only)bytes
OOptimizer state (AdamW: m + v; Lion: m)bytes
AActivation memory (forward'da biriken intermediates)bytes
BBuffers + workspace + fragmentation (~2-4 GB sabit)bytes
W ve G kolay — parametre sayısı × bytes/param. Zor olan O ve A — bunlar mühendislik kararı.

2. W — Weights Memory#

W = N_params × bytes_per_param
Precisionbytes/paramLlama 3.1 8B için W
fp32432.0 GB
fp16 / bf16216.0 GB
fp8 (e4m3)18.0 GB
int8 (LLM.int8)18.0 GB
nf4 / int4 (QLoRA)0.54.0 GB
2-bit (Q2_K)0.252.0 GB (inf-only)
Llama 3.1 8B'nin gerçek parametre sayısı: 8.03B (8,030,261,248). Tablo değerleri ufak farkla yukarı yuvarlanır.
Cookbook'ta kural: fine-tune sırasında bf16 ya da NF4, fp16'dan kaçın (loss scaling complexity + RTX 4090 native bf16 destekler). FP8 training cookbook'ta Part X'te (advanced).

3. G — Gradient Memory#

G = N_trainable_params × bytes_per_grad
  • Full FT: N_trainable = N_params → G ≈ W.
  • LoRA / QLoRA: N_trainable = sadece LoRA matrisleri (A ve B) →
    G ≈ trainable × 2 bytes
    (bf16) → milyarın binde-yüzde-biri kadar.
Llama 3.1 8B QLoRA, rank=32, target=q/k/v/o/gate/up/down:
LoRA params (per layer) = 32 × 2 matrices × (h + h) bytes = 32 × 2 × 4096 × 7 module × 32 layers ≈ 58.7 M params G ≈ 58.7M × 2 = 117 MB
İlginç: full FT'de G ≈ 16 GB, QLoRA'da 0.12 GB — yani G %99.3 azalıyor.

4. O — Optimizer State (En Büyük Sürpriz Kaynağı)#

OptimizerState per paramLlama 3.1 8B full FTNiye
SGD (no momentum)0 bytes0 GBsadece grad var
SGD + momentum4 bytes (fp32 m)32 GBvelocity tensor
AdamW (fp32)8 bytes (fp32 m + fp32 v)64 GB ⚠️mü ve varyans
AdamW (bf16 master)8 bytes (bf16 m + bf16 v + fp32 master)~48 GBmixed precision
8-bit AdamW (bnb)~2 bytes (8-bit m + 8-bit v + percentile quant)16 GBblock-wise quant
Lion4 bytes (fp32 m)32 GBsadece momentum
Adafactor~2-4 bytes (factorized v)16-32 GBrow+col stats
Paged AdamW (bnb)8 bytes ama CPU RAM'e taşır~8 GB peakCPU offload
Cookbook'un kuralı (RTX 4090 üzerinde):
  • LoRA / QLoRA → 8-bit AdamW (bitsandbytes
    paged_adamw_8bit
    )
  • Full FT (<3B model) → 8-bit AdamW veya Lion (Lion özellikle stable)
  • DPO / R1-style RL → AdamW bf16 (8-bit instability gözlemleniyor bazen)
Sayı örneği — Llama 3.1 8B QLoRA (rank=32) + 8-bit AdamW:
O = 58.7M × 8 / 4 (8-bit avg) ≈ 117 MB
Karşılaştır: full FT bf16 AdamW → 48 GB. 400x daha az.

5. A — Activation Memory (En Yanıltıcı Terim)#

Forward pass'te her layer'ın çıktısı backward'a kadar saklanır. Bu birikim activation memory.

Naïve formül (gradient checkpointing kapalı):#

A_naive ≈ batch × seq_len × layers × hidden × bytes × multiplier
multiplier
mimari-bağımlı:
  • Plain transformer: ~10-14 (attn intermediates + ffn intermediates + norms)
  • FlashAttention ile attn intermediates kaybolur → ~8-10
Llama 3.1 8B (32 layer, hidden=4096), batch=1, seq=4096, bf16:
A_naive ≈ 1 × 4096 × 32 × 4096 × 2 × 10 ≈ 10.7 GB

Gradient checkpointing açık:#

A_ckpt ≈ A_naive / sqrt(layers) × c
c
= recomputation segment sayısı (cookbook varsayılan 2-4).
Aynı modelde:
A_ckpt ≈ 10.7 / sqrt(32) × 2.5 ≈ 4.7 GB
Maliyeti: Backward'da ~%33 daha fazla compute (forward'ın bazı kısımları yeniden hesaplanır). RTX 4090'da pratik throughput cezası %20-30.

6. B — Buffers + Workspace + Fragmentation#

  • cuBLAS workspace: ~256-512 MB
  • cuDNN workspace: ~256-512 MB
  • NCCL buffers (multi-GPU): 0.5-2 GB
  • PyTorch caching allocator fragmentation: %5-15 of allocated
  • Triton autotune cache (Unsloth/Flash): ~100-200 MB
Toplam: ~2-4 GB baseline. Cookbook tablolarında
B = 3 GB
varsayılır.

7. Vaka — Llama 3.1 8B'yi RTX 4090'a 4 Ayrı Yolla Sığdır#

YolWGOABTotalSığar?
(a) Full FT bf16 + AdamW1616484.3387 GB
(b) Full FT bf16 + 8-bit AdamW + grad-ckpt1616164.3355 GB
(c) LoRA r=32 bf16 + 8-bit AdamW + grad-ckpt160.120.125.2324.4 GB⚠️ marjinal
(d) QLoRA NF4 r=32 + 8-bit AdamW + grad-ckpt40.120.125.2312.4 GB
(d) + Unsloth optimizations40.120.124.4210.6 GB✅✅
(d) + seq_len=8192 (instead of 4096)40.120.1210.4317.6 GB
Cookbook'un Llama 3.1 8B baseline'ı (d) konfigürasyonudur: 12.4 GB peak, 11.6 GB headroom = stres-test'e dayanıklı.
(c) ve (d) arasındaki fark: NF4 ile weights'in 16'dan 4 GB'a düşmesi. Bu tek başına kompakt FT'yi mümkün kılıyor.
python
# === Bellek ölçüm helper'ı — cookbook'un her Lab'ında bulunur ===
import torch
 
def measure_memory(label: str = ""):
"""Mevcut GPU bellek breakdown'unu döner."""
torch.cuda.synchronize()
allocated = torch.cuda.memory_allocated() / 1024**3
reserved = torch.cuda.memory_reserved() / 1024**3
peak = torch.cuda.max_memory_allocated() / 1024**3
free, total = torch.cuda.mem_get_info()
free_gb = free / 1024**3
total_gb = total / 1024**3
print(
f"[mem{':' + label if label else ''}] "
f"alloc={allocated:6.2f} GB reserved={reserved:6.2f} GB "
f"peak={peak:6.2f} GB free={free_gb:6.2f}/{total_gb:.1f} GB"
)
return {
"alloc_gb": allocated, "reserved_gb": reserved,
"peak_gb": peak, "free_gb": free_gb,
}
 
def estimate_budget(n_params: int, precision: str = "nf4", optimizer: str = "adamw_8bit",
batch: int = 1, seq_len: int = 4096, layers: int = 32, hidden: int = 4096,
grad_ckpt: bool = True, trainable_fraction: float = 0.007):
"""
Cookbook bütçe formülü — kâğıt-kalem tahmin yapar.
trainable_fraction: QLoRA r=32 için ~0.7%, full FT için 1.0.
"""
bpp = {"fp32": 4, "fp16": 2, "bf16": 2, "fp8": 1, "int8": 1, "nf4": 0.5}[precision]
opt_mult = {"sgd": 0, "sgd_momentum": 4, "adamw": 8, "adamw_bf16": 8, "adamw_8bit": 2, "lion": 4}[optimizer]
 
W = n_params * bpp
G = n_params * trainable_fraction * 2 # grads always bf16
O = n_params * trainable_fraction * opt_mult
mult = 10
A_naive = batch * seq_len * layers * hidden * 2 * mult
A = A_naive / (layers**0.5) * 2.5 if grad_ckpt else A_naive
B = 3 * 1024**3
 
total = W + G + O + A + B
return {
"W_gb": W / 1024**3,
"G_gb": G / 1024**3,
"O_gb": O / 1024**3,
"A_gb": A / 1024**3,
"B_gb": B / 1024**3,
"total_gb": total / 1024**3,
}
 
# Llama 3.1 8B QLoRA baseline
budget = estimate_budget(n_params=8_030_000_000)
print(budget)
# {'W_gb': 3.74, 'G_gb': 0.10, 'O_gb': 0.10, 'A_gb': 5.21, 'B_gb': 3.00, 'total_gb': 12.15}
bellek ölçüm + tahmin helper'ı
🐛 Failure Mode Drill — 'Formül 12 GB diyor ama nvidia-smi 19 GB peak gösteriyor'
Hipotezler: (a) Sequence packing on, effective batch artmış → A formülün öngördüğünden büyük. (b) HF Trainer + Trainer.evaluate çağrısı sırasında ek inference batch eval kümesinde sığmıyor → eval_batch_size=1 yap. (c) Tokenizer max_length>4096, gerçek sequence'lar daha uzun → `max_seq_length` zorla kısıtla. (d) Allocator fragmentation, `reserved`/`allocated` oranı 1.5+ → `PYTORCH_CUDA_ALLOC_CONF=expandable_segments
` ekle. Drill: nvidia-smi peak'ten 19 GB olduğunda hangi hipotez geçerli — `torch.cuda.memory_summary()` çıktısını oku.

8. Bench — Aynı Model, 5 Konfigürasyon#

50 step warmup, sonra 100 step ölçüm. RTX 4090 + Llama 3.1 8B.
ConfigPeak GBstep/stokens/sTR-MMLU Δ (3 epoch)
(c) LoRA bf16 + AdamW (memory borderline)23.11.325400+6.8
(d) QLoRA NF4 r=3212.41.787290+7.1
(d) + Unsloth10.63.1012700+7.0
(d) + r=6413.11.717000+7.4
(d) + r=12814.31.656760+7.5
Çıkarımlar:
  • NF4'ün bf16'ya karşı kalite kaybı çok küçük (Δ TR-MMLU 0.1-0.3 puan).
  • Unsloth, aynı output'a 2-3x daha hızlı ulaşır (Triton fused kernel'lar).
  • Lora rank'i artırmak (r=128) küçük ama gerçek bir kalite artışı verir; bütçe yetiyorsa tercih edilir.
✅ Bu dersin teslimi
  1. `estimate_budget` helper'ını çalıştır, kendi favori model + recipe'in için tahmin yap. 2) Gerçek Lab'da peak ölç (`measure_memory("post-step")`). 3) Tahmin vs ölçüm farkın <%15 olmalı — değilse hipotez bul. 4) Sonraki ders: 1.2 — Activation Memory Anatomisi: Niye O(L·s·h)?

Frequently Asked Questions

Marjinal — 70B × 0.5 bytes = 35 GB sadece weights. 24GB'a sığmaz. **Çözümler:** (a) CPU offload (paged_adamw_8bit + bnb 4-bit cpu offload) → 4090'da kısmi inference + train, çok yavaş (~0.1 step/s); (b) **2-bit quant** weights (HQQ / AQLM) + LoRA → 4090'a sığar, kalite kaybı orta. Cookbook Part IV'te detaylı.

Yorumlar & Soru-Cevap

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

Related Content

Connected pillar topics

Pillar topics this article maps to