Inteligência artificial
Otimizando a Implantação de LLM: vLLM PagedAttention e o Futuro do Serviço de IA Eficiente

Modelos de Linguagem Grande (LLMs) implantados em aplicações do mundo real apresentam desafios únicos, particularmente em termos de recursos computacionais, latência e eficiência de custo. Neste guia abrangente, exploraremos o cenário de serviço de LLM, com foco especial em vLLM (modelo de linguagem de vetor), uma solução que está redefinindo a forma como implantamos e interagimos com esses modelos poderosos.
Os Desafios de Servir Modelos de Linguagem Grande
Antes de mergulhar em soluções específicas, vamos examinar os principais desafios que tornam o serviço de LLM uma tarefa complexa:
Recursos Computacionais
LLMs são notórios por seus enormes contadores de parâmetros, variando de bilhões a centenas de bilhões. Por exemplo, o GPT-3 tem 175 bilhões de parâmetros, enquanto modelos mais recentes, como GPT-4, são estimados ter ainda mais. Esse tamanho impressionante se traduz em significativas exigências computacionais para inferência.
Exemplo:
Considere um LLM relativamente modesto com 13 bilhões de parâmetros, como o LLaMA-13B. Mesmo esse modelo requer:
– Aproximadamente 26 GB de memória apenas para armazenar os parâmetros do modelo (supondo precisão de 16 bits)
– Memória adicional para ativações, mecanismos de atenção e cálculos intermediários
– Substancial poder de processamento de GPU para inferência em tempo real
Latência
Em muitas aplicações, como chatbots ou geração de conteúdo em tempo real, baixa latência é crucial para uma boa experiência do usuário. No entanto, a complexidade dos LLMs pode levar a tempos de processamento significativos, especialmente para sequências mais longas.
Exemplo:
Imagine um chatbot de atendimento ao cliente alimentado por um LLM. Se cada resposta leva vários segundos para ser gerada, a conversa parecerá não natural e frustrante para os usuários.
Custo
O hardware necessário para executar LLMs em escala pode ser extremamente caro. GPUs ou TPUs de alta qualidade são frequentemente necessários, e o consumo de energia desses sistemas é substancial.
Exemplo:
Executar um cluster de GPUs NVIDIA A100 (frequentemente usadas para inferência de LLM) pode custar milhares de dólares por dia em taxas de computação em nuvem.
Abordagens Tradicionais para Serviço de LLM
Antes de explorar soluções mais avançadas, vamos revisar brevemente algumas abordagens tradicionais para servir LLMs:
Implantação Simples com Hugging Face Transformers
A biblioteca Hugging Face Transformers fornece uma maneira direta de implantar LLMs, mas não é otimizada para serviço de alta taxa.
Exemplo de código:
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
model_name = "meta-llama/Llama-2-13b-hf"
model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto")
tokenizer = AutoTokenizer.from_pretrained(model_name)
def generate_text(prompt, max_length=100):
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.decode(outputs[0], skip_special_tokens=True)
print(generate_text("O futuro da IA é"))
Embora essa abordagem funcione, não é adequada para aplicações de alto tráfego devido ao uso ineficiente de recursos e falta de otimizações para serviço.
Usando TorchServe ou Frameworks Semelhantes
Frameworks como TorchServe fornecem capacidades de serviço mais robustas, incluindo balanceamento de carga e versionamento de modelo. No entanto, eles ainda não abordam os desafios específicos do serviço de LLM, como gerenciamento de memória eficiente para modelos grandes.
Entendendo Gerenciamento de Memória no Serviço de LLM
O gerenciamento de memória eficiente é crítico para servir modelos de linguagem grande (LLMs) devido aos recursos computacionais extensivos necessários. As seguintes imagens ilustram vários aspectos do gerenciamento de memória, que são integrais para otimizar o desempenho do LLM.
Memória Segmentada vs. Paginada
Essas duas diagramas comparam técnicas de gerenciamento de memória segmentada e paginada, comumente usadas em sistemas operacionais (SO).
- Memória Segmentada: Essa técnica divide a memória em diferentes segmentos, cada um correspondendo a um diferente programa ou processo. Por exemplo, em um contexto de serviço de LLM, diferentes segmentos podem ser alocados para vários componentes do modelo, como tokenização, incorporação e mecanismos de atenção. Cada segmento pode crescer ou diminuir independentemente, fornecendo flexibilidade, mas potencialmente levando à fragmentação se os segmentos não forem gerenciados adequadamente.
- Memória Paginada: Aqui, a memória é dividida em páginas de tamanho fixo, que são mapeadas na memória física. Páginas podem ser trocadas para dentro e para fora conforme necessário, permitindo o uso eficiente dos recursos de memória. No serviço de LLM, isso pode ser crucial para gerenciar as grandes quantidades de memória necessárias para armazenar pesos do modelo e cálculos intermediários.
Gerenciamento de Memória em OS vs. vLLM
Essa imagem contrasta o gerenciamento de memória tradicional do SO com a abordagem de gerenciamento de memória usada em vLLM.
- Gerenciamento de Memória do SO: Em sistemas operacionais tradicionais, processos (por exemplo, Processo A e Processo B) são alocados páginas de memória (Página 0, Página 1, etc.) na memória física. Essa alocação pode levar à fragmentação ao longo do tempo, à medida que os processos solicitam e liberam memória.
- Gerenciamento de Memória do vLLM: O framework vLLM usa um cache de chave-valor (KV) para gerenciar a memória de forma mais eficiente. Solicitações (por exemplo, Solicitação A e Solicitação B) são alocadas blocos do cache KV (Bloco KV 0, Bloco KV 1, etc.). Essa abordagem ajuda a minimizar a fragmentação e a otimizar o uso de memória, permitindo um serviço de modelo mais rápido e eficiente.
Mecanismo de Atenção em LLMs
O mecanismo de atenção é um componente fundamental dos modelos transformer, que são comumente usados para LLMs. Esse diagrama ilustra a fórmula de atenção e seus componentes:
- Consulta (Q): Um novo token na etapa de decodificação ou o último token que o modelo viu.
- Chave (K): Contexto anterior que o modelo deve atender.
- Valor (V): Soma ponderada sobre o contexto anterior.
A fórmula calcula as pontuações de atenção, tomando o produto escalar da consulta com as chaves, escalonando pela raiz quadrada da dimensão da chave, aplicando uma função softmax e, finalmente, tomando o produto escalar com os valores. Esse processo permite que o modelo se concentre em partes relevantes da sequência de entrada ao gerar cada token.
Comparação de Taxa de Serviço
Essa imagem apresenta uma comparação da taxa de serviço entre diferentes frameworks (HF, TGI e vLLM) usando modelos LLaMA em diferentes configurações de hardware.
- LLaMA-13B, A100-40GB: vLLM alcança 14x a 24x mais taxa de serviço do que HuggingFace Transformers (HF) e 2,2x a 2,5x mais taxa de serviço do que HuggingFace Text Generation Inference (TGI).
- LLaMA-7B, A10G: Tendências semelhantes são observadas, com vLLM superando significativamente tanto HF quanto TGI.
vLLM: Uma Nova Arquitetura de Serviço de LLM
vLLM, desenvolvido por pesquisadores da UC Berkeley, representa um grande salto para frente na tecnologia de serviço de LLM. Vamos explorar suas principais características e inovações:
PagedAttention
No coração do vLLM está o PagedAttention, um algoritmo de atenção inovador inspirado no gerenciamento de memória virtual em sistemas operacionais. Aqui está como ele funciona:
– Particionamento do Cache de Chave-Valor (KV): Em vez de armazenar o cache KV inteiro contiguamente na memória, o PagedAttention o divide em blocos de tamanho fixo.
– Armazenamento Não Contíguo: Esses blocos podem ser armazenados não contiguamente na memória, permitindo um gerenciamento de memória mais flexível.
– Alocação sob Demanda: Blocos são alocados apenas quando necessário, reduzindo o desperdício de memória.
– Compartilhamento Eficiente: Múltiplas sequências podem compartilhar blocos, permitindo otimizações para técnicas como amostragem paralela e busca em feixe.
Ilustração:
“`
Cache KV Tradicional:
[Token 1 KV][Token 2 KV][Token 3 KV]…[Token N KV]
(Alocação de memória contígua)
Cache KV do PagedAttention:
[Block 1] -> Endereço Físico A
[Block 2] -> Endereço Físico C
[Block 3] -> Endereço Físico B
…
(Alocação de memória não contígua)
“`
Essa abordagem reduz significativamente a fragmentação de memória e permite um uso muito mais eficiente da memória da GPU.
Lote Contínuo
vLLM implementa lote contínuo, que processa dinamicamente as solicitações à medida que elas chegam, em vez de esperar para formar lotes de tamanho fixo. Isso leva a uma latência mais baixa e uma taxa de serviço mais alta.
Exemplo:
Imagine um fluxo de solicitações de entrada:
“`
Tempo 0ms: Solicitação A chega
Tempo 10ms: Iniciar processamento da Solicitação A
Tempo 15ms: Solicitação B chega
Tempo 20ms: Iniciar processamento da Solicitação B (em paralelo com A)
Tempo 25ms: Solicitação C chega
…
“`
Com o lote contínuo, vLLM pode iniciar o processamento de cada solicitação imediatamente, em vez de esperar para agrupá-las em lotes pré-definidos.
Amostragem Paralela Eficiente
Para aplicações que exigem múltiplas amostras de saída por prompt (por exemplo, assistentes de escrita criativa), as capacidades de compartilhamento de memória do vLLM brilham. Ele pode gerar múltiplas saídas enquanto reutiliza o cache KV para prefixos compartilhados.
Exemplo de código usando vLLM:
from vllm import LLM, SamplingParams
llm = LLM(model="meta-llama/Llama-2-13b-hf")
prompts = ["O futuro da IA é"]
# Gerar 3 amostras por prompt
sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100)
outputs = llm.generate(prompts, sampling_params)
for output in outputs:
print(f"Prompt: {output.prompt}")
for i, out in enumerate(output.outputs):
print(f"Amostra {i + 1}: {out.text}")
Esse código gera eficientemente múltiplas amostras para o prompt dado, aproveitando as otimizações do vLLM.
Benchmarking do Desempenho do vLLM
Para realmente apreciar o impacto do vLLM, vamos olhar para algumas comparações de desempenho:
Comparação de Taxa de Serviço
Com base nas informações fornecidas, vLLM supera significativamente outras soluções de serviço:
– Até 24x mais taxa de serviço em comparação com Hugging Face Transformers
– 2,2x a 3,5x mais taxa de serviço do que Hugging Face Text Generation Inference (TGI)
Ilustração:
“`
Taxa de Serviço (Tokens/segundo)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`
Eficiência de Memória
O PagedAttention do vLLM resulta em uso de memória quase ótimo:
– Apenas cerca de 4% de desperdício de memória, em comparação com 60-80% em sistemas tradicionais
– Essa eficiência permite servir modelos maiores ou lidar com mais solicitações concorrentes com o mesmo hardware
Como Começar com vLLM
Agora que exploramos os benefícios do vLLM, vamos percorrer o processo de configurá-lo e usá-lo em seus projetos.
6.1 Instalação
Instalar vLLM é direto usando pip:
!pip install vllm
6.2 Uso Básico para Inferência Offline
Aqui está um exemplo simples de usar vLLM para geração de texto offline:
from vllm import LLM, SamplingParams
# Inicializar o modelo
llm = LLM(model="meta-llama/Llama-2-13b-hf")
# Preparar prompts
prompts = [
"Escreva um poema curto sobre inteligência artificial:",
"Explique computação quântica em termos simples:",
]
# Definir parâmetros de amostragem
sampling_params = SamplingParams(temperature=0.8, max_tokens=100)
# Gerar respostas
outputs = llm.generate(prompts, sampling_params)
# Imprimir os resultados
for output in outputs:
print(f"Prompt: {output.prompt}")
print(f"Texto gerado: {output.outputs[0].text}\n")
Esse script demonstra como carregar um modelo, definir parâmetros de amostragem e gerar texto para múltiplos prompts.
6.3 Configurando um Servidor vLLM
Para serviço online, vLLM fornece um servidor de API compatível com OpenAI. Aqui está como configurá-lo:
1. Inicie o servidor:
python -m vllm.entrypoints.openai.api_server --model meta-llama/Llama-2-13b-hf
2. Consulte o servidor usando curl:
curl http://localhost:8000/v1/completions \
-H "Content-Type: application/json" \
-d '{"model": "meta-llama/Llama-2-13b-hf", "prompt": "Os benefícios da inteligência artificial incluem:", "max_tokens": 100, "temperature": 0.7}'
Essa configuração permite servir seu LLM com uma interface compatível com a API do OpenAI, facilitando a integração em aplicações existentes.
Tópicos Avançados sobre vLLM
Embora vLLM ofereça melhorias significativas no serviço de LLM, há considerações e tópicos avançados adicionais a explorar:
7.1 Quantização de Modelo
Para um serviço ainda mais eficiente, especialmente em hardware com memória limitada, técnicas de quantização podem ser empregadas. Embora vLLM não suporte quantização atualmente, pode ser usado em conjunto com modelos quantizados:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch # Carregar um modelo quantizado model_name = "meta-llama/Llama-2-13b-hf" model = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", load_in_8bit=True) tokenizer = AutoTokenizer.from_pretrained(model_name) # Usar o modelo quantizado com vLLM from vllm import LLM llm = LLM(model=model, tokenizer=tokenizer)
7.2 Inferência Distribuída
Para modelos extremamente grandes ou aplicações de alto tráfego, a inferência distribuída em múltiplas GPUs ou máquinas pode ser necessária. Embora vLLM não suporte isso nativamente, pode ser integrado em sistemas distribuídos usando frameworks como Ray:
import ray
from vllm import LLM
@ray.remote(num_gpus=1)
class DistributedLLM:
def __init__(self, model_name):
self.llm = LLM(model=model_name)
def generate(self, prompt, params):
return self.llm.generate(prompt, params)
# Inicializar LLMs distribuídos
llm1 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
llm2 = DistributedLLM.remote("meta-llama/Llama-2-13b-hf")
# Usá-los em paralelo
result1 = llm1.generate.remote("Prompt 1", sampling_params)
result2 = llm2.generate.remote("Prompt 2", sampling_params)
# Recuperar resultados
print(ray.get([result1, result2]))
7.3 Monitoramento e Observabilidade
Ao servir LLMs em produção, o monitoramento é crucial. Embora vLLM não forneça monitoramento integrado, você pode integrá-lo com ferramentas como Prometheus e Grafana:
from prometheus_client import start_http_server, Summary
from vllm import LLM
# Definir métricas
REQUEST_TIME = Summary('request_processing_seconds', 'Tempo gasto processando solicitação')
# Inicializar vLLM
llm = LLM(model="meta-llama/Llama-2-13b-hf")
# Expor métricas
start_http_server(8000)
# Usar o modelo com monitoramento
@REQUEST_TIME.time()
def process_request(prompt):
return llm.generate(prompt)
# Seu loop de serviço aqui
Essa configuração permite rastrear métricas como tempo de processamento de solicitação, que podem ser visualizadas em dashboards do Grafana.
Conclusão
Servir Modelos de Linguagem Grande de forma eficiente é uma tarefa complexa, mas crucial na era da IA. vLLM, com seu algoritmo de atenção inovador e implementação otimizada, representa um grande passo para frente na tecnologia de serviço de LLM.
Ao melhorar drasticamente a taxa de serviço, reduzir o desperdício de memória e permitir opções de serviço mais flexíveis, vLLM abre novas possibilidades para integrar modelos de linguagem poderosos em uma ampla gama de aplicações. Seja que você esteja construindo um chatbot, um sistema de geração de conteúdo ou qualquer outra aplicação alimentada por NLP, entender e aproveitar ferramentas como vLLM será fundamental para o sucesso.














