Saltar al contenido
Fantástico Mundo de Jon
RSS

Cuánta VRAM ocupa realmente un LLM

La cuenta rápida — parámetros por bits — se equivoca por varios gigabytes, porque ignora la caché KV. Aquí está el cálculo completo, con la fórmula, los números y cómo verificarlo en tu propia GPU.

¿Con prisa? Pide el TL;DR a Claude — lee la página y la resume.

La pregunta que más recibo sobre ejecutar modelos en local es siempre la misma: ¿cabe en mi tarjeta?

Y casi todo el mundo hace la misma cuenta equivocada. Toma el número de parámetros, lo multiplica por los bits de la cuantización, divide entre ocho y concluye que un modelo de 32B en Q4 ocupa 20 GB — así que cabe holgado en una tarjeta de 24 GB.

Entonces carga el modelo y la GPU se queda sin memoria con 8 mil tokens de contexto.

El problema no es la cuenta. El problema es que responde solo un tercio de la pregunta. La memoria que ocupa un modelo tiene tres partes, y la segunda crece con el tamaño de la conversación.

Parte 1: los pesos

Esta es la parte fácil, y la única que casi todos calculan. Cada parámetro ocupa un número de bits que depende de la cuantización:

Cuantización bits/peso bytes/peso
FP16 (sin cuantizar) 16,0 2,00
Q8_0 8,5 1,06
Q6_K 6,6 0,82
Q5_K_M 5,7 0,71
Q4_K_M 4,9 0,61
Promedios efectivos de los K-quants de llama.cpp. No son exactos: los K-quants usan precisiones distintas por capa, y la cifra real varía ~2% entre arquitecturas. Verifica siempre el tamaño del archivo .gguf.

Fíjate en que Q4_K_M no da 4 bits por peso, sino ~4,9. Los K-quants guardan las capas sensibles (atención, embeddings) con más precisión de lo que sugiere el nombre. Quien calcula con 4,0 subestima el modelo en casi un 20%.

Multiplicando por los tamaños más comunes:

Modelo FP16 Q8_0 Q6_K Q4_K_M
8B 16,1 8,5 6,6 4,9
12B 24,4 13,0 10,1 7,5
32B 65,6 34,9 27,1 20,1
70B 141,2 75,0 58,2 43,2
Peso de los parámetros en GB decimales (10⁹ bytes), a partir del recuento real de parámetros de cada familia. Es solo la primera parte — falta la caché KV.

De aquí sale el número que todo el mundo repite: 32B en Q4 = 20 GB. Es correcto. Y está incompleto.

Parte 2: la caché KV — la que nadie calcula

Cada token que entra en la conversación deja un rastro en memoria. El modelo guarda los vectores de clave y valor de cada token, en cada capa, para no tener que recalcular la atención desde cero en cada palabra que genera. Eso es la caché KV, y crece linealmente con el contexto.

La fórmula:

bytes por token = 2 × capas × cabezas_kv × dim_cabeza × bytes_por_elemento

El 2 es porque son dos matrices: clave y valor. Los otros tres números los lees directamente del config.json del modelo — num_hidden_layers, num_key_value_heads y head_dim (o hidden_size / num_attention_heads, cuando head_dim no está declarado).

Para Llama 3 8B — 32 capas, 8 cabezas KV, dimensión 128, en FP16:

2 × 32 × 8 × 128 × 2 bytes = 131.072 bytes = 128 KiB por token

128 KiB por token parece poco. Multiplícalo por una ventana de contexto de verdad:

Capas (modelo típico) KiB/token 4k 8k 32k 128k
32 (≈8B) 128 0,54 1,07 4,29 17,18
40 (≈12B) 160 0,67 1,34 5,37 21,47
64 (≈32B) 256 1,07 2,15 8,59 34,36
80 (≈70B) 320 1,34 2,68 10,74 42,95
Caché KV en GB decimales, asumiendo GQA con 8 cabezas KV, dimensión de cabeza 128 y caché en FP16 — la configuración de la mayoría de las arquitecturas abiertas actuales. Verifica el config.json de tu modelo: más cabezas KV multiplican estos números.

