Por qué casi todo el mundo se queda corto
La pregunta llega siempre igual: «quiero servir un modelo de 70B, ¿me vale una tarjeta de 48 GB?». La respuesta honesta es «depende», pero no de nada misterioso: depende de con cuántos bits guardes los pesos y de cuánto contexto quieras atender a la vez. Son dos números que puedes calcular en treinta segundos, y la mayoría de los dimensionados fallidos vienen de haber calculado solo el primero.
La memoria que consume un modelo en inferencia tiene tres partidas: los pesos, el KV cache y el overhead del runtime. La primera es fija y fácil. La segunda crece con el contexto y con el número de peticiones simultáneas, y es la que sorprende. La tercera es pequeña pero no nula.
La parte fácil: los pesos
Los pesos ocupan número de parámetros × bytes por parámetro. Nada más. Un modelo de 8.000 millones de parámetros en precisión de 16 bits ocupa 8.000 millones × 2 bytes = 16 GB. La tabla sale sola:
| Modelo | FP16 / BF16 | FP8 / INT8 | INT4 |
|---|---|---|---|
| 8B | 16 GB | 8 GB | 4 GB |
| 13B | 26 GB | 13 GB | 6,5 GB |
| 32B | 64 GB | 32 GB | 16 GB |
| 70B | 140 GB | 70 GB | 35 GB |
Ya se ve el primer corte: un 70B en FP16 no cabe en ninguna tarjeta de 96 GB. O lo cuantizas, o repartes el modelo entre varias GPU.
La cuantización cambia la ecuación
Cuantizar es guardar cada peso con menos bits. Pasar de FP16 a INT4 divide la memoria por cuatro y, en la mayoría de tareas de generación de texto, la pérdida de calidad es modesta si se usa un método moderno. No es gratis: la calidad cae más en razonamiento largo y en código que en conversación, y conviene medirlo con tu propio conjunto de evaluación antes de darlo por bueno.
Regla práctica: si el modelo cabe en FP8 dentro de tu presupuesto de memoria, quédate en FP8. Baja a INT4 solo cuando sea la única forma de que entre, o cuando necesites el hueco libre para atender más peticiones a la vez.
El KV cache, el coste que se olvida
Durante la generación, el modelo guarda las claves y los valores de atención de cada token que ya ha procesado, para no recalcularlos. Eso es el KV cache, y crece de forma lineal con la longitud del contexto y con el número de peticiones simultáneas. La fórmula es:
KV cache = 2 × capas × cabezas_kv × dim_cabeza × contexto × bytes × peticiones
El 2 son la clave y el valor. Con un Llama 3.1 de 70B —80 capas, 8 cabezas KV por atención agrupada, dimensión de cabeza 128— en FP16 y una sola petición:
- 8.192 tokens de contexto: 2 × 80 × 8 × 128 × 8.192 × 2 = 2,5 GiB
- 32.768 tokens: 10 GiB
Parece poco hasta que sirves a varios usuarios. Diez peticiones concurrentes de 32k contexto sobre ese mismo modelo son 100 GiB solo de KV cache, más que la tarjeta entera. Por eso el dimensionado de un servicio con concurrencia real no se parece en nada al de una prueba de laboratorio con una sola conversación.
Hay dos atajos legítimos: cuantizar también el KV cache a 8 bits, que lo reduce a la mitad, y limitar el contexto máximo por petición a lo que de verdad usas. Un límite de 8k en lugar de 128k ahorra más memoria que cualquier otra decisión de la lista.
Lo que no aparece en la cuenta
Al total hay que sumarle las activaciones intermedias, los búferes del runtime y la fragmentación del asignador de memoria. Con vLLM o TensorRT-LLM, reservar un 10-15 % extra sobre la suma de pesos y KV cache es una estimación razonable. Si el cálculo te deja justo en el límite de la tarjeta, no cabe.
Qué cabe en 24, 48 y 96 GB
Juntando las tres partidas, con 8k de contexto, una petición y un 15 % de overhead, esto es lo que entra en cada tamaño de instancia GPU:
| Instancia | Entra cómodo | Entra apurado |
|---|---|---|
| 24 GB | 8B en FP8 (10 GB) · 13B en INT4 (9 GB) | 8B en FP16 (20 GB) · 13B en FP8 (16 GB) · 32B en INT4 (20 GB) |
| 48 GB | 13B en FP16 (31 GB) · 32B en FP8 (39 GB) | 70B en INT4 (43 GB) |
| 96 GB | 32B en FP16 (75 GB) · 70B en INT4 (43 GB) | 70B en FP8 (83 GB) |
La columna «entra apurado» es exactamente donde se rompen los despliegues: el modelo carga, las primeras peticiones responden y al tercer usuario concurrente el servidor se queda sin memoria. Si tu caso está ahí, sube de tamaño.
Cuándo necesitas más de una tarjeta
Cuando el modelo no entra en una sola GPU ni cuantizado, hay que repartirlo. El reparto por tensores divide cada capa entre varias tarjetas y exige interconexión rápida entre ellas; el reparto por capas es más tolerante al ancho de banda pero deja GPUs esperando. En cualquiera de los dos casos ya no hablamos de una instancia sino de un servidor GPU dedicado con dos, cuatro u ocho tarjetas.
El otro motivo para dar el salto es la concurrencia. Un modelo pequeño atendiendo a cien usuarios a la vez consume más memoria en KV cache que un modelo grande atendiendo a uno, y ahí el cuello no son los pesos sino el número de peticiones que quieres mantener vivas.
Cómo medirlo tú mismo
La cuenta de servilleta sirve para elegir tamaño; para confirmar, mídelo. Carga el modelo con tu runtime, lanza la carga que esperas en producción y observa el consumo real:
nvidia-smi --query-gpu=memory.used,memory.total --format=csv -l 1
Los parámetros exactos de tu modelo —capas, cabezas KV, dimensión de cabeza— están en el config.json del repositorio del modelo, así que puedes sustituirlos en la fórmula de arriba en lugar de fiarte de una tabla genérica. La calculadora de tamaño de modelo de Hugging Face hace la parte de los pesos automáticamente.
Y si la tarjeta se comparte, asegúrate de que el reparto es por hardware y no por turnos: en una partición MIG la memoria que te asignan es tuya y nadie puede invadirla, mientras que en un reparto por software el consumo del vecino sí te afecta. Esa diferencia es la que hace que una instancia de 24 GB sea realmente de 24 GB.
Si todavía estás decidiendo si te conviene alojar el modelo o seguir pagando por token, la otra mitad de la cuenta está en LLM local vs API: ahí comparamos coste, latencia y privacidad. Esta guía te dice cuánta GPU necesitas; aquella, si merece la pena tenerla.