Inteligencia artificial

Optimización de la implementación de LLM: vLLM PagedAttention y el futuro de la integración de IA eficiente

mm
Deploy the vLLM Inference Engine to Run Large Language Models

Los modelos de lenguaje grande (LLM) que se implementan en aplicaciones del mundo real presentan desafíos únicos, particularmente en términos de recursos computacionales, latencia y rentabilidad. En esta guía integral, exploraremos el panorama de la implementación de LLM, con un enfoque especial en vLLM (modelo de lenguaje vectorial), una solución que está cambiando la forma en que implementamos y interactuamos con estos modelos poderosos.

Los desafíos de la implementación de LLM

Antes de profundizar en soluciones específicas, analicemos los desafíos clave que hacen que la implementación de LLM sea una tarea compleja:

Recursos computacionales

Los LLM son notorios por su enorme cantidad de parámetros, que van desde miles de millones hasta cientos de miles de millones. Por ejemplo, GPT-3 cuenta con 175.000 millones de parámetros, mientras que modelos más recientes como GPT-4 se estima que tienen aún más. Este tamaño tan grande se traduce en requisitos computacionales significativos para la inferencia.

Ejemplo:
Considera un LLM relativamente modesto con 13.000 millones de parámetros, como LLaMA-13B. Incluso este modelo requiere:

– Aproximadamente 26 GB de memoria solo para almacenar los parámetros del modelo (suponiendo precisión de 16 bits)
– Memoria adicional para activaciones, mecanismos de atención y cálculos intermedios
– Una gran potencia de cálculo de GPU para la inferencia en tiempo real

Latencia

En muchas aplicaciones, como chatbots o generación de contenido en tiempo real, la latencia baja es crucial para una buena experiencia del usuario. Sin embargo, la complejidad de los LLM puede llevar a tiempos de procesamiento significativos, especialmente para secuencias más largas.

Ejemplo:
Imagina un chatbot de servicio al cliente impulsado por un LLM. Si cada respuesta tarda varios segundos en generarse, la conversación se sentirá poco natural y frustrante para los usuarios.

Costo

El hardware necesario para ejecutar LLM a gran escala puede ser extremadamente costoso. A menudo se necesitan GPUs o TPUs de alta gama, y el consumo de energía de estos sistemas es sustancial.

Ejemplo:
Ejecutar un clúster de GPUs NVIDIA A100 (a menudo utilizadas para la inferencia de LLM) puede costar miles de dólares al día en tarifas de computación en la nube.

Enfoques tradicionales para la implementación de LLM

Antes de explorar soluciones más avanzadas, revisemos brevemente algunos enfoques tradicionales para la implementación de LLM:

Implementación simple con Hugging Face Transformers

La biblioteca Hugging Face Transformers proporciona una forma sencilla de implementar LLM, pero no está optimizada para la implementación de alto rendimiento.

Código de ejemplo:

“`python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

nombre_del_modelo = “meta-llama/Llama-2-13b-hf”
modelo = AutoModelForCausalLM.from_pretrained(nombre_del_modelo, device_map=”auto”)
tokenizador = AutoTokenizer.from_pretrained(nombre_del_modelo)

def generar_texto(prompt, max_length=100):
entradas = tokenizador(prompt, return_tensors=”pt”).to(modelo.device)
salidas = modelo.generate(**entradas, max_length=max_length)
return tokenizador.decode(salidas[0], skip_special_tokens=True)

print(generar_texto(“El futuro de la IA es”))
“`

Aunque este enfoque funciona, no es adecuado para aplicaciones de alto tráfico debido a su uso ineficiente de recursos y falta de optimizaciones para la implementación.

Uso de TorchServe o frameworks similares

Frameworks como TorchServe proporcionan capacidades de implementación más robustas, incluyendo equilibrio de carga y control de versiones de modelos. Sin embargo, no abordan los desafíos específicos de la implementación de LLM, como la gestión eficiente de la memoria para modelos grandes.

Comprensión de la gestión de la memoria en la implementación de LLM

La gestión eficiente de la memoria es fundamental para la implementación de modelos de lenguaje grande (LLM) debido a los recursos computacionales extensos necesarios. Las siguientes imágenes ilustran varios aspectos de la gestión de la memoria, que son integrales para optimizar el rendimiento de LLM.

Memoria segmentada vs. memoria paginada

