GRATÍCULAinstrumento de maestría
BancoRTX 5090 · GB202
Rev2026.06
Entrar
N0 · Fundamentos Blackwell/L3

El presupuesto de VRAM: qué cabe en 32 GB

Objetivo de maestría

dado un modelo y una tarea, decir en segundos si cabe en tu 5090 y con qué técnica, o si debe ir a cloud. Esto te ahorra horas de experimentos que iban a fallar con OOM (out-of-memory) desde el principio.


3.1La VRAM se reparte en cuatro cubos

Toda la memoria de la GPU durante un workload se divide en:

  1. Pesos del modelonum_params × bytes_por_param.
  2. Estados del optimizador (solo en training) — el más caro y el que la gente olvida.
  3. Activaciones / KV-cache — depende de batch, longitud de secuencia y arquitectura.
  4. Overhead — CUDA context, fragmentación, buffers de la librería (~1–2 GB).

La regla es siempre: VRAM_necesaria = pesos + optimizador + activaciones + overhead ≤ 32 GB.


3.2Inferencia: la cuenta fácil

En inferencia no hay optimizador ni gradientes. Solo pesos + KV-cache + overhead.

VRAM_inferencia ≈ num_params × bytes_por_param  +  KV_cache  +  ~1.5 GB

bytes_por_param según precisión: FP16/BF16 = 2 · FP8 = 1 · 4-bit (Q4/NF4/AWQ/MXFP4) = 0.5.

Ejemplos (solo pesos, batch pequeño):

ModeloFP16FP84-bit
8B16 GB8 GB4 GB
14B28 GB ⚠️ tight14 GB7 GB
32B denso64 GB ❌32 GB ⚠️16 GB ✅
70B denso140 GB ❌70 GB ❌35 GB ❌
120B MoE (gpt-oss)~30 GB ✅ (MXFP4)

(Suma el KV-cache de L1·E1 para contextos largos; a 32K tokens puede ser varios GB.)

Conclusión operativa de inferencia:

  • FP16 denso: hasta 14B.
  • FP8 denso: hasta ~30B.
  • 4-bit denso: 32B (Qwen3-32B) cabe; 70B no (35 GB > 32).
  • MoE en 4-bit: hasta ~120B (gpt-oss-120B) porque solo cargas pesos esparsos activos en cómputo, pero todos los pesos siguen en VRAM → el truco es que MXFP4 los comprime lo justo para entrar en 31 GB.

3.3Training: por qué cuesta 4–8× más que inferencia

Aquí está la trampa que sorprende a todo el mundo. En full fine-tuning con AdamW, por cada parámetro guardas:

  • el peso (2 o 4 bytes),
  • el gradiente (mismos bytes que el peso),
  • dos estados del optimizador (momentum m y varianza v, normalmente en FP32 = 4 bytes cada uno).
Full FT (mixed precision bf16 + AdamW fp32 states):
  por parámetro ≈ 2 (peso bf16) + 2 (grad bf16) + 4 (m) + 4 (v) ≈ 12-16 bytes
  → un modelo de 7B en full FT ≈ 7e9 × 16 ≈ 112 GB  ❌ (sin contar activaciones)

Por eso full fine-tuning en la 5090 solo es viable hasta ~1.5–3B.

LoRA/QLoRA cambian las reglas: congelas los pesos del base (no necesitan gradiente ni estados de optimizador) y solo entrenas los adaptadores (millones, no miles de millones, de params). En QLoRA además el base va en 4-bit:

QLoRA:
  pesos base en 4-bit (0.5 B/param, congelados, sin optimizador)
  + adaptadores LoRA (pequeños) con sus gradientes y estados
  + activaciones (gradient checkpointing las reduce mucho)
  → un modelo de 14B en QLoRA cabe holgado en 32 GB
  → con Unsloth, MoE 30B-A3B cabe en 17.5 GB

Conclusión operativa de training:

TécnicaTecho en 32 GB
Full fine-tuning (bf16 + AdamW)1.5–3B
LoRA (base bf16)7–13B
QLoRA (base 4-bit)~14B con calidad; hasta ~40B agresivo
QLoRA MoE (Unsloth)30B-A3B en 17.5 GB
GRPO/RLVR (Unsloth + vLLM colocate)Qwen3-4B cómodo, 8B LoRA, 30B-A3B QLoRA

Por qué QLoRA es la palanca del curso: te deja tocar modelos 10× mayores de lo que permitiría full FT, a cambio de entrenar solo adaptadores. En el Nivel 2 verás que la pérdida de calidad frente a full FT es pequeña para la mayoría de tareas — y lo medirás tú mismo.


3.4Las dos técnicas que estiran la VRAM (las usarás siempre)

  • Gradient checkpointing: en lugar de guardar todas las activaciones del forward para el backward, guardas solo algunas y recomputas el resto. Cambia memoria por cómputo (~30% más lento, pero permite secuencias/batches mucho mayores). Unsloth tiene una versión optimizada (use_gradient_checkpointing="unsloth").
  • Paged optimizers (QLoRA): los estados del optimizador se paginan a RAM cuando hay picos, evitando OOM. Lo activa bitsandbytes automáticamente con optim="paged_adamw_8bit".

