Entendiendo el Aprendizaje Automático Distribuido Moderno: Desde Programadores HPC hasta Motores de Servicio LLM
Hoy en día, los ingenieros de aprendizaje automático manejan un conjunto diverso de herramientas e ideas para entrenar y desplegar modelos a gran escala. Este artículo profundiza en varios temas clave: ejecutar trabajos con Contenedores de Aprendizaje Profundo (DLC), usar programadores por lotes de HPC como Volcano (VOLC) y SLURM, servicio eficiente de LLM con vLLM y SGLang, estructuras y parámetros de entrenamiento típicos, modos operativos (entrenamiento vs. inferencia), estrategias de paralelismo (DPTPPP – datos, canalización, paralelismo tensorial), el papel de los enrutadores y controladores en sistemas distribuidos, y estrategias de carga de datos para un alto rendimiento. Explicaremos cada concepto, daremos ejemplos (con muestras de código y configuración) y ofreceremos información práctica de manera técnica y precisa. Empecemos.
Contenedores de Aprendizaje Profundo (DLC) y Ejecución de Trabajos de ML
Los Contenedores de Aprendizaje Profundo (DLC) se refieren a imágenes de contenedores Docker preconstruidas que vienen con marcos de aprendizaje profundo populares y dependencias optimizadas y listas para ejecutarse. Por ejemplo, AWS proporciona DLC para TensorFlow, PyTorch, MXNet, etc., que incluyen compilaciones optimizadas (a menudo con soporte de GPU, bibliotecas como CUDA/cuDNN instaladas e incluso optimizaciones de red como EFA para entrenamiento de múltiples nodos). Estos contenedores garantizan un entorno consistente para que los investigadores no necesiten instalar manualmente marcos en cada máquina. Según AWS, los DLC están disponibles como imágenes Docker en Amazon ECR (Elastic Container Registry), y cada imagen está hecha a medida para una versión y tarea de marco específica (entrenamiento o inferencia) (Build high-performance ML models using PyTorch 2.0 on AWS – Part 1 | AWS Machine Learning Blog). Esto significa que puede elegir un contenedor que coincida con el marco que desee (por ejemplo, PyTorch 2.0 con CUDA 11) y estar seguro de que tiene todas las bibliotecas correctas.
Cómo funciona: En la práctica, usar un DLC implica extraer la imagen del contenedor y ejecutar su entrenamiento o inferencia dentro de él. Esto se puede hacer en una VM en la nube o en un servidor local con Docker instalado. Por ejemplo, después de iniciar una instancia de EC2 GPU, se podría hacer:
# Paso 1: Iniciar sesión en AWS ECR público (si es necesario) y extraer la imagen del DLC
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <aws_account>.dkr.ecr.us-west-2.amazonaws.com
docker pull <aws_account>.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.0.0-gpu-py310-cu118-ubuntu20.04-ec2
# Paso 2: Ejecutar el contenedor con un script de entrenamiento
docker run --gpus all -v /data:/data -it <aws_account>.dkr.ecr.us-west-2.amazonaws.com/pytorch-training:2.0.0-gpu-py310-cu118-ubuntu20.04-ec2 \
python /data/train.py --epochs 5 --batch-size 32
En el ejemplo anterior, extrajimos un DLC de entrenamiento AWS PyTorch 2.0 y luego ejecutamos un script de entrenamiento (train.py
) dentro de él. El indicador --gpus all
le da al contenedor acceso a las GPU NVIDIA en el host, y -v /data:/data
monta un directorio de datos del host en el contenedor. Este enfoque garantiza que el entorno dentro del contenedor tenga la versión correcta de PyTorch, CUDA, etc., lo que simplifica la ejecución del trabajo. También es portátil: el mismo contenedor se puede ejecutar en cualquier máquina con Docker, por lo que los experimentos son reproducibles.
Cuándo usar DLC: Los DLC son especialmente útiles en plataformas en la nube y servicios gestionados. Por ejemplo, los trabajos de entrenamiento de Amazon SageMaker usan imágenes de DLC bajo el capó para que pueda especificar la imagen y su código de entrenamiento, y la plataforma se encarga del resto. Incluso en clústeres HPC, los equipos a veces usan Singularity o Docker para ejecutar trabajos en un entorno contenedorizado para mayor consistencia. En resumen, los DLC simplifican el problema de "funciona en mi máquina" al proporcionar un tiempo de ejecución consistente para las tareas de aprendizaje profundo. Vienen con bibliotecas probadas y optimizadas (que pueden generar mejoras de rendimiento, por ejemplo, AWS informó una aceleración de hasta el 42 % usando su DLC optimizado PyTorch 2.0 en ciertas instancias (Build high-performance ML models using PyTorch 2.0 on AWS – Part 1 | AWS Machine Learning Blog)).
Volcano (VOLC) – Programación por Lotes de Kubernetes para Trabajos de IA
Volcano (VOLC) es un sistema de programación por lotes construido sobre Kubernetes, diseñado para ejecutar computación de alto rendimiento (HPC) y cargas de trabajo de IA en un entorno nativo de la nube. Si bien el programador predeterminado de Kubernetes es excelente para los microservicios, carece de algunas capacidades necesarias para los trabajos de aprendizaje profundo (como la programación de grupos, la administración de colas y la programación de prioridades). Volcano aborda esto al proporcionar un programador personalizado y CRD (Definiciones de recursos personalizados) de administración de trabajos sobre Kubernetes (Volcano: Collision between containers and batch computing | CNCF). En esencia, Volcano permite que Kubernetes se comporte más como un programador de clúster HPC para trabajos por lotes.
Qué es: Volcano se introdujo para unir contenedores y computación por lotes. Admite marcos como TensorFlow, PyTorch, Spark y MPI al permitir que los usuarios envíen trabajos que requieran múltiples recursos (por ejemplo, un trabajo que necesita 8 GPU en 2 nodos) y garantizar que esos recursos se asignen juntos antes de que comience el trabajo (Volcano: Collision between containers and batch computing | CNCF). Esta "programación de grupos" asegura que los trabajos de entrenamiento distribuido (que pueden generar muchos pods) no comiencen hasta que todos los pods requeridos puedan comenzar, evitando una situación en la que la mitad del trabajo se está ejecutando y la otra mitad está esperando (lo que desperdiciaría recursos). Volcano también proporciona políticas de equidad, colas de prioridad y la capacidad de programar conjuntamente cargas de trabajo mixtas.
Cómo funciona: Volcano se integra con Kubernetes como un complemento de programación. Los usuarios normalmente definen un YAML de Trabajo de Volcano, que especifica las tareas y sus recuentos de réplicas, las necesidades de recursos, etc. Por ejemplo, un YAML podría declarar un trabajo con 4 réplicas, cada una necesitando 1 GPU, y un minAvailable: 4
(lo que significa programar este trabajo solo cuando se puedan colocar 4 pods). Cuando se envía, el programador de Volcano encontrará espacio en el clúster para los 4 pods y los lanzará simultáneamente. Si solo 3 GPU están libres, esperará hasta que una cuarta esté libre (en lugar de comenzar 3 ahora y 1 después). Esto es crucial para marcos de entrenamiento distribuido como Horovod o PyTorch DDP, que esperan que todos los rangos estén activos a la vez para la sincronización.
La arquitectura de Volcano incluye un controlador central y complementos de programación. Considera algoritmos de programación como el reparto justo, la prioridad, etc., a través de un mecanismo de complementos. Por ejemplo, puede aplicar políticas de cola (para que ciertos trabajos no dejen sin recursos a otros) y programación consciente de la topología (distribuyendo trabajos entre nodos o racks para el rendimiento). Desde la perspectiva del usuario, usar Volcano se siente como usar Kubernetes pero con una API diferente para los trabajos y la garantía de que su trabajo de ML se programará de manera integral. En resumen, VOLC convierte a Kubernetes en un programador consciente de HPC (Volcano: Collision between containers and batch computing | CNCF), uniendo la conveniencia de los contenedores con el poder de la orquestación de trabajos por lotes.
Caso de uso de ejemplo: Suponga que tiene un clúster de Kubernetes con nodos GPU y desea ejecutar un trabajo de entrenamiento distribuido basado en MPI. Con Volcano, puede enviar un trabajo MPI (Volcano se integra con el operador MPI) solicitando (digamos) 2 pods cada uno con 4 GPU. Volcano se asegurará de que ambos pods comiencen juntos en dos nodos y tengan 4 GPU cada uno. También se encargará de si un pod falla, reprogramando todo el trabajo si es necesario, para mantener la semántica del grupo. De esta manera, su comando MPI mpirun
dentro de los pods puede lanzarse de manera confiable en ambos pods. Sin Volcano, el programador predeterminado podría iniciar un pod y luego retrasar el segundo hasta que se liberen los recursos, lo que provocaría que el proceso MPI del primer pod se cuelgue o agote el tiempo de espera.
SLURM: Programación Clásica de Trabajos HPC (Inmersión Profunda)
SLURM (Simple Linux Utility for Resource Management) es un programador de trabajos de código abierto ampliamente utilizado para clústeres HPC. Funciona como el "sistema operativo" de un clúster, asignando recursos (núcleos de CPU, GPU, memoria, nodos) a los trabajos, poniendo en cola los trabajos hasta que los recursos estén disponibles e iniciando y supervisando esos trabajos. Slurm es altamente escalable y se utiliza en muchas de las supercomputadoras principales. Proporciona una herramienta de administración de clústeres y programación de trabajos que se centra en hacer coincidir de manera eficiente los trabajos con los recursos disponibles (Choosing the Right Orchestration Tool for ML Workloads: Slurm vs. Kubernetes | Nscale).
Cómo funciona SLURM: Un clúster de Slurm consta de un controlador central (slurmctld) que administra la cola y la programación, y demonios de agente (slurmd) que se ejecutan en cada nodo de cómputo para iniciar y supervisar las tareas. Los usuarios interactúan con Slurm a través de comandos como sbatch
(para enviar un script de trabajo por lotes), salloc
(para solicitar una asignación interactiva) o srun
(para iniciar tareas paralelas). Slurm mantiene una lista de particiones (piense en ellas como colas o grupos de nodos con nombre), cada una con ciertos límites o características de hardware, y programa los trabajos en los nodos de esas particiones de acuerdo con las políticas configuradas (prioridad, equidad, programación de relleno, etc.).
Ejemplo de envío de trabajo: A continuación, se muestra un ejemplo de script de trabajo por lotes de Slurm (train.sbatch
), que solicita recursos y ejecuta un programa de entrenamiento:
#!/bin/bash
#SBATCH --job-name=train_model # Nombre del trabajo
#SBATCH --nodes=1 # Ejecutar en un solo nodo
#SBATCH --ntasks=4 # Tareas totales (procesos) = 4
#SBATCH --gres=gpu:4 # Solicitar 4 GPU (en un nodo)
#SBATCH --cpus-per-task=4 # 4 núcleos de CPU por tarea (16 núcleos en total)
#SBATCH --mem=64G # 64 GB de memoria para el trabajo
#SBATCH --time=02:00:00 # Límite de tiempo hh:mm:ss
#SBATCH --partition=ml_gpu # Nombre de la partición (cola)
module load anaconda/2023a # Cargar los módulos necesarios (por ejemplo, Anaconda)
source activate myenv # Activar el entorno virtual si es necesario
echo "Ejecutando en $SLURM_NNODES nodo(s) con $SLURM_NTASKS tareas..."
srun python train.py --epochs 10 --batch-size 128
En este script, las líneas #SBATCH
son directivas para Slurm. Solicitamos 1 nodo con 4 GPU y configuramos el trabajo para ejecutar python train.py
a través de srun
. Cuando ejecutamos sbatch train.sbatch
, Slurm pondrá el trabajo en cola. Una vez que un nodo en la partición ml_gpu
con 4 GPU libres y 16 núcleos de CPU libres esté disponible, Slurm asignará ese nodo al trabajo, iniciará el trabajo y srun
lanzará 4 tareas (ya que --ntasks=4
). Si este fuera un escenario de entrenamiento distribuido usando MPI o PyTorch distribuido, esas 4 tareas podrían corresponder a 4 trabajadores (cada uno asignado a una GPU). Slurm se encarga de lanzarlos con las variables de entorno adecuadas para MPI o para torch.distributed
(si está configurado para hacerlo).
Usar Slurm de manera efectiva: Slurm proporciona muchas características, como arreglos de trabajos (para enviar muchos trabajos similares fácilmente), cadenas de dependencia (iniciar el trabajo B después de que finalice el trabajo A) y perfiles de recursos. Para ML, un patrón común es solicitar --gres=gpu:N
para obtener N GPU y usar srun
o MPI para generar N procesos. Slurm asegura que todos esos procesos se ejecuten en los nodos asignados y puedan comunicarse (a menudo configura nombres de host en SLURM_HOSTNAMES
y MPI puede usarlos). Slurm también permite políticas de programación; por ejemplo, los trabajos se pueden interrumpir o rellenar. La programación de relleno es útil en HPC para maximizar la utilización: un trabajo corto podría avanzar en la cola si puede encajar en un espacio entre trabajos grandes. Como ingeniero, cuando tiene trabajos de entrenamiento grandes, puede solicitar un tiempo de pared más largo; pero si puede dividir el trabajo en fragmentos más cortos o hacer un punto de control y reiniciar, puede utilizar el relleno para que se ejecuten antes en partes.
En resumen, Slurm es una herramienta poderosa para ejecutar trabajos de ML por lotes en clústeres. Es de nivel inferior que Kubernetes o los servicios en la nube (normalmente se conecta a un nodo de inicio de sesión y usa sbatch
para enviar), pero brinda un control detallado. Muchos investigadores ejecutan PyTorch o TensorFlow en clústeres de Slurm simplemente escribiendo scripts de Slurm que lanzan su código de entrenamiento, beneficiándose de la programación de recursos de GPU del clúster.
vLLM: Motor de Inferencia LLM de Alto Rendimiento
A medida que los modelos de lenguaje grandes (LLM) pasaron de la investigación a la producción, servirlos de manera eficiente se convirtió en un desafío. vLLM es una biblioteca y motor de código abierto diseñado para una inferencia LLM rápida y rentable. Desarrollado en el Sky Computing Lab de UC Berkeley, vLLM introduce una nueva técnica de gestión de memoria llamada PagedAttention para optimizar cómo se almacena y accede a la caché de clave-valor de atención del modelo (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog). El resultado es un rendimiento significativamente mayor (solicitudes por segundo) en comparación con las implementaciones tradicionales. De hecho, vLLM logra hasta 24 veces más rendimiento que la biblioteca de referencia Hugging Face Transformers en el servicio de modelos de estilo GPT (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog), todo sin requerir cambios en la arquitectura del modelo.
Cómo funciona vLLM: En la generación autorregresiva (la forma típica en que los LLM generan texto token por token), se mantiene una caché de claves y valores de atención pasados para cada secuencia. Esta caché KV crece con la longitud de la secuencia y puede consumir mucha memoria de GPU (por ejemplo, ~1,7 GB para una sola secuencia larga en LLaMA-13B (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog)). La mayoría de los marcos asignan un bloque contiguo para la longitud máxima posible, lo que lleva a una gran cantidad de espacio no utilizado (fragmentación). En cambio, PagedAttention de vLLM trata la caché KV como páginas de memoria virtual, asignándola en bloques y permitiendo el almacenamiento no contiguo (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog). De esta manera, la memoria se puede administrar de manera flexible: las secuencias que terminan de generarse liberan sus páginas, que pueden reutilizarse para nuevas secuencias. Reduce drásticamente el desperdicio de memoria (en un 60-80 % en casos típicos) y permite que vLLM maneje más secuencias concurrentes que otros sistemas.
Además, vLLM implementa el lote continuo: puede agregar nuevas solicitudes entrantes al lote sobre la marcha, incluso mientras otras solicitudes están a mitad de la generación. Los sistemas tradicionales a menudo procesan un lote fijo de solicitudes de principio a fin para cada paso de generación; en cambio, el programador de vLLM está ajustado para fusionar solicitudes siempre que sea posible, manteniendo las GPU ocupadas. También usa gráficos CUDA optimizados para evitar la sobrecarga de Python en el bucle de servicio, admite GPU NVIDIA y AMD, y se integra con Hugging Face Transformers (para que pueda cargar modelos por nombre y servirlos).
Ejemplo de uso: Usar vLLM se siente similar a usar un servidor de inferencia de alto nivel. Puede usarlo programáticamente o a través de un servidor API. Por ejemplo, programáticamente:
from vllm import LLM, SamplingParams
# Cargar un modelo 7B (asumiendo que los pesos están disponibles localmente o a través de HuggingFace Hub)
llm = LLM(model="facebook/opt-6.7b", tensor_parallel_size=1) # tensor_parallel_size puede ser >1 para dividir el modelo en GPU
prompts = [
"Usuario: Hola, ¿cómo estás?\nAsistente:",
"Usuario: ¿Cuál es la capital de Francia?\nAsistente:"
]
# Generar con ciertos parámetros de decodificación
outputs = llm.generate(prompts, sampling_params=SamplingParams(top_p=0.95, max_tokens=100))
for out in outputs:
print("Prompt:\n", out.prompt)
print("Completion:\n", out.outputs[0].text)
Este código crea una instancia de LLM
y genera respuestas para dos prompts en un lote. Internamente, vLLM usará PagedAttention para administrar la caché KV para estos prompts e incluso puede agruparlos si es posible. Los outputs
contendrán las finalizaciones para cada prompt. También se podría lanzar vLLM como un servidor (que proporciona una API REST compatible con OpenAI) usando un comando como python -m vllm.entrypoints.openai.api_server --model your_model_name
. Esto facilita la integración de vLLM con aplicaciones que esperan una API de OpenAI (simplemente apúntelas a este servidor).
Por qué es importante: vLLM esencialmente empuja los límites de rendimiento del servicio LLM. Si tiene un presupuesto fijo de GPU, servir más solicitudes por segundo significa un costo por solicitud más bajo. La mejora de 24 veces informada es en escenarios donde se generan muchas solicitudes concurrentes con salidas relativamente largas (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog). Incluso en casos menos extremos, vLLM a menudo produce aceleraciones múltiples sobre implementaciones ingenuas, y aproximadamente 3 veces sobre el servidor TGI de Hugging Face en muchas configuraciones (vLLM: Easy, Fast, and Cheap LLM Serving with PagedAttention | vLLM Blog). También admite algoritmos de decodificación avanzados (como la búsqueda de haz, el muestreo paralelo) de manera eficiente (vLLM and PagedAttention: A Comprehensive Overview | by Abonia Sojasingarayar | Medium). Para un ingeniero, adoptar vLLM puede ser tan simple como cambiar su código de inferencia para usar la API de vLLM (o ejecutar su servidor). El beneficio es manejar más usuarios o reducir la latencia sin comprar más GPU.
SGLang: Lenguaje de Generación Estructurada y Marco de Servicio
Si bien vLLM se centra en el rendimiento bruto de la finalización de prompts de un solo paso, SGLang aborda el problema de orquestar interacciones complejas y estructuradas con LLM de manera eficiente. SGLang (abreviatura de Structured Generation Language) es un sistema que combina un DSL (Lenguaje Específico del Dominio) frontend para describir programas LLM de varios pasos con un tiempo de ejecución backend altamente optimizado para ejecutarlos ([2312.07104] SGLang: Efficient Execution of Structured Language Model Programs) (SGLang: A Deep Dive into Efficient LLM Program Execution - DEV Community). Es como si SGLang fuera tanto un lenguaje de programación para prompts (con características como bucles, condicionales y llamadas paralelas) como un motor de servicio que asegura que esos programas se ejecuten rápido.
Qué es: La idea central detrás de SGLang es que muchas aplicaciones reales requieren múltiples llamadas a un LLM y salidas estructuradas. Por ejemplo, un agente de IA podría planificar pasos y llamar al LLM para cada paso, o podría requerir que el LLM genere JSON con un esquema específico. Hacer esto de manera ingenua puede ser lento: múltiples llamadas incurren en sobrecarga y el LLM podría repetir el procesamiento de las mismas partes del prompt, etc. El frontend de SGLang le permite escribir un solo "script" que puede incluir múltiples llamadas de generación, lógica de bifurcación e integración de herramientas externas. El compilador/tiempo de ejecución de SGLang luego ejecutará esto de manera eficiente. El tiempo de ejecución introduce optimizaciones como RadixAttention (un algoritmo para reutilizar la caché KV en todos los prefijos de prompt, similar en espíritu a la paginación de vLLM pero orientado a partes de prompt compartidas) y una máquina de estados finitos comprimida para la gramática de salida (para manejar salidas estructuradas más rápido) ([2312.07104] SGLang: Efficient Execution of Structured Language Model Programs). En términos sencillos, RadixAttention significa que si tiene muchas solicitudes que comparten un prefijo común (por ejemplo, un prompt del sistema o de pocos disparos), SGLang calculará esa parte una vez y la reutilizará, lo que hará que los chatbots o la generación aumentada de recuperación sean mucho más rápidos al evitar el trabajo redundante (What is SGLang and Why Does It Matter? | by Emad Dehnavi | Medium). El FSM de salida estructurada significa que si espera, por ejemplo, un JSON con claves fijas, SGLang puede omitir la generación de la puntuación/claves fijas token por token y avanzar, ya que sabe que esas partes son deterministas (What is SGLang and Why Does It Matter? | by Emad Dehnavi | Medium). Esto da un aumento de velocidad de 3 veces+ para generar salidas JSON o XML largas (What is SGLang and Why Does It Matter? | by Emad Dehnavi | Medium).
Cómo funciona: SGLang consta de dos partes: un DSL basado en Python y un tiempo de ejecución. El DSL permite a los usuarios escribir algo como:
from sglang import sg # interfaz hipotética
# Pseudocódigo: definir un flujo de generación estructurado
with sg.session(model="Llama-2-13b-chat") as sess:
# Un programa simple con dos llamadas LLM secuenciales y una salida estructurada
user_input = "Traduce el siguiente texto en inglés al francés y da el sentimiento: Me encanta este producto."
sg.prompt(f"El usuario pregunta: {user_input}\nEres un traductor y analizador de sentimientos.")
translation = sg.generate("Primero, traduce al francés:")
sentiment = sg.generate("Ahora, analiza el sentimiento del texto original:")
sg.return_json({"translation": translation, "sentiment": sentiment})
(Nota: El código anterior es pseudocódigo ilustrativo. La sintaxis real de SGLang podría diferir, pero conceptualmente permite la generación secuencial y paralela y la devolución de datos estructurados.)
Cuando se ejecuta este "programa" SGLang, el tiempo de ejecución se hará cargo: podría ejecutar la primera llamada de generación para traducir, luego la segunda para el sentimiento y finalmente ensamblar un JSON. Internamente, utiliza uno o más backends de inferencia LLM (con optimizaciones similares a vLLM). Debido a que los dos prompts comparten el contexto de instrucción inicial, SGLang puede reutilizar el cálculo del prefijo para la segunda llamada. Y al devolver JSON, si las claves y el formato JSON están predeterminados por sg.return_json
, puede asegurarse de que se generen sin gastar múltiples tokens en llaves/comas.
Características clave: Los autores de SGLang destacan características que incluyen programación de sobrecarga cero (su programador para orquestar múltiples llamadas prácticamente no agrega latencia adicional), equilibrio de carga consciente de la caché (puede enrutar solicitudes a trabajadores de una manera que maximice los aciertos de caché) y soporte multimodal (también puede manejar modelos de visión-lenguaje, por ejemplo, LLaVA para imágenes) (GitHub - sgl-project/sglang: SGLang is a fast serving framework for large language models and vision language models.) (GitHub - sgl-project/sglang: SGLang is a fast serving framework for large language models and vision language models.). También admite trucos de eficiencia comunes: cuantificación (int8/4 bits, etc.), decodificación especulativa (generación de múltiples tokens por adelantado para luego verificar, lo que puede acelerar las generaciones largas) y orquestación multimodelos (por ejemplo, usar un modelo para una parte del programa y otro modelo para una parte diferente). Esencialmente, es un marco todo en uno para escribir aplicaciones impulsadas por LLM y ejecutarlas con alto rendimiento.
Rendimiento y casos de uso: SGLang ha mostrado hasta 6.4 veces más mejoras de rendimiento sobre los sistemas de última generación en tareas complejas ([2312.07104] SGLang: Efficient Execution of Structured Language Model Programs). Considere una canalización de generación aumentada de recuperación (RAG): normalmente, podría buscar vectores para el contexto, luego anteponerlo a un prompt, luego generar una respuesta. Con SGLang, podría expresar toda esta secuencia (resultado de búsqueda de vectores que se alimenta a una plantilla de prompt, luego generación) como un solo programa. El tiempo de ejecución podría paralelizar algunos pasos si es posible y reutilizar componentes en caché. Del mismo modo, para los chatbots que tienen un historial de conversación, SGLang puede reutilizar las partes invariantes del prompt en todos los turnos (en lugar de volver a procesar toda la conversación cada vez). Para salidas estructuradas, como asegurar que la respuesta del modelo siga un esquema JSON, el enfoque de máquina de estados finitos de SGLang puede evitar que el modelo se desvíe del formato y hacerlo más rápido al inyectar la sintaxis fija. Desde un punto de vista de ingeniería, SGLang ofrece tanto un aumento de productividad (a través del DSL) como un aumento de rendimiento (a través de la ejecución optimizada) para construir flujos de trabajo LLM complejos.
Quién está detrás: SGLang es un proyecto de código abierto (respaldado por una comunidad que incluye investigadores de Stanford/Berkeley y empresas como LinkedIn, etc., según sus reconocimientos). Ha sido utilizado en producción por empresas como ByteDance y xAI (SGLang: A Deep Dive into Efficient LLM Program Execution - DEV Community). Es relativamente nuevo (el artículo de arXiv llegó a finales de 2023), pero está ganando terreno para aplicaciones LLM avanzadas. Si su caso de uso va más allá de pares de finalización de prompts únicos, por ejemplo, necesita un agente que llame al modelo varias veces o necesita respuestas estructuradas ultrarrápidas, explorar SGLang podría valer la pena. Tiene más partes móviles que un simple servidor, pero puede automatizar gran parte de la optimización que de otro modo tendría que construir usted mismo.
Marcos de Entrenamiento y Parámetros de Entrenamiento Típicos
Cuando hablamos de marcos de entrenamiento, nos referimos a las bibliotecas y herramientas utilizadas para implementar el entrenamiento del modelo. Los principales son PyTorch, TensorFlow, JAX e interfaces de nivel superior como PyTorch Lightning o Hugging Face Transformers Trainer, así como marcos de entrenamiento distribuido como Horovod, DeepSpeed o ColossalAI que se sientan encima de estos. Independientemente del marco, existe un conjunto común de parámetros de entrenamiento (hiperparámetros) que los profesionales deben administrar. Estas son las perillas que definen la configuración del entrenamiento e influyen en la convergencia y el rendimiento del modelo.
Los parámetros de entrenamiento típicos incluyen:
- Tasa de Aprendizaje (LR): Quizás el hiperparámetro más crítico. Esto controla el tamaño del paso en el descenso de gradiente. Una tasa de aprendizaje demasiado alta y el entrenamiento podría divergir; demasiado baja y converge lentamente o se atasca en un resultado subóptimo. A menudo usamos programaciones de la tasa de aprendizaje (como la decadencia del coseno, el calentamiento lineal y luego la decadencia, etc.) para ajustar LR con el tiempo.
- Tamaño del Lote: Número de muestras que el modelo ve antes de que se actualicen sus pesos. Hay tamaño del lote por dispositivo y tamaño del lote global (global = por dispositivo * número