
La reproducibilidad ha sido siempre un pilar de la investigación científica, pero al trabajar con modelos de lenguaje grandes (LLM), esta tarea se complica más de lo que parece. Aunque podría suponerse que ajustar la temperatura a cero garantizaría respuestas repetibles, en la práctica, los resultados pueden variar incluso en condiciones aparentemente idénticas.
La falsa promesa del determinismo con temperatura cero
Muchos desarrolladores creen que si configuran la temperatura en cero en un modelo como ChatGPT, obtendrán siempre la misma salida para una entrada dada. Sin embargo, esto rara vez ocurre. La razón es que los sistemas de inferencia no son completamente deterministas, aunque a nivel teórico la ausencia de muestreo estocástico debería garantizarlo. Incluso usando librerías de código abierto como vLLM o SGLang, los resultados pueden variar de una ejecución a otra.
Flotantes y concurrencia: el mito incompleto
Una de las explicaciones más comunes apunta a la combinación de la aritmética de punto flotante no asociativa y la ejecución concurrente como culpables. Aunque esta hipótesis tiene algo de cierto, no cuenta toda la historia. Por ejemplo, realizar una multiplicación de matrices repetidamente en una GPU puede arrojar resultados idénticos en cada ejecución, a pesar del uso de flotantes y concurrencia.
La aritmética en punto flotante no siempre conserva propiedades como la asociatividad. Esto significa que el orden en el que se suman los números afecta al resultado, especialmente cuando se combinan valores con exponentes muy distintos. Esta variabilidad se amplifica cuando se agregan miles de valores flotantes en diferentes órdenes, lo que puede generar salidas distintas.
El problema real: falta de invariancia ante el batch
La razón principal por la que la inferencia en LLMs no es determinista no radica tanto en los flotantes ni en los hilos concurrentes, sino en la forma en que se gestiona la carga de trabajo en los servidores. Cuando haces una petición a un modelo, esta se procesa junto con otras en un lote (batch). Si el tamaño de este lote cambia, las operaciones internas también lo hacen, lo que altera el resultado final.
Este fenómeno se conoce como falta de invariancia ante el batch. Aunque cada componente de un modelo como RMSNorm o la atención puede ser determinista de forma aislada, su resultado puede variar si se cambia el número de elementos procesados simultáneamente.
Transformando los kernels para lograr invariancia
Para resolver el problema, es necesario rediseñar los códigos de bajo nivel (kernels) usados en la inferencia. Esto implica garantizar que operaciones clave como la normalización RMS, la multiplicación de matrices y la atención se comporten igual sin importar el tamaño del lote.
Por ejemplo, en la operación RMSNorm se puede adoptar una estrategia de paralelismo por dato, donde cada hilo de procesamiento se encarga de un solo elemento del batch. Esta técnica mantiene la invariancia si se conserva para todos los tamaños. Si el lote es muy pequeño, podría haber necesidad de dividir las operaciones, lo cual rompe la invariancia. Una solución es usar una estrategia de reducción fija, aceptando una ligera pérdida de rendimiento a cambio de estabilidad.
En la multiplicación de matrices, el problema es similar. Si el lote es demasiado pequeño, el código puede cambiar el tipo de instrucciones utilizadas (por ejemplo, desactivar los tensor cores), lo que altera el orden de las operaciones. Una solución es fijar el uso de una sola configuración de kernel para todos los casos, incluso si no es la más eficiente.
El caso complejo de la atención
La atención introduce retos adicionales porque involucra dos multiplicaciones de matrices y opera sobre dimensiones de secuencia y de características. Algunas optimizaciones, como dividir las secuencias para preprocesarlas, pueden cambiar el orden de reducción y afectar el resultado. La clave es asegurarse de que, sin importar cuántos tokens se procesen a la vez o cuántos estén en caché, el orden de operaciones se mantenga constante.
Para ello, se pueden usar estrategias de división fija, donde el tamaño de cada fragmento de la operación es constante, aunque el número de fragmentos varíe. Esto evita que el sistema decida dividir de manera distinta según el tamaño del batch, preservando la invariancia.
Resultados prácticos: completaciones consistentes y aprendizaje por refuerzo fiable
Al aplicar estos cambios en librerías como vLLM y crear kernels invariantes al batch, los resultados mejoran significativamente. Por ejemplo, al generar 1000 respuestas con temperatura cero a la pregunta «Cuéntame sobre Richard Feynman», se obtuvieron 80 variaciones. Con los kernels modificados, las 1000 respuestas fueron idénticas.
Esto no solo tiene implicaciones en la estabilidad de las respuestas al usuario, sino también en el entrenamiento. En algoritmos de aprendizaje por refuerzo, si el modelo no produce siempre la misma respuesta ante el mismo estado, se rompe la coherencia entre el entrenamiento y la inferencia. Con estos cambios, es posible entrenar de forma completamente en-política, es decir, con 0 divergencia KL entre el generador y el modelo evaluador, eliminando la necesidad de correcciones por muestreo fuera de la política.
Un cambio de paradigma en la fiabilidad de los LLM
Superar la no determinación en la inferencia de modelos de lenguaje no es solo una cuestión técnica; también redefine cómo concebimos la estabilidad y la confianza en estos sistemas. Lo que antes se consideraba un comportamiento aceptable debido a la naturaleza probabilística de los modelos ahora puede controlarse de forma precisa. Y con ello, se abre la puerta a aplicaciones más rigurosas, como el uso en sistemas críticos o entrenamiento de agentes con feedback humano directo.
☞ El artículo completo original de Natalia Polo lo puedes ver aquí
