26

Inferencia: cómo responde un modelo

¿Qué pasa, y cuánto cuesta, entre que escribes y que aparece la respuesta?

13 minRuta ejecutiva

Inferencia: cómo responde un modelo

Con voz. Puedes pausar y saltar a cualquier paso.

Lección completa

Subtítulos

Escribes una pregunta y pulsas Enter. Un instante después aparece la primera palabra, y luego las demás, una tras otra. ¿Qué hace el modelo en ese rato? ¿Y cuánto cuesta?

Voz

Sin voz: la lección avanza sola con subtítulos.

La voz de esta lección está en preparación: por ahora avanza sola con subtítulos.

0:00 / 0:00

Qué lograrás

  • Explicar las dos fases de una respuesta: el llenado, que lee tu mensaje de una vez, y la decodificación, que escribe un token por vuelta.
  • Describir qué guarda la caché KV, qué trabajo ahorra y por qué ocupa más memoria cuanto más larga es la conversación.
  • Estimar el costo de una tarea con sus tokens de entrada y de salida, y reconocer qué la encarece o la hace esperar: contexto largo, salida larga, lote pequeño.

Ideas clave

  1. Una respuesta tiene dos fases. El llenado (prefill) procesa todo tu mensaje de una vez y fija la espera hasta el primer token; la decodificación (decode) escribe un token por vuelta y fija cuánto tarda el resto.
  2. La caché KV guarda las claves y los valores de los tokens anteriores, que nunca cambian, para no recalcularlos: en el ejemplo, 15 casillas en lugar de 105. A cambio ocupa memoria que crece con cada token y con cada conversación.
  3. En cada vuelta la GPU lee todos los pesos (y las cachés) de su memoria y hace muy poca aritmética: el ancho de banda marca el paso. Tokens por segundo ≤ ancho de banda ÷ bytes leídos por vuelta.
  4. Atender a varias personas en un lote reparte esa lectura: sube el rendimiento (throughput) y baja el costo por token, pero cada persona recibe menos tokens por segundo (más latencia).
  5. Costo de una tarea = entrada × su precio + salida × su precio, y la salida cuesta varias veces más. La mezcla de expertos ahorra cálculo por token, no memoria.

Lo que mucha gente cree

Creencia común Responder es «calcular»: con una GPU que haga el doble de operaciones por segundo, el modelo escribiría el doble de rápido.

Lo correcto Al escribir, la GPU espera datos, no cuentas: con una persona usa menos del uno por ciento de su cálculo. Manda el ancho de banda de memoria, junto con los bytes que hay que leer por vuelta (pesos y cachés), el largo del contexto y el tamaño del lote.

Compruébalo

Cuatro preguntas. Sin nota ni cuenta: sirven para ver si la idea quedó.

Concepto¿Qué hace la caché KV durante la inferencia?
Concepto¿Por qué la decodificación la limita la memoria y no el cálculo?
CálculoLlama 3 de 8 mil millones guarda unos 131 000 bytes de caché por token. ¿Cuánta caché ocupa una conversación de 64 000 tokens?
AplicaciónUna empresa resume contratos de 40 000 tokens en resúmenes de 400; otra redacta informes de 4 000 tokens a partir de 500 de instrucciones. Si la salida cuesta cinco veces la entrada, ¿qué es correcto?

Por dentroPara quien quiere las fórmulas y el código. No hace falta para seguir el curso.

Dos fases, dos cuellos de botella

Un modelo denso con NN parámetros hace unas 2N2N operaciones por cada token que procesa (una multiplicación y una suma por parámetro; Kaplan et al., 2020; Pope et al., 2022), más un término de atención que crece con el contexto.

Llenado (los LL tokens del mensaje a la vez; nℓn_\ell bloques, datd_{\text{at}} = cabezas × dimensión por cabeza):

FLOPsllenado≈2NL+2 nℓ dat L2\text{FLOPs}_{\text{llenado}}\approx 2NL+2\,n_\ell\,d_{\text{at}}\,L^2

Son multiplicaciones de matrices grandes: la GPU trabaja cerca de su pico. La lección supone el 40 % del pico (Llama 3 reporta entre 38 y 43 % al entrenar; Pope et al. llegan a 76 % en el llenado con lotes grandes). Con el modelo de 8 mil M y 2 000 tokens: 3.3⋅10133.3\cdot10^{13} FLOPs ÷ (0.4⋅989⋅1012)(0.4\cdot 989\cdot10^{12}) ≈ 84 ms.

Decodificación (BB conversaciones de LL tokens de contexto cada una). Cada vuelta tiene un tiempo de memoria y un tiempo de cálculo (Pope et al., §2), y manda el mayor:

tvuelta=max⁡ ⁣(W+B L ckvBW, B (2N+4 nℓ dat L)P)t_{\text{vuelta}}=\max\!\left(\frac{W+B\,L\,c_{kv}}{\mathrm{BW}},\ \frac{B\,(2N+4\,n_\ell\,d_{\text{at}}\,L)}{P}\right)