Un 32B con 32k de contexto reserva 8,6 GB solo de caché — casi la mitad de lo que ocupan los pesos. En 128k, la caché supera los 34 GB y se convierte en el elemento más caro de la cuenta, mayor que el propio modelo.

Parte 3: el overhead del runtime

Queda la parte molesta de estimar, porque depende del runtime, del driver y de cuánto espacio temporal necesita el kernel de atención:

  • Contexto de CUDA: entre 300 y 600 MB, solo por existir un proceso usando la GPU.
  • Buffers de cómputo: el espacio temporal de la atención y del feed-forward, típicamente unos cientos de MB, proporcional al batch y al contexto.
  • Fragmentación del asignador: la memoria disponible nunca es 100% aprovechable.

En la práctica, 1 GB es una reserva honesta para inferencia de un solo usuario en llama.cpp u Ollama. Los servidores con vLLM o TensorRT-LLM reservan bastante más, porque preasignan la caché entera al arrancar.

La cuenta completa

Juntando las tres partes para el caso que me interesa — un 32B en Q4_K_M con 32k de contexto:

32B · Q4_K_M · 32k de contexto

Pesos
20,1 GB
Caché KV
8,6 GB
Overhead
1,0 GB
Total
29,7 GB (27,6 GiB)
Disponible
32 GiB (34,4 GB)
Margen
4,4 GiB

Cabe — pero con 4 GiB de margen, no con los 12 GB que prometía la cuenta rápida. Y si subes el contexto a 64k, ya no cabe.

Cómo verificarlo de verdad

Toda esta aritmética sirve para predecir. Para saber, mide — antes y después de cargar el modelo, con la misma ventana de contexto que vas a usar realmente:

# Antes de cargar: cuánto ya está ocupado (compositor, navegador, etc.)
nvidia-smi --query-gpu=memory.used,memory.total --format=csv

# Carga con la ventana de contexto real, no con la predeterminada
OLLAMA_CONTEXT_LENGTH=32768 ollama run qwen3:32b "ok"

# Cuánto reservó el modelo de hecho, y si algo se fue a la CPU
ollama ps

ollama ps muestra una columna PROCESSOR. Si dice algo como 70%/30% CPU/GPU, parte del modelo se fue a la RAM del sistema — y el throughput se desploma por un factor de diez, porque cada token tiene que atravesar el bus PCIe.

Cuando no cabe

En orden de coste-beneficio, de lo que menos duele a lo que más:

  1. Reduce el contexto. Es la palanca más barata y la más ignorada. Nadie necesita 128k para lo que hace el 90% del tiempo, y cada recorte a la mitad devuelve la mitad de la caché.
  2. Cuantiza la caché KV. --cache-type-k q8_0 --cache-type-v q8_0 en llama.cpp reduce la caché a la mitad con una pérdida de calidad que rara vez aparece en uso normal. Es el mejor intercambio de la lista.
  3. Baja un nivel de cuantización. De Q6_K a Q4_K_M devuelve un 25% de los pesos. La degradación es real, pero suele ser menor de lo que sugiere la intuición.
  4. Descarga capas a la CPU. Funciona, cabe casi cualquier cosa — y es diez veces más lento. Último recurso.
  5. Cambia de modelo. Un 12B bien elegido ejecutándose entero en la GPU entrega más valor por segundo que un 32B a medias en la CPU.

El orden importa: las dos primeras opciones cuestan casi nada en calidad y resuelven la mayoría de los casos. La cuarta es la que todo el mundo intenta primero, y es la peor.


En el próximo post mido lo que este cálculo predice, en el banco, con tokens por segundo para cada configuración. La aritmética dice qué cabe; solo la medición dice qué vale la pena.