Проблема
«Модель не влезает» — OOM при запуске или под нагрузкой. VRAM — это бюджет: веса + KV-cache + overhead. Вот как посчитать, влезет ли конкретная модель в конкретное железо.
Алгоритм: 6 шагов
- Бюджет VRAM: суммарная VRAM кластера ×
gpu-memory-utilization(≈0.90) − overhead (~10–15%). - Целевой workload: макс. контекст (8K / 32K / 128K?), целевая concurrency (1 / 4 / 16?) → KV-cache = f(контекст, concurrency, архитектура).
- Размер модели:
weights_VRAM ≈ params × bytes/param × 1.2; weights + KV ≤ бюджет → максимальный размер, который влезает. - Формат под GPU-архитектуру:
- Ampere (RTX 3090/4090, A100): AWQ / GPTQ INT4 (W4A16); FP8 недоступен.
- Hopper/Blackwell (H100/H200/B200): FP8 / NVFP4 — максимум throughput; AWQ — запасной.
- CPU / edge / мало VRAM: GGUF Q4_K_M / Q5_K_M / Q8_0.
- Проверка: weights + KV + overhead ≤ бюджет? Если OOM — лестница снижения: контекст ↓ → concurrency ↓ → квант ниже (Q4) → KV-cache FP8/INT8 (
--kv-cache-dtype fp8) → CPU offload → больше GPU (TP). - Валидация качества: бенчмарк на целевых задачах (code / RAG / chat) vs FP16 baseline → фиксация модели + кванта в документацию.
Формулы
Веса:
weights_VRAM ≈ params × bytes/param × 1.2
×1.2 — embeddings, CUDA context. bytes/param по форматам:
| Формат | bytes/param | 27B | 70B |
|---|---|---|---|
| FP16/BF16 | 2 | ~65 GB | ~168 GB |
| FP8 | 1 | ~32 GB | ~84 GB |
| AWQ/GPTQ INT4 | 0.5 | ~16 GB | ~42 GB |
| GGUF Q4_K_M | ~0.55 | ~17 GB | — |
| GGUF Q8_0 | ~1.07 | ~34 GB | — |
KV-cache (на 1 запрос):
bytes/token = 2 × n_layers × n_kv_heads × head_dim × bytes_per_element
Множитель 2 — храним и K, и V. GQA (мало KV-голов) сильно снижает размер. Пример: 27B dense, GQA, BF16 KV ≈ 1–4 GB на 32K контекст; при concurrency 4 — умножаем на 4. KV-cache не квантуется вместе с весами — это отдельный потребитель VRAM (можно FP8/INT8 KV: --kv-cache-dtype fp8).
Бюджет:
weights + KV × concurrency + overhead ≤ VRAM × gpu-memory-utilization
Форматы — когда что брать
- FP16/BF16: 80 GB+ GPU, потеря 0% — эталон, валидация качества.
- FP8 / NVFP4: Hopper/Blackwell, потеря <1% — production на H100, максимум throughput.
- AWQ INT4 (W4A16): любая NVIDIA вкл. Ampere, потеря ~1–3% — default для RTX 3090/4090, лучшее качество среди 4-bit (защита «важных» весов до квантизации).
- GPTQ INT4 (W4A16): любая NVIDIA, потеря ~2–5% (чуть хуже AWQ на code) — запасной, если AWQ-чека нет.
- GGUF Q4_K_M / Q5_K_M / Q8_0: CPU, любая GPU, Mac; Q4 ~3–5% потери, Q8 <1% — edge, Ollama, мало VRAM, CPU offload.
Правила: Ampere → AWQ (FP8 нет); H100+ → FP8 (AWQ — fallback). Качество критично → AWQ > GPTQ; VRAM критична → GGUF Q4_K_M (лучший баланс размер/качество). Длинный контекст → KV FP8/INT8 или снизить max-model-len. MoE (35B-A3B, DeepSeek): активные параметры малы — 35B-A3B в Q4 живёт на 24 GB, 120+ tok/s.
Наш стек: Qwen3.8-27B на 2×RTX 3090
2×RTX 3090 = 48 GB, бюджет ≈ 43 GB:
| Вариант | Расчёт | Вердикт |
|---|---|---|
| FP16 | ~65 GB | OOM, не влезает |
| FP8 | ~32 GB | Недоступно: на Ampere нет FP8 |
| AWQ W4A16 | 16 GB весов (TP=2) + KV 2–4 GB (32K, 1 req) + overhead ≈ 5 GB → ~20–25 GB | ✅ Наш выбор |
| GGUF Q4_K_M | ~17 GB → ~22 GB | Альтернатива (llama.cpp) |
Продакшн-реальность: 256K контекст → KV-cache растёт до ~18 GB, итого ~39 GB — влезает, но max-num-seqs = 2 (KV съедает бюджет — см. часть 3).
Вывод
VRAM-бюджет считается до выбора модели, а не после первого OOM. weights + KV + overhead ≤ бюджет — если запаса нет, снижаем контекст или concurrency, а не задачу.
Смежные материалы: AWQ, FP8, Тюнинг vLLM (часть 3), Подбор модели (часть 2).