con WW los bytes de los pesos, ckvc_{kv} los bytes de caché por token, BW el ancho de banda y PP el cálculo útil (la lección usa la mitad del pico). Con B=1B=1 hay 2N2N operaciones por cada W=bNW=bN bytes, es decir 2/b2/b operaciones por byte: una, en FP16. La H100 puede hacer 989⋅1012/3.35⋅1012≈295989\cdot10^{12}/3.35\cdot10^{12}\approx 295 por byte, así que la decodificación de una persona usa cerca del 0.3 % del cálculo. Pope et al. lo dicen así: con lotes y secuencias cortas domina el tiempo de cargar los pesos; con lotes grandes y secuencias largas, el de cargar la caché.

La caché KV por dentro

ckv=2 nℓ nkv dh bc_{kv}=2\,n_\ell\,n_{kv}\,d_h\,b

El 2 es clave y valor; nkvn_{kv} las cabezas de clave-valor; dhd_h la dimensión por cabeza y bb los bytes por número. Llama 3 8B (Llama Team, 2024, tabla 3): 2⋅32⋅8⋅128⋅2=131 0722\cdot32\cdot8\cdot128\cdot2=131\,072 bytes por token (en la escena, 8⋅128=1 0248\cdot128=1\,024 números por clave y por bloque). Con atención multicabeza completa (32 cabezas KV) serían 524 288524\,288: Llama 3 usa atención de consultas agrupadas (GQA, Ainslie et al., 2023), que comparte cada par entre cuatro cabezas de consulta, «para reducir el tamaño de las cachés de clave-valor durante la decodificación». La misma cuenta da el valor de Kwon et al. (2023) para OPT-13B: 2⋅5 120⋅40⋅2=819 2002\cdot5\,120\cdot40\cdot2=819\,200 bytes, unos 800 KB por token.

Sin caché, generar GG tokens tras PP de entrada procesa GP+G(G−1)/2GP+G(G-1)/2 posiciones; con caché, P+G−1P+G-1. Con P=6P=6 y G=10G=10: 105105 frente a 1515. El transformer de juguete de la escena (2 bloques, 2 cabezas, d=16d=16, pesos al azar con semilla fija; tiny.ts) recorre los dos caminos: cuenta 105 y 15 pasadas, 498 240 y 72 960 multiplicaciones-sumas, y sus logits coinciden con una diferencia máxima de 0.

Techo de velocidad, lotes y costo

tokens/s por persona≤BWW+B L ckv,rendimiento=Btvuelta,costo por milloˊn=precio por hora3 600⋅rendimiento⋅106\text{tokens/s por persona}\le\frac{\mathrm{BW}}{W+B\,L\,c_{kv}},\qquad \text{rendimiento}=\frac{B}{t_{\text{vuelta}}},\qquad \text{costo por millón}=\frac{\text{precio por hora}}{3\,600\cdot\text{rendimiento}}\cdot10^{6}

Con el 8B en FP16 en una H100, 8 000 tokens de contexto y 2 USD por hora de GPU (supuesto): B=1B=1 da 196 tokens/s y 2.84 USD por millón; B=60B=60, el máximo que cabe, da 42 tokens/s por persona, 2 545 en total y 0.22 USD por millón: unas trece veces más barato en la misma máquina. Con 128 000 tokens de contexto solo caben 3 conversaciones.

Lo que paga quien usa una API

En las listas consultadas el 12 de octubre de 2026, la salida cuesta cinco veces la entrada en todos los modelos de Anthropic, y de cinco a más de ocho veces en los de Google. Los precios de la escena (US$ 3 y 15 por millón) son un ejemplo con esa proporción. Si el inicio de tu mensaje se repite (instrucciones, un documento base), la caché de prompt lo cobra mucho más barato: en la lista de Anthropic, leer de ella cuesta 0.1 veces el precio de entrada (0.05 o 0.025 en algunos modelos) y escribir en ella, con vigencia de cinco minutos, 1.25 veces.

Las esperas de la escena son estimaciones con el modelo de 8 mil M en una H100 y una sola persona: llenado al 40 % del pico, y cada vuelta de escritura con el tiempo de memoria de arriba.

Mezcla de expertos

Cada bloque reemplaza su red por EE expertos y un enrutador que elige kk por token:

Ntotal=Ncomunes+E nℓ (3dh),Nactivos=Ncomunes+k nℓ (3dh)N_{\text{total}}=N_{\text{comunes}}+E\,n_\ell\,(3dh),\qquad N_{\text{activos}}=N_{\text{comunes}}+k\,n_\ell\,(3dh)

Mixtral 8x7B (Jiang et al., 2024, tabla 1): d=4 096d=4\,096, h=14 336h=14\,336, nℓ=32n_\ell=32, E=8E=8, k=2k=2. Salen 46.7 mil millones en total y 12.9 activos. El artículo lo dice así: el cálculo es proporcional a los parámetros activos, pero «el costo de memoria para servir Mixtral es proporcional a su cantidad de parámetros dispersos, 47B». Si cada token eligiera sus dos expertos al azar (supuesto: en la práctica el reparto es desigual), un lote de BB tokens tocaría en cada bloque una fracción 1−(1−k/E)B1-(1-k/E)^B de los expertos: 25 % con B=1B=1, 90 % con B=8B=8, 99 % con B=16B=16.

