⏱️ Lectura: 13 min

Corriste el mismo checkpoint de Qwen3.6-27B en tu máquina y en la demo oficial del laboratorio, y las respuestas no coinciden ni de cerca. No es tu imaginación ni un modelo roto: es la firma numérica de la pila de inferencia que armaste, y tiene nombre técnico, KL divergence.

📑 En este artículo
  1. TL;DR
  2. Introducción
  3. Qué pasó
  4. Contexto e historia
  5. Detalles técnicos y rendimiento: midiendo la KL divergence
  6. Cómo empezar a medirlo
    1. Linux (recomendado, soporte nativo de CUDA)
    2. macOS (Apple Silicon, sin aceleración CUDA)
    3. Windows (vía WSL2)
  7. Impacto y análisis
  8. Qué sigue
  9. Preguntas frecuentes
    1. ¿Qué es la KL divergence aplicada a un LLM?
    2. ¿Por qué mi modelo cuantizado en Ollama se siente peor que la demo oficial del laboratorio?
    3. ¿Un KLD bajo garantiza que el modelo cuantizado es igual de inteligente?
    4. ¿Qué backend de atención debería usar en mi GPU?
    5. ¿Por qué mi modelo se queda atrapado dentro de una etiqueta think sin terminar?
    6. ¿Sirven los benchmarks con tres prompts a temperatura cero para evaluar un LLM local?
  10. Referencias

Un análisis publicado el 16 de agosto de 2026 en los foros de Level1Techs desarma, capa por capa, por qué dos instancias del mismo modelo (misma arquitectura, mismos pesos) producen tokens distintos según el backend de atención, la cuantización y la configuración del sampler.

TL;DR

  • El foro Level1Techs publicó el 16 de agosto de 2026 un análisis sobre por qué un LLM local rinde distinto al original.
  • La KL divergence mide cuánto se aleja la distribución de probabilidad de tokens de tu inferencia respecto a un baseline.
  • El experimento usó Qwen3.6-27B en BF16 sobre una RTX PRO 6000 Blackwell con tensor parallelism 1 y sin cuantización de KV cache.
  • El contenedor nightly de vLLM probado incluía 734 paquetes, 252 de ellos instalados vía uv/pip en Python.
  • Cada backend de atención usa kernels CUDA distintos según la compute capability de la GPU, lo que cambia la precisión del prefill.
  • Una temperatura de sampler demasiado baja puede dejar a modelos como Qwen atrapados en bucles dentro de la etiqueta think.
  • Comparar con tres prompts a temperatura cero no representa tareas agénticas: hacen falta evaluaciones de contexto largo y tool-calling.

Introducción

La KL divergence (divergencia de Kullback-Leibler) es la métrica técnica detrás de este fenómeno: mide cuánto se aleja la distribución de probabilidad de tu inferencia local de un baseline de referencia. No mide inteligencia directamente, mide distancia entre distribuciones de tokens.

El punto de partida del análisis es simple: cada combinación de hardware y software que corre un LLM hoy es distinta, y esa diferencia empieza mucho antes de que veas el primer token. GPUs de generaciones mezcladas, distintos sets de instrucciones, kernels CUDA compilados para compute capabilities específicas: todo eso cambia cómo se calcula matemáticamente el siguiente token, incluso corriendo exactamente los mismos pesos.

Qué pasó

El usuario thr3e publicó en la categoría Machine Learning, LLMs, & AI del foro de Level1Techs una serie de experimentos técnicos diseñados para aislar, uno por uno, los puntos donde una implementación local diverge de lo que el laboratorio que entrenó el modelo (lo que el autor llama reference implementation) reporta en sus benchmarks originales.

El experimento base corrió el checkpoint oficial en BF16 de Qwen3.6-27B sobre una GPU RTX PRO 6000 Blackwell, con tensor parallelism en 1 y sin ningún tipo de cuantización de pesos, activaciones ni KV cache. Para eliminar variables, el autor desactivó CUDA graphs, prefix caching y MTP (multi-token prediction), y forzó ejecución en modo eager.