Estos dos diagramas comparan las técnicas de gestión de memoria segmentada y paginada, comúnmente utilizadas en sistemas operativos (OS).

  • Memoria segmentada: Esta técnica divide la memoria en diferentes segmentos, cada uno correspondiente a un programa o proceso diferente. Por ejemplo, en un contexto de implementación de LLM, diferentes segmentos podrían asignarse a varios componentes del modelo, como tokenización, incrustación y mecanismos de atención. Cada segmento puede crecer o disminuir de forma independiente, lo que proporciona flexibilidad pero puede llevar a la fragmentación si los segmentos no se gestionan adecuadamente.
  • Memoria paginada: Aquí, la memoria se divide en páginas de tamaño fijo, que se asignan a la memoria física. Las páginas se pueden intercambiar según sea necesario, lo que permite un uso eficiente de los recursos de memoria. En la implementación de LLM, esto puede ser crucial para gestionar las grandes cantidades de memoria necesarias para almacenar los pesos del modelo y los cálculos intermedios.

Gestión de la memoria en OS vs. vLLM

Esta imagen contrasta la gestión de la memoria tradicional de OS con el enfoque de gestión de la memoria utilizado en vLLM.

  • Gestión de la memoria de OS: En sistemas operativos tradicionales, los procesos (por ejemplo, Proceso A y Proceso B) se asignan páginas de memoria (Página 0, Página 1, etc.) en la memoria física. Esta asignación puede llevar a la fragmentación con el tiempo a medida que los procesos solicitan y liberan memoria.
  • Gestión de la memoria de vLLM: El marco de vLLM utiliza una caché de clave-valor (KV) para gestionar la memoria de forma más eficiente. Las solicitudes (por ejemplo, Solicitud A y Solicitud B) se asignan bloques de la caché KV (Bloque KV 0, Bloque KV 1, etc.). Este enfoque ayuda a minimizar la fragmentación y optimiza el uso de la memoria, lo que permite una implementación de modelo más rápida y eficiente.

Mecanismo de atención en LLM

Mecanismo de atención en LLM

Mecanismo de atención en LLM

El mecanismo de atención es un componente fundamental de los modelos de transformadores, que se utilizan comúnmente para LLM. Este diagrama ilustra la fórmula de atención y sus componentes:

  • Consulta (Q): Un nuevo token en el paso de decodificador o el último token que el modelo ha visto.
  • Clave (K): Contexto previo al que el modelo debe prestar atención.
  • Valor (V): Suma ponderada sobre el contexto previo.

La fórmula calcula las puntuaciones de atención tomando el producto escalar de la consulta con las claves, escalando por la raíz cuadrada de la dimensión de la clave, aplicando una función softmax y finalmente tomando el producto escalar con los valores. Este proceso permite al modelo centrarse en las partes relevantes de la secuencia de entrada al generar cada token.

Comparación de rendimiento de implementación

vLLM: Implementación de LLM fácil, rápida y asequible con PagedAttention

vLLM: Implementación de LLM fácil, rápida y asequible con PagedAttention

Esta imagen presenta una comparación del rendimiento de implementación entre diferentes marcos (HF, TGI y vLLM) utilizando modelos LLaMA en diferentes configuraciones de hardware.

  • LLaMA-13B, A100-40GB: vLLM logra un rendimiento 14 veces mayor que HuggingFace Transformers (HF) y 2,2 veces mayor que HuggingFace Text Generation Inference (TGI).
  • LLaMA-7B, A10G: Se observan tendencias similares, con vLLM superando significativamente a HF y TGI.

vLLM: Una nueva arquitectura de implementación de LLM

vLLM, desarrollado por investigadores de la Universidad de California en Berkeley, representa un avance significativo en la tecnología de implementación de LLM. Analicemos sus características y innovaciones clave:

PagedAttention

En el corazón de vLLM se encuentra PagedAttention, un algoritmo de atención novedoso inspirado en la gestión de la memoria virtual en sistemas operativos. Aquí está cómo funciona:

Particionamiento de la caché de clave-valor (KV): En lugar de almacenar la caché KV completa de forma contigua en la memoria, PagedAttention la divide en bloques de tamaño fijo.
Almacenamiento no contiguo: Estos bloques se pueden almacenar de forma no contigua en la memoria, lo que permite una gestión de la memoria más flexible.
Asignación bajo demanda: Los bloques se asignan solo cuando se necesitan, lo que reduce el desperdicio de memoria.
Compartir eficiente: Las secuencias múltiples pueden compartir bloques, lo que permite optimizaciones para técnicas como muestreo paralelo y búsqueda en haz.

Ilustración:

“`
Caché KV tradicional:
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV]
(Asignación de memoria contigua)

Caché KV de PagedAttention:
[Bloque 1] -> Dirección física A
[Bloque 2] -> Dirección física C
[Bloque 3] -> Dirección física B

(Asignación de memoria no contigua)
“`

Este enfoque reduce significativamente la fragmentación de la memoria y permite un uso más eficiente de la memoria de la GPU.

Lote continuo

vLLM implementa un lote continuo, que procesa las solicitudes de forma dinámica a medida que llegan, en lugar de esperar a formar lotes de tamaño fijo. Esto conduce a una latencia más baja y un rendimiento más alto.

Ejemplo:
Imagina un flujo de solicitudes entrantes:

“`
Tiempo 0 ms: Solicitud A llega
Tiempo 10 ms: Comienza el procesamiento de la Solicitud A
Tiempo 15 ms: Solicitud B llega
Tiempo 20 ms: Comienza el procesamiento de la Solicitud B (en paralelo con A)
Tiempo 25 ms: Solicitud C llega

“`

Con el lote continuo, vLLM puede comenzar a procesar cada solicitud de inmediato, en lugar de esperar a agruparlas en lotes predefinidos.

Muestreo paralelo eficiente

Para aplicaciones que requieren múltiples muestras de salida por prompt (por ejemplo, asistentes de escritura creativa), las capacidades de compartición de memoria de vLLM brillan. Puede generar múltiples salidas mientras reutiliza la caché KV para prefijos compartidos.

Código de ejemplo que utiliza vLLM:

“`python
from vllm import LLM, SamplingParams

llm = LLM(modelo=”meta-llama/Llama-2-13b-hf”)
prompts = [“El futuro de la IA es”]

# Generar 3 muestras por prompt
params_de_muestreo = SamplingParams(n=3, temperatura=0.8, max_tokens=100)
salidas = llm.generate(prompts, params_de_muestreo)

for salida in salidas:
print(f”Prompt: {salida.prompt}”)
for i, out in enumerate(salida.salidas):
print(f”Muestra {i + 1}: {out.text}”)
“`

Este código genera de forma eficiente múltiples muestras para el prompt dado, aprovechando las optimizaciones de vLLM.

Benchmarking del rendimiento de vLLM

Para apreciar realmente el impacto de vLLM, analicemos algunas comparaciones de rendimiento:

Comparación de rendimiento

Basado en la información proporcionada, vLLM supera significativamente a otras soluciones de implementación:

– Hasta 24 veces más rendimiento que Hugging Face Transformers
– 2,2 veces más rendimiento que Hugging Face Text Generation Inference (TGI)

Ilustración:

“`
Rendimiento (Tokens/segundo)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`

Eficiencia de la memoria

La PagedAttention de vLLM resulta en un uso casi óptimo de la memoria:

– Solo alrededor del 4% de desperdicio de memoria, en comparación con el 60-80% en sistemas tradicionales
– Esta eficiencia permite servir modelos más grandes o manejar más solicitudes concurrentes con el mismo hardware

Introducción a vLLM

Ahora que hemos explorado los beneficios de vLLM, analicemos el proceso de configuración y uso en sus proyectos.

6.1 Instalación

Instalar vLLM es sencillo utilizando pip:

“`python
!pip install vllm
“`

6.2 Uso básico para inferencia sin conexión

Aquí hay un ejemplo simple de uso de vLLM para la generación de texto sin conexión:

“`python
from vllm import LLM, SamplingParams

# Inicializar el modelo
llm = LLM(modelo=”meta-llama/Llama-2-13b-hf”)

# Preparar prompts
prompts = [
“Escribe un poema corto sobre la inteligencia artificial:”,
“Explica la computación cuántica en términos simples:”
]

# Establecer parámetros de muestreo
params_de_muestreo = SamplingParams(temperatura=0.8, max_tokens=100)

# Generar respuestas
salidas = llm.generate(prompts, params_de_muestreo)

# Imprimir los resultados
for salida in salidas:
print(f”Prompt: {salida.prompt}”)
print(f”Texto generado: {salida.salidas[0].text}\n”)
“`

Este script demuestra cómo cargar un modelo, establecer parámetros de muestreo y generar texto para múltiples prompts.

6.3 Configuración de un servidor vLLM

Para la implementación en línea, vLLM proporciona un servidor de API compatible con OpenAI. Aquí está cómo configurarlo:

1. Iniciar el servidor:

“`bash
python -m vllm.entrypoints.openai.api_server –modelo meta-llama/Llama-2-13b-hf
“`

2. Consultar el servidor utilizando curl:

“`bash
curl http://localhost:8000/v1/completions \
-H “Content-Type: application/json” \
-d ‘{“modelo”: “meta-llama/Llama-2-13b-hf”, “prompt”: “Los beneficios de la inteligencia artificial incluyen:”, “max_tokens”: 100, “temperatura”: 0.7}’
“`

Esta configuración permite servir su LLM con una interfaz compatible con la API de OpenAI, lo que facilita la integración en aplicaciones existentes.

Tópicos avanzados sobre vLLM

Aunque vLLM ofrece mejoras significativas en la implementación de LLM, hay consideraciones y temas avanzados adicionales para explorar:

7.1 Cuantificación del modelo

Para una implementación aún más eficiente, especialmente en hardware con memoria limitada, se pueden emplear técnicas de cuantificación. Aunque vLLM en sí no admite cuantificación, se puede utilizar con modelos cuantificados:

“`python
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch

# Cargar un modelo cuantificado
nombre_del_modelo = “meta-llama/Llama-2-13b-hf”
modelo = AutoModelForCausalLM.from_pretrained(nombre_del_modelo, device_map=”auto”, load_in_8bit=True)
tokenizador = AutoTokenizer.from_pretrained(nombre_del_modelo)

# Utilizar el modelo cuantificado con vLLM
from vllm import LLM

llm = LLM(modelo=modelo, tokenizador=tokenizador)
“`

7.2 Inferencia distribuida

Para modelos extremadamente grandes o aplicaciones de alto tráfico, es posible que se necesite inferencia distribuida en varias GPUs o máquinas. Aunque vLLM no admite esto de forma nativa, se puede integrar en sistemas distribuidos utilizando frameworks como Ray:

“`python
import ray
from vllm import LLM

@ray.remote(num_gpus=1)
class LLM_Distribuido:
def __init__(self, nombre_del_modelo):
self.llm = LLM(modelo=nombre_del_modelo)

def generar(self, prompt, params):
return self.llm.generate(prompt, params)

# Inicializar LLM distribuidos
llm1 = LLM_Distribuido.remote(“meta-llama/Llama-2-13b-hf”)
llm2 = LLM_Distribuido.remote(“meta-llama/Llama-2-13b-hf”)

# Utilizarlos en paralelo
resultado1 = llm1.generar.remote(“Prompt 1”, params_de_muestreo)
resultado2 = llm2.generar.remote(“Prompt 2”, params_de_muestreo)

# Recuperar resultados
print(ray.get([resultado1, resultado2]))
“`

7.3 Monitoreo y observabilidad

Al servir LLM en producción, el monitoreo es crucial. Aunque vLLM no proporciona monitoreo integrado, se puede integrar con herramientas como Prometheus y Grafana:

“`python
from prometheus_client import start_http_server, Summary
from vllm import LLM

# Definir métricas
TIEMPO_DE_SOLICITUD = Summary(“tiempo_de_solicitud_segundos”, “Tiempo dedicado a procesar la solicitud”)

# Inicializar vLLM
llm = LLM(modelo=”meta-llama/Llama-2-13b-hf”)

# Exponer métricas
start_http_server(8000)

# Utilizar el modelo con monitoreo
@TIEMPO_DE_SOLICITUD.time()
def procesar_solicitud(prompt):
return llm.generate(prompt)

# Su ciclo de servicio aquí
“`

Esta configuración permite rastrear métricas como el tiempo de procesamiento de la solicitud, que se pueden visualizar en paneles de Grafana.

Conclusión

La implementación eficiente de modelos de lenguaje grande es una tarea compleja pero crucial en la era de la IA. vLLM, con su algoritmo de atención PagedAttention innovador y su implementación optimizada, representa un avance significativo en la implementación de LLM, haciéndola más accesible y rentable.

Al mejorar significativamente el rendimiento, reducir el desperdicio de memoria y permitir opciones de implementación más flexibles, vLLM abre nuevas posibilidades para integrar modelos de lenguaje poderosos en una amplia gama de aplicaciones. Ya sea que esté construyendo un chatbot, un sistema de generación de contenido o cualquier otra aplicación impulsada por NLP, comprender y aprovechar herramientas como vLLM será clave para el éxito.

He dedicado los últimos cinco años sumergiéndome en el fascinante mundo de Machine Learning y Deep Learning. Mi pasión y experiencia me han llevado a contribuir a más de 50 proyectos de ingeniería de software diversos, con un enfoque particular en AI/ML. Mi curiosidad en curso también me ha llevado hacia el Procesamiento de Lenguaje Natural, un campo que estoy ansioso por explorar más a fondo.