En código

Caché, techo de velocidad y costo con la arquitectura de Llama 3 8B:

capas, cabezas_kv, dim_cabeza, bytes_num = 32, 8, 128, 2
kv_por_token = 2 * capas * cabezas_kv * dim_cabeza * bytes_num      # 2 = clave y valor
print(kv_por_token)                                                  # bytes por token

pesos = 8.03e9 * 2                                                   # FP16: 2 bytes por parámetro
print(round(kv_por_token * 128_000 / 1e9, 2))                        # GB de una conversación de 128 000 tokens

ancho_banda = 3.35e12                                                # H100 SXM: 3.35 TB/s
print(round(ancho_banda / pesos, 1))                                 # techo de tokens/s con una persona

def servir(personas, contexto, usd_por_hora=2.0):
    bytes_por_vuelta = pesos + personas * contexto * kv_por_token    # pesos + una caché por persona
    t = bytes_por_vuelta / ancho_banda                               # segundos por vuelta
    rendimiento = personas / t                                       # tokens/s de todo el sistema
    return round(1 / t, 1), round(rendimiento), round(usd_por_hora / (3600 * rendimiento) * 1e6, 3)

print(servir(1, 8000))     # (tokens/s por persona, tokens/s totales, US$ por millón)
print(servir(60, 8000))
# 131072
# 16.78
# 208.6
# (195.8, 196, 2.837)
# (42.4, 2545, 0.218)

La caché no cambia el resultado: atención de una cabeza con y sin caché.

import numpy as np

rng = np.random.default_rng(0)
d = 8
Wq, Wk, Wv = (rng.normal(size=(d, d)) for _ in range(3))
x = rng.normal(size=(6, d))                          # 6 tokens (ya convertidos en vectores)

def atencion_sin_cache(x):                           # recalcula K y V de todos los tokens
    q, k, v = x @ Wq, x @ Wk, x @ Wv
    s = q @ k.T / np.sqrt(d)
    s = np.where(np.tril(np.ones_like(s)) == 1, s, -np.inf)       # máscara causal
    w = np.exp(s - s.max(1, keepdims=True)); w /= w.sum(1, keepdims=True)
    return w @ v

K, V, salida = [], [], []                            # con caché: un token por vuelta
for t in range(len(x)):
    q = x[t] @ Wq
    K.append(x[t] @ Wk); V.append(x[t] @ Wv)         # solo el par nuevo entra a la caché
    s = np.array(K) @ q / np.sqrt(d)
    w = np.exp(s - s.max()); w /= w.sum()
    salida.append(w @ np.array(V))

print(np.allclose(atencion_sin_cache(x), np.array(salida)))
# True

Lo que viene

Los sistemas reales añaden más piezas: PagedAttention reparte la caché en bloques para no desperdiciar memoria (vLLM: de 2 a 4 veces más rendimiento con la misma latencia que sistemas anteriores, Kwon et al., 2023); el batching continuo mete y saca conversaciones del lote en cada vuelta (Orca, Yu et al., 2022); y la decodificación especulativa dio de 2 a 3 veces más velocidad en T5-XXL «con salidas idénticas» (Leviathan et al., 2023) y de 2 a 2.5 veces en Chinchilla 70B (Chen et al., 2023). Todo esto sirve a un modelo base; convertirlo en asistente empieza con el ajuste fino, en la lección 27.

Lente de decisión

Qué significa esta idea si tu trabajo es decidir, no programar.

  • Costo por tarea = tokens de entrada × precio de entrada + tokens de salida × precio de salida. Pide el desglose por tipo de tarea: resumir (entrada larga, salida corta) no se parece a redactar (al revés). Estima tu volumen real en tokens antes de presupuestar.
  • La espera depende del largo del contexto: el primer token tarda más cuanto más texto envías, y cada token posterior sale más lento con contextos largos. Pide el tiempo hasta el primer token y los tokens por segundo medidos con textos del largo de los tuyos, no los de la ficha comercial.
  • Pregunta por la caché de prompt. Si el inicio de tus mensajes se repite (instrucciones, un documento base), reutilizarlo baja el costo y la espera: en la lista de Anthropic, leer de esa caché cuesta una décima parte del precio de entrada o menos (escribir la primera vez cuesta algo más: 1.25 veces).
  • Al comparar modelos o proveedores, mira más que los «parámetros»: parámetros activos (mezcla de expertos), largo del contexto, precio de entrada y de salida. Si alojas tú el modelo, el costo por token depende de cuánto llenes la GPU: con los supuestos de la lección, atender a una persona sola cuesta unas trece veces más por token que un lote lleno.

Términos de la lección

Transcripción completa
ComentariosConversación pública de esta lección: dudas, datos por revisar, ideas.

Los comentarios viven en GitHub Discussions, en el repositorio público del curso; para escribir se necesita una cuenta de GitHub. Se cargan desde giscus.app al abrir esta sección. Las personas que revisan el curso los leen, y si un cambio se acepta, se aplica en los dos idiomas. Abrir el hilo en GitHub

Fuentes