La pila de software usada fue una build nightly de vLLM, fijada a una versión específica para que los resultados fueran reproducibles. Ese detalle importa: el propio autor midió que la imagen de contenedor nightly de vLLM que descargó traía 734 paquetes, de los cuales 252 son paquetes de Python instalados vía uv/pip. Son 734 bases de código distintas, cada una con sus propios bugs y comportamientos no documentados, en el camino entre tu prompt y el texto que ves en pantalla.

Pila de inferencia de un LLM local con múltiples componentes de software
El contenedor nightly de vLLM probado traía 734 paquetes distintos. Foto de Steve A Johnson en Unsplash

Contexto e historia

Para entender qué mide la KL divergence primero hay que entender qué es un logit. Un logit es el puntaje crudo que el modelo le asigna a cada token posible como candidato a ser el siguiente. Esos puntajes se normalizan en probabilidades con una función softmax, pasan por un sampler configurado (temperatura, top-p, top-k) y el detokenizer los convierte de vuelta en texto legible, token por token.

La divergencia de Kullback-Leibler es un concepto de teoría de la información de 1951 que cuantifica cuánto se aleja una distribución de probabilidad de otra tomada como referencia. Aplicada a un LLM: se convierten los logits de salida en una distribución de probabilidad y se mide qué tan lejos está esa distribución de la que produce el checkpoint de referencia en la misma posición del texto.

Un detalle que el análisis remarca: la KL divergence es direccional. El orden de las dos distribuciones que comparás importa, invertirlo no da el mismo número. Y un KLD más bajo significa más cerca del baseline elegido, no más inteligente: son dos afirmaciones distintas que suelen confundirse.

⚠️ Ojo: no confundas un KLD bajo publicado en la ficha de un modelo cuantizado con misma calidad que el original. Sin conocer el checkpoint de referencia exacto, el entorno de ejecución completo, el texto de evaluación, los datos de calibración, el largo de contexto, las posiciones muestreadas, la dirección del cálculo y cómo se agregaron las mediciones, ese número no se puede interpretar.

Detalles técnicos y rendimiento: midiendo la KL divergence

Durante el prefill (el procesamiento inicial del prompt completo), el motor de inferencia elige entre varios backends de atención disponibles. Esa elección no es cosmética: cada backend usa kernels CUDA distintos, compilados para arquitecturas y compute capabilities específicas, y eso afecta tanto la velocidad como la precisión numérica del resultado.

BackendCuándo usarloVentajaLimitación
FlashAttention-2GPUs Ampere, Hopper o Blackwell con soporte nativoPrefill más rápido con buena precisión numéricaKernels específicos por familia de GPU, no cubre todo el hardware
FlashInferDecode con KV cache paginadoBuen balance entre velocidad y precisión en generaciónHay que compilarlo contra tu versión exacta de CUDA
xFormersGPUs más antiguas sin soporte de FlashAttentionCompatibilidad ampliaPrefill más lento y mayor uso de memoria
Eager (PyTorch nativo)Debugging y validación de precisiónMáxima fidelidad numérica como referenciaDemasiado lento para producción

El análisis de Level1Techs corrió su primer experimento (comparación de backends de atención por precisión) sobre esa base BF16 sin cuantizar, para aislar el efecto del backend del efecto de la cuantización. Es la única forma honesta de saber cuál de las dos variables mete más ruido en tu setup.

flowchart TD
A["Prompt de entrada"] --> B["Tokenizer"]
B --> C["Prefill: backend de atencion"]
C --> D["Logits crudos"]
D --> E["Sampler: temperatura y top-p"]
E --> F["Detokenizer"]
F --> G["Texto de salida"]

Para medir tu propia divergencia contra un baseline necesitás los logits crudos de ambos modelos en la misma posición del texto. Un script mínimo con la librería transformers se ve así:

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