3.5Laboratorio L3.1 — Calculadora de VRAM

Una herramienta que usarás todo el curso para decidir local vs cloud:

python
1# lab_l3_vram.py — estima la VRAM de un modelo en inferencia y training
2def bytes_per_param(precision: str) -> float:
3    return {"fp32": 4, "fp16": 2, "bf16": 2, "fp8": 1, "int4": 0.5, "nf4": 0.5}[precision]
4
5def kv_cache_gb(n_layers, n_kv_heads, head_dim, seq_len, batch, kv_dtype="fp16"):
6    b = bytes_per_param(kv_dtype)
7    total = 2 * n_layers * n_kv_heads * head_dim * seq_len * batch * b
8    return total / 1e9
9
10def inference_vram_gb(n_params_b, precision="fp16", kv_gb=0.0, overhead_gb=1.5):
11    weights = n_params_b * 1e9 * bytes_per_param(precision) / 1e9
12    return weights + kv_gb + overhead_gb
13
14def training_vram_gb(n_params_b, mode="qlora", overhead_gb=2.0, activations_gb=4.0):
15    p = n_params_b * 1e9
16    if mode == "full":      # peso+grad bf16 + m,v fp32
17        mem = p * (2 + 2 + 4 + 4)
18    elif mode == "lora":    # base bf16 congelado, adaptadores ~1% entrenables
19        trainable = p * 0.01
20        mem = p * 2 + trainable * (2 + 4 + 4)
21    elif mode == "qlora":   # base 4-bit congelado, adaptadores ~1%
22        trainable = p * 0.01
23        mem = p * 0.5 + trainable * (2 + 4 + 4)
24    return mem / 1e9 + overhead_gb + activations_gb
25
26if __name__ == "__main__":
27    # Qwen3-14B, inferencia FP16, 8K ctx (n_layers=40, kv_heads=8, head_dim=128)
28    kv = kv_cache_gb(40, 8, 128, 8192, 1)
29    print(f"Inf 14B fp16 @8K: {inference_vram_gb(14, 'fp16', kv):.1f} GB")
30    print(f"Inf 14B int4 @8K: {inference_vram_gb(14, 'int4', kv):.1f} GB")
31    for m in ("full", "lora", "qlora"):
32        print(f"Train 7B {m:6}: {training_vram_gb(7, m):.1f} GB")
33        print(f"Train 14B {m:6}: {training_vram_gb(14, m):.1f} GB")

Líneas no triviales:

  • En training mode full, el (2+2+4+4) son los cuatro cubos por parámetro (peso bf16, grad bf16, momentum fp32, varianza fp32). Es la fórmula que explica el "×8".
  • En lora/qlora solo los trainable (≈1%) pagan gradiente y optimizador; el base solo ocupa sus pesos.
  • activations_gb es una estimación; con gradient checkpointing baja mucho y depende de seq_len/batch.

Corre el script y verifica: 14B full FT da ~150 GB (imposible), 14B QLoRA da ~12 GB (cabe de sobra). Esa es la intuición que quieres tener internalizada.


3.6La frontera local↔cloud

Manda a cloud (Hetzner / CloudRift / Spheron spot) sin dudar cuando:

  • Inferencia/fine-tune de modelos densos >30B.
  • Full fine-tuning de >3B.
  • Pretraining serio (>1B params, >100B tokens).
  • RL multi-node o eval a gran escala.

Quédate local cuando: itera <24 h, ≤30B, prototipado, eval pequeña, QLoRA/GRPO de hasta ~14–30B-A3B. Nunca alquiles >$1/hr para exploración — la 5090 ya la pagaste.


3.7Ejercicios

E1. Usa la calculadora: ¿cabe un fine-tune QLoRA de Qwen3-32B en 32 GB? ¿Y LoRA (base bf16)? ¿Y full FT de un 3B?

Solución QLoRA 32B: pesos 4-bit ≈16 GB + adaptadores + overhead+act ≈ ~22-24 GB → cabe tight (Unsloth lo hace con MoE; denso 32B es ajustado pero posible con seq corto). LoRA 32B (base bf16) ≈ 64 GB base → ❌. Full FT 3B ≈ 3e9×16/1e9 + extras ≈ ~54 GB → ❌ en 32 GB; baja a ~1.5B o usa LoRA.

E2. Quieres servir gpt-oss-120B (MoE) en tu 5090. ¿Por qué cabe en 4-bit pero un 70B denso en 4-bit no?

Solución 70B denso × 0.5 B/param = 35 GB > 32 → no cabe. gpt-oss-120B en MXFP4 comprime a ~30 GB y, aunque es "más grande" en params totales, la cuantización MXFP4 + el hecho de que entra justo en 31 GB lo permite; en cómputo solo se activan los expertos top-k, pero **todos** los pesos residen en VRAM (por eso aún necesita ~30 GB).