36 Cuantización, destilación y poda
Dónde estamos. Seguimos en eficiencia (Parte VI). El Cap. 34 abarató la atención; aquí abaratamos el modelo entero: hacerlo más pequeño y barato de ejecutar sin perder (mucha) calidad. Tres familias que se combinan —cuantización (menos bits), destilación (entrenar un alumno pequeño) y poda (quitar pesos)—, con su mecánica y sus compromisos honestos.
36.1 La idea en una frase
Un modelo entrenado se puede encoger por tres vías ortogonales —usar menos bits por peso, enseñar a un modelo pequeño a imitar a uno grande, o quitar pesos que sobran—, cambiando siempre algo de calidad por tamaño, velocidad y coste.
36.2 Conceptos clave y su papel en el transformer
Antes de entrar en detalle, definimos los términos de este capítulo y para qué sirve cada uno dentro de un transformer:
- Cuantización. Definición: representar los pesos/activaciones con menos bits (FP32 → INT8 → 4 bits). En el transformer: recorta memoria y ancho de banda —la vía más usada para que un modelo grande quepa y vaya rápido—.
- Escala y zero-point. Definición: los dos números del mapa \(x \approx S\,(x_q - Z)\) que traducen entre el real y el entero. En el transformer: definen cómo se redondea cada peso a pocos bits sin perder su rango.
- PTQ vs QAT. Definición: cuantizar después de entrenar (barato) vs simular la cuantización durante el entrenamiento (mejor a bits muy bajos, caro). En el transformer: PTQ es lo habitual; QAT, para los casos extremos.
- Outliers de activación. Definición: unas pocas dimensiones con valores enormes que rompen la cuantización ingenua. En el transformer: aparecen a escala (~6.700 M parámetros) y obligan a tratarlas aparte (LLM.int8, SmoothQuant).
- Cuantización de la caché KV. Definición: aplicar la cuantización no a los pesos, sino a la caché KV (las claves/valores guardados al generar). En el transformer: ataca el glotón de memoria del contexto largo; es ortogonal a comprimir los pesos.
- Destilación. Definición: entrenar un modelo alumno pequeño para imitar la distribución de un maestro grande. En el transformer: transfiere capacidad a un modelo más barato de servir.
- Objetivos suaves y temperatura. Definición: la distribución completa de probabilidades del maestro (no solo la respuesta), suavizada con una temperatura \(T\). En el transformer: es la “información oscura” que enseña más que la etiqueta dura.
- Poda (estructurada vs no estructurada). Definición: eliminar pesos individuales (no estructurada) o bloques enteros —cabezas, neuronas, capas— (estructurada). En el transformer: la estructurada acelera de verdad en hardware normal; la no estructurada necesita soporte específico.
- Esparsidad. Definición: la fracción de pesos puestos a cero. En el transformer: más esparsidad = modelo más ligero, hasta que la calidad cae.
Con esto en mano, vamos familia por familia.
36.3 Por qué comprimir
Un modelo entrenado es caro en cuatro ejes: memoria (ocupa decenas de GB), ancho de banda (mover esos pesos), energía y latencia/coste. Comprimirlo busca que quepa (en una sola GPU, en un móvil) y que servir salga barato. Las tres familias son ortogonales y componibles: la cuantización es la “primera mano” (la más barata); la destilación pide presupuesto de entrenamiento; la poda cambia la forma del modelo.
36.4 Cuantización: menos bits por peso
Cuantizar es aproximar un valor real por escala × entero: \(x \approx S\,(x_q - Z)\), donde \(S\) (la escala) fija el tamaño del paso y \(Z\) (el zero-point) marca qué entero representa el cero real (Jacob et al. 2018). Se puede aplicar por tensor (un \(S\) para todo), por canal (uno por fila/columna) o por grupo (bloques de, p. ej., 128 pesos, cada uno con su escala) —a más fino, más fiel, más metadatos— (Nagel et al. 2021).
El viaje de un peso, de real a comprimido y de vuelta:
La distinción de método clave es cuándo se cuantiza: PTQ (post-training quantization) cuantiza un modelo ya entrenado —barato, sin reentrenar— y QAT (quantization-aware training) simula la cuantización durante el entrenamiento —mejor a bits muy bajos, pero caro—.
🧩 Analogía — 16 lápices en vez de un millón de tonos. Cuantizar es describir los colores con 16 lápices de colores en lugar de un millón de matices: para casi todo se ve igual de bien y pesa muchísimo menos. La escala es cuán separados están los tonos de tu caja; el zero-point, cuál de ellos es el “blanco”.
El problema a escala: los outliers. En LLMs grandes, unas pocas dimensiones de activación tienen valores gigantescos que, al cuantizar a la brava, dominan el rango y destrozan la precisión del resto. Las soluciones modernas (todas PTQ):
- LLM.int8() (Dettmers et al. 2022): detecta esas dimensiones outlier y las calcula aparte en 16 bits, mientras el >99,9 % restante va en 8 bits → INT8 sin pérdida hasta 175 000 M. (Los outliers emergen sobre ~6.700 M parámetros.)
- SmoothQuant (Xiao et al. 2023): como las activaciones son difíciles de cuantizar pero los pesos no, migra la dificultad de las activaciones a los pesos con una transformación equivalente → W8A8 (pesos y activaciones en 8 bits) casi sin pérdida.
- GPTQ (Frantar et al. 2023): cuantización one-shot a 3-4 bits usando información de segundo orden (Hessiana) para corregir el error; cuantiza un 175B en ~4 horas de GPU.
- AWQ (Lin et al. 2024): identifica el ~1 % de pesos “salientes” (por la activación, no por el peso) y los protege con un reescalado —evitando la precisión mixta—.
🧩 Analogía — las voces que distorsionan. Los outliers son como unas pocas voces muy fuertes en un coro: si las grabas con el mismo micro que al resto, saturan toda la mezcla. Hay que ponerles una pista de alta fidelidad aparte (los 16 bits de LLM.int8) y el resto se graba normal.
Estos outliers, por cierto, no son un capricho aislado de la cuantización: se parecen sospechosamente a las massive activations y a los sumideros de atención del Capítulo 18, donde dejamos planteada la pregunta abierta de si son el mismo fenómeno.
La frontera de bits: 8 bits ≈ sin pérdida; 4 bits casi sin pérdida con buenos métodos (proteger el ~1 %); por debajo de ~3-4 bits hay un “precipicio” que daña desproporcionadamente mates y código.
El 4-bit clásico (INT4) reparte los valores en una rejilla uniforme de enteros, y por eso sufre con los outliers. La novedad de 2025-26 es cuantizar a 4 bits en coma flotante: el formato E2M1 (1 bit de signo, 2 de exponente, 1 de mantisa) más una escala compartida por bloque. Al tener exponente, cubre mucho mejor el rango dinámico que una rejilla entera. Dos variantes: MXFP4 (bloques de 32 → 4,25 bits/peso) y NVFP4 (NVIDIA 2025) (bloques de 16, escala más fina → más precisión). Con soporte nativo en hardware (GPU Blackwell) y en vLLM/TensorRT-LLM, rinde hasta ~2–2,3× frente a BF16 con degradación mínima. De hecho, gpt-oss (OpenAI 2025) —el modelo de pesos abiertos de OpenAI— publica sus pesos MoE directamente en MXFP4. Es el sucesor real de INT4 para inferencia.
Si alguna vez descargas un modelo para correrlo en tu propio ordenador (con llama.cpp, Ollama o LM Studio), te toparás con GGUF: un formato de fichero que empaqueta el modelo ya cuantizado, listo para usar (Gerganov y llama.cpp contributors 2023). Verás nombres como Q4_K_M, Q5_K_M o Q8_0. Se leen así: el número (4, 5, 8) son los bits por peso; la K avisa de que es cuantización por grupo (los llamados k-quants, más fieles); y la letra final (S/M/L) es cuánta precisión extra reserva para las capas sensibles (M = “media”). Regla de bolsillo del mundo local: Q4_K_M es el punto dulce tamaño/calidad para casi todo; Q8_0 si te sobra memoria; por debajo de Q3 la calidad ya se resiente. En el fondo no es nada nuevo —es “por grupo + proteger lo sensible” (lo que ya viste arriba) con nombres propios de usuario—. (¿Qué nivel aguanta tu modelo sin desmoronarse? El Quant-regime Classifier de tafagent lo estima a partir de su perfil.)
BitNet b1.58 (Ma et al. 2024) lleva cada peso a ternario {−1, 0, 1} (≈1,58 bits) y afirma igualar a un modelo FP16 del mismo tamaño. Dos matices honestos: (1) iguala a FP16 solo a partir de ~3.000 M parámetros; (2) no es cuantización post-entrenamiento, sino QAT desde cero (hay que reentrenar el modelo con esa restricción). Resultado prometedor, pero de un solo equipo y aún sin réplica independiente amplia a gran escala.
36.5 Cuantizar la caché KV (no solo los pesos)
Todo lo anterior encoge los pesos del modelo. Pero hay un segundo glotón de memoria que los pesos ni tocan: al generar en contexto largo, quien se lo come todo es la caché KV (Cap. 20) —las claves y los valores de cada token ya leído, que el modelo guarda para no recalcularlos—. Con un prompt muy largo, esa caché puede ocupar más que el propio modelo. Buena noticia: también se puede cuantizar.
KVQuant (Hooper et al. 2024) baja la caché a ~4 bits o menos con dos trucos que merece la pena entender, porque explican por qué la caché es especial:
- Las claves se cuantizan por canal (una escala por dimensión), no por token —porque, igual que las activaciones, tienen sus propios outliers que arruinarían un redondeo a la brava (misma idea que con los pesos, arriba)—.
- El primer token (el sumidero de atención, Cap. 17) se trata aparte, en alta precisión, porque acumula muchísima masa y cuantizarlo a lo bruto duele.
Con eso, un contexto que no cabía pasa a caber, estirando la longitud viable hasta millones de tokens en la misma GPU. Y no hace falta irse a lo exótico: los motores de serving habituales (vLLM, TensorRT-LLM) ya ofrecen caché KV en 8 bits casi gratis (Cap. 36).
🧩 Analogía. Cuantizar los pesos es comprar una estantería más pequeña; cuantizar la caché KV es usar cajas más pequeñas para lo que vas apuntando mientras lees. En un texto corto la estantería manda; en uno larguísimo, las cajas acaban ocupando más que la estantería —por eso, en contexto largo, cuantizar la KV es tan importante como cuantizar el modelo—.
Y aquí está el enganche con nuestro tema: cuantizar la KV la hace más pequeña por token (menos bits por entrada). Nuestra ventana D_f basada en γ (Cap. 20) decide algo distinto: cuántos tokens de KV merece la pena guardar (menos entradas). Son dos palancas ortogonales —bits por entrada × número de entradas— y por eso se multiplican: puedes aplicar las dos a la vez.
36.6 Destilación: enseñar a un alumno pequeño
Entrenar un modelo alumno (pequeño) para que imite no solo la respuesta del maestro (grande), sino su distribución completa de probabilidades —los objetivos suaves—, suavizada con una temperatura \(T\) que agranda las diferencias entre opciones poco probables (Hinton et al. 2015). Esa “información oscura” (que el maestro vea “probablemente gato, quizá perro, seguro no coche”) enseña más que la etiqueta dura “gato”.
(Detalle de la pérdida: como los gradientes de los objetivos suaves escalan como \(1/T^2\), se multiplican por \(T^2\) al combinarlos con la etiqueta dura, para que ambos pesen parecido.)
🧩 Analogía — el maestro que enseña el matiz. En vez de decirle al aprendiz solo la respuesta final (“es un gato”), el maestro le transmite el matiz: “esto es casi seguro un gato, podría confundirse con un perro, jamás con un coche”. Ese reparto de dudas es lo que de verdad enseña a generalizar.
El caso canónico es DistilBERT (Sanh et al. 2019): 40 % más pequeño, 60 % más rápido y conserva ~97 % de la capacidad de BERT, con una triple pérdida (modelado de lenguaje + destilación + distancia coseno). TinyBERT (Jiao et al. 2020) va más allá y destila también las matrices de atención y los estados intermedios (7,5× más pequeño). Para generación, la destilación a nivel de secuencia (Kim y Rush 2016) entrena al alumno sobre las salidas del maestro —la base de “destilar” un LLM grande en uno pequeño—. Honesto: ojo con el sentido laxo de “destilar” = entrenar con las salidas de un modelo mejor; como vimos (Cap. 27 (Gudibande et al. 2023)), eso copia el estilo, no la capacidad.
36.7 Poda: quitar lo que sobra
Eliminar pesos para encoger el modelo. No estructurada: poner a cero pesos individuales → alta esparsidad, pero necesita hardware especial para acelerar. Estructurada: quitar bloques enteros (cabezas, neuronas, capas) → más rápida en hardware normal.
El telón de fondo conceptual es la hipótesis del billete de lotería (Frankle y Carbin 2019): dentro de una red densa hay subredes (“billetes premiados”) que, entrenadas solas, igualan a la original —es decir, gran parte de los pesos sobran—. En LLMs, la poda one-shot moderna lo explota: SparseGPT (Frantar y Alistarh 2023) poda ≥50 % de los pesos de un 175B sin reentrenar y con pérdida mínima; Wanda (Sun et al. 2024) hace algo más simple —podar por |peso| × ‖activación de entrada‖—, también sin reentrenar.
Y enlaza con el Cap. 5: se pueden podar cabezas de atención enteras —Michel et al. (Michel et al. 2019) quitaron muchas sin apenas pérdida; Voita et al. (Voita et al. 2019) podaron 38 de 48 cabezas con solo −0,15 BLEU—.
🧩 Analogía — podar el árbol. La poda es cortar las ramas secas de un árbol: queda más ligero pero sigue siendo el mismo árbol. La estructurada quita ramas enteras (se nota al levantarlo); la no estructurada quita hojas sueltas por todas partes (pesa menos, pero cargarlo cuesta casi igual si no tienes la carretilla adecuada).
Poner pesos a cero dispersos rara vez acelera en una GPU normal: el hardware no sabe “saltarse” ceros repartidos al azar. Por eso SparseGPT/Wanda apuntan a patrones 2:4 (dos de cada cuatro a cero), que las GPU recientes sí aceleran. Moraleja: la poda estructurada suele ganar en la práctica; la no estructurada, solo con soporte de hardware.
36.8 Cómo se combinan, y el compromiso honesto
El orden típico de “alcance”: cuantización (lo más barato y usado) → destilación (si puedes entrenar) → poda (cambio de forma). Y se componen: SparseGPT se combina con cuantización; QLoRA (Cap. 28) es base de 4 bits + LoRA. La regla universal y honesta: toda compresión cambia algo de calidad por tamaño/velocidad; el arte es encontrar el codo de la curva.
No te fíes solo de la perplejidad: la compresión daña desproporcionadamente los comportamientos raros (mates, código, casos de cola larga). Mide también tareas downstream, robustez y casos poco frecuentes antes de dar por buena una versión comprimida.
36.9 Puente con nuestro tema (breve y honesto)
La cuantización de pesos y la poda son reducciones agnósticas al contenido. Incluso cuantizar la caché KV (la sección de arriba) es agnóstico: encoge cada entrada por igual, sin mirar cuál importa. Nuestra ventana D_f basada en γ (Cap. 20) hace algo distinto y complementario —decide qué tokens de la caché conservar, de forma consciente del contenido—: es un eje ortogonal, no un método rival, y se combina con cuantizar la KV (menos bits × menos entradas). Y la poda de cabezas encaja con nuestra observación de que distintas cabezas decaen distinto (su γ por cabeza): unas importan más que otras —coherente tanto con la poda de cabezas como con nuestro γ por cabeza, sin afirmar causalidad—.
tafagent trabaja en un eje complementario a la compresión de pesos: te calcula el presupuesto de KV (memoria de caché) a partir de γ (Cap. 20). Si cuantizas y/o podas un modelo para que quepa, mide además su γ para saber cuánta caché necesitarás al servirlo en contexto largo —las dos palancas se suman—.
36.10 Resumen
- Tres familias componibles: cuantización (menos bits), destilación (alumno pequeño), poda (quitar pesos). Toda compresión cambia calidad por tamaño/velocidad.
- Cuantización: mapa \(x\approx S(x_q-Z)\); PTQ (barato) vs QAT (mejor a bits bajos). El reto a escala son los outliers → LLM.int8 (16 bits aparte), SmoothQuant (migra a pesos), GPTQ (3-4 bits, Hessiana), AWQ (protege el ~1 %). 8 bits ≈ sin pérdida; 4 bits casi; sub-4-bit contestado (BitNet, QAT desde cero).
- Formato local (GGUF/k-quants): Q4_K_M es el punto dulce para correr en tu propio equipo. Y no solo se cuantizan pesos: la caché KV también (KVQuant (Hooper et al. 2024); 8-bit casi gratis en vLLM), clave en contexto largo y ortogonal a D_f (γ), que elige qué tokens guardar.
- Destilación (Hinton et al. 2015): el alumno imita los objetivos suaves (temperatura \(T\), “información oscura”) del maestro. DistilBERT (40 % menor, 97 % de calidad). Honesto: imitar salidas copia estilo, no capacidad.
- Poda: estructurada (acelera en HW normal) vs no estructurada (necesita soporte); SparseGPT/Wanda podan ~50 % one-shot; poda de cabezas (Cap. 5). La esparsidad dispersa no siempre acelera (de ahí el patrón 2:4).
- Evaluar: no solo perplejidad — la compresión daña lo raro (mates/código).
- Puente: compresión = agnóstica al contenido (pesos); D_f (γ) = consciente del contenido (caché KV), eje ortogonal.
Siguiente (Capítulo 36): con el modelo ya eficiente y comprimido, cerramos la Parte VI con servir y desplegar —throughput, batching continuo, paginación del KV-cache, latencia vs coste—.
36.11 Ejercicios
- El mapa. En \(x \approx S\,(x_q - Z)\), ¿qué papel juegan \(S\) y \(Z\)? ¿Qué gana la cuantización por grupo frente a por tensor?
- PTQ vs QAT. ¿Cuándo merece la pena el coste de QAT frente a la comodidad de PTQ?
- Outliers. ¿Por qué unas pocas dimensiones rompen la cuantización ingenua, y cómo lo resuelve LLM.int8()?
- Objetivos suaves. ¿Qué enseña la distribución completa del maestro que la etiqueta dura no? ¿Para qué sirve la temperatura \(T\)?
- Poda. ¿Por qué la poda estructurada suele acelerar más que la no estructurada en una GPU normal?
- Honestidad. ¿Por qué no basta la perplejidad para evaluar un modelo comprimido?
- Dos glotones. En generación de contexto largo, ¿qué crece más rápido con la longitud: la memoria de los pesos o la de la caché KV? ¿Por qué cuantizar la KV y usar D_f (γ) no son rivales, sino que se suman?