modelo_id = "Qwen/Qwen3.6-27B"
tokenizer = AutoTokenizer.from_pretrained(modelo_id)
modelo = AutoModelForCausalLM.from_pretrained(
    modelo_id, torch_dtype=torch.bfloat16, device_map="cuda"
)

entrada = tokenizer("Que es un indice B+ en una base de datos?", return_tensors="pt").to("cuda")

with torch.no_grad():
    salida = modelo(**entrada)
    logits = salida.logits[:, -1, :]

print(logits.shape)

Ese fragmento carga el checkpoint de referencia y extrae los logits del último token. El resultado esperado es un tensor con forma [1, vocab_size]: un puntaje por cada token posible del vocabulario. Repetís el mismo proceso con tu modelo local (cuantizado, con otro backend) y comparás ambas distribuciones con KL divergence:

import torch.nn.functional as F

log_p_referencia = F.log_softmax(logits_referencia, dim=-1)
p_local = F.softmax(logits_local, dim=-1)

kld = F.kl_div(log_p_referencia, p_local, reduction="batchmean")
print(f"KL divergence en esta posicion: {kld.item():.6f}")

Cuanto más cerca de cero, más se parece tu distribución local a la de referencia en esa posición puntual. Para que el número signifique algo tenés que promediarlo sobre muchas posiciones y muchos prompts representativos de tu caso de uso real, no sobre tres prompts al azar con temperatura en cero.

Comparación de backends de atención en una GPU corriendo un LLM
Cada backend de atención usa kernels CUDA distintos según la GPU. Foto de Igor Omilaev en Unsplash

Cómo empezar a medirlo

Antes de correr nada, revisá el model card del checkpoint que vas a usar en Hugging Face: ahí suele especificarse el sampler recomendado (temperatura, top-p) y el chat template exacto. Usar los valores de otro modelo es una causa común de comportamientos raros.

💡 Tip: si tu Qwen se queda dando vueltas dentro de una etiqueta think sin salir nunca, revisá la temperatura antes que nada: una temperatura demasiado baja puede dejar al modelo atrapado repitiendo el mismo razonamiento sin converger a una respuesta.

Linux (recomendado, soporte nativo de CUDA)

python3 -m venv .venv
source .venv/bin/activate
pip install vllm
VLLM_ATTENTION_BACKEND=FLASHINFER vllm serve Qwen/Qwen3.6-27B --tensor-parallel-size 1 --dtype bfloat16

macOS (Apple Silicon, sin aceleración CUDA)

python3 -m venv .venv
source .venv/bin/activate
pip install vllm --extra-index-url https://download.pytorch.org/whl/cpu

Windows (vía WSL2)

wsl --install -d Ubuntu
wsl
python3 -m venv .venv
source .venv/bin/activate
pip install vllm

Para confirmar qué backend de atención terminó activo en tu proceso no hace falta adivinar: vLLM lo imprime explícitamente en el log de arranque del servidor, en una línea del estilo Using FlashInfer backend o Using FlashAttention backend. Si esa línea no coincide con lo que pusiste en VLLM_ATTENTION_BACKEND, tu GPU no soporta ese backend y el motor cayó a otro en silencio.

Impacto y análisis

La conclusión práctica del análisis es incómoda pero útil: tu implementación local nunca va a igualar bit a bit al benchmark que publicó el laboratorio, pero eso también es cierto para cualquier otra persona que no use exactamente el mismo hardware, el mismo build de software y la misma configuración que ese laboratorio. La pregunta relevante no es si es igual al original, sino qué tan lejos está y en qué dirección.

Esto tiene implicaciones directas para cómo se leen las fichas de modelos cuantizados en Hugging Face. Cuando una cuantización afirma un KLD extremadamente bajo sin publicar el checkpoint de referencia, el entorno de ejecución, el texto de calibración y la dirección del cálculo, ese número no se puede auditar. El análisis original lo dice sin rodeos: la metodología importa tanto como el número, y bastante gente la ignora.

También cuestiona un hábito extendido: evaluar un modelo con tres prompts a temperatura cero y sacar una conclusión sobre si sirve o no sirve. Ese tipo de prueba zero-shot no representa una tarea agéntica real, que necesita contexto largo, tool-calling y conocimiento específico de dominio para exponer dónde falla realmente tu setup frente a otro que corre los mismos pesos.

Qué sigue

El propio análisis deja la puerta abierta a una segunda mitad de la investigación: comparar cuantizaciones GGUF de distintos bits contra el baseline BF16 ya caracterizado, usando la misma metodología de KL divergence por posición. Eso permitiría separar, con datos propios y reproducibles, cuánto ruido mete el backend de atención frente a cuánto ruido mete la cuantización en sí.

A nivel de comunidad, la expectativa es que más fichas de modelos en Hugging Face empiecen a publicar la metodología completa de sus mediciones de KLD (checkpoint de referencia, entorno, datos de calibración) en lugar de un número aislado. Sin eso, cualquier comparación entre cuantizaciones de distintos autores sigue siendo, en la práctica, no auditable.

📖 Resumen en Telegram: Ver resumen

Probalo vos: instalá vLLM con pip install vllm, arrancá tu checkpoint favorito fijando VLLM_ATTENTION_BACKEND a un valor explícito y compará los logits contra la demo oficial del mismo modelo para ver tu propia KL divergence.

Preguntas frecuentes

¿Qué es la KL divergence aplicada a un LLM?

Es una métrica que compara la distribución de probabilidad de los tokens que genera tu inferencia local, en una posición dada del texto, contra la distribución que produce un checkpoint de referencia. Cuanto más cerca de cero, más se parecen ambas distribuciones en ese punto.

¿Por qué mi modelo cuantizado en Ollama se siente peor que la demo oficial del laboratorio?

Porque no solo cambia la cuantización: también cambia el backend de atención, la precisión del KV cache, el sampler por defecto y el chat template. Cada capa de esa pila diverge un poco del entorno con el que el laboratorio publicó sus benchmarks originales, y esas pequeñas diferencias se acumulan.

¿Un KLD bajo garantiza que el modelo cuantizado es igual de inteligente?

No. Un KLD bajo solo dice que la distribución de tokens está cerca del baseline elegido. Sin conocer la metodología completa (checkpoint de referencia, entorno, datos de calibración, dirección del cálculo), el número no es interpretable ni comparable con el de otro autor.

¿Qué backend de atención debería usar en mi GPU?

Depende de tu arquitectura y del caso de uso: FlashAttention-2 o FlashInfer para GPUs recientes con buen soporte, xFormers como alternativa en hardware más viejo, y eager solo para debugging por su lentitud. Confirmá siempre en el log de arranque cuál quedó activo.

¿Por qué mi modelo se queda atrapado dentro de una etiqueta think sin terminar?

Casi siempre es la temperatura del sampler configurada demasiado baja para ese modelo específico. Revisá el model card en Hugging Face y usá los valores de temperatura y top-p que el propio autor del modelo recomienda.

¿Sirven los benchmarks con tres prompts a temperatura cero para evaluar un LLM local?

No de forma representativa. Los benchmarks zero-shot con pocos prompts no capturan tareas agénticas reales con contexto largo y tool-calling. Se recomienda usar suites como terminal-bench, HLE o SWE-bench orientadas a tu caso de uso concreto.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Imagen destacada: Foto de Sandip Kalal en Unsplash


Andrés Morales

Desarrollador e investigador en inteligencia artificial. Escribe sobre modelos de lenguaje, frameworks, herramientas para devs y lanzamientos open source. Cubre papers de ML, ecosistema de startups tech y tendencias de programación.

0 Comentarios

Deja un comentario

Marcador de posición del avatar

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.