A implantação de Giant Language Fashions (LLMs) em aplicativos do mundo actual apresenta desafios únicos, particularmente em termos de recursos computacionais, latência e custo-benefício. Neste guia abrangente, exploraremos o cenário do serviço LLM, com foco explicit no vLLM (vector Language Mannequin), uma solução que está remodelando a maneira como implantamos e interagimos com esses modelos poderosos.
Os desafios de servir grandes modelos de linguagem
Antes de mergulhar em soluções específicas, vamos examinar os principais desafios que tornam o atendimento de LLM uma tarefa complexa:
Recursos Computacionais
Os LLMs são notórios por suas enormes contagens de parâmetros, variando de bilhões a centenas de bilhões. Por exemplo, o GPT-3 ostenta 175 bilhões de parâmetros, enquanto estima-se que modelos mais recentes como o GPT-4 tenham ainda mais. Esse tamanho absoluto se traduz em requisitos computacionais significativos para inferência.
Exemplo:
Considere um LLM relativamente modesto com 13 bilhões de parâmetros, como LLaMA-13B. Mesmo este modelo requer:
– Aproximadamente 26 GB de memória apenas para armazenar os parâmetros do modelo (assumindo precisão de 16 bits)
– Memória adicional para ativações, mecanismos de atenção e computações intermediárias
– Poder de computação de GPU substancial para inferência em tempo actual
Latência
Em muitas aplicações, como chatbots ou geração de conteúdo em tempo actual, baixa latência é essential 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:
Think about um chatbot de atendimento ao cliente alimentado por um LLM. Se cada resposta levar vários segundos para ser gerada, a conversa parecerá synthetic e frustrante para os usuários.
Custo
O {hardware} necessário para executar LLMs em escala pode ser extremamente caro. GPUs ou TPUs de ponta são frequentemente necessárias, e o consumo de energia desses sistemas é substancial.
Exemplo:
Executar um cluster de GPUs NVIDIA A100 (geralmente usadas para inferência LLM) pode custar milhares de dólares por dia em taxas de computação em nuvem.
Abordagens tradicionais para o serviço de LLM
Antes de explorar soluções mais avançadas, vamos revisar brevemente algumas abordagens tradicionais para atender LLMs:
Implantação simples com transformadores de rosto envolventes
A biblioteca Hugging Face Transformers fornece uma maneira simples de implantar LLMs, mas não é otimizada para serviços de alto rendimento.
Código de exemplo:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch model_name = "meta-llama/Llama-2-13b-hf" mannequin = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto") tokenizer = AutoTokenizer.from_pretrained(model_name) def generate_text(immediate, max_length=100): inputs = tokenizer(immediate, return_tensors="pt").to(mannequin.machine) outputs = mannequin.generate(**inputs, max_length=max_length) return tokenizer.decode(outputs(0), skip_special_tokens=True) print(generate_text("The way forward for AI is"))
Embora essa abordagem funcione, ela não é adequada para aplicativos de alto tráfego devido ao uso ineficiente de recursos e à falta de otimizações para atendimento.
Usando TorchServe ou Frameworks Similares
Frameworks como TorchServe fornecem recursos de serviço mais robustos, incluindo balanceamento de carga e versionamento de modelo. No entanto, eles ainda não abordam os desafios específicos do serviço LLM, como gerenciamento de memória eficiente para modelos grandes.
Compreendendo o gerenciamento de memória no serviço LLM
O gerenciamento eficiente de memória é crítico para servir modelos de linguagem grandes (LLMs) devido aos extensos recursos computacionais necessários. As imagens a seguir ilustram vários aspectos do gerenciamento de memória, que são integrais para otimizar o desempenho do LLM.
Memória segmentada vs. paginada
Esses dois diagramas comparam técnicas de gerenciamento de memória segmentada e memória paginada, comumente usadas em sistemas operacionais (SO).
- Memória Segmentada: Esta técnica divide a memória em diferentes segmentos, cada um correspondendo a um programa ou processo diferente. Por exemplo, em um contexto de serviço LLM, diferentes segmentos podem ser alocados a vários componentes do modelo, como tokenização, incorporação e mecanismos de atenção. Cada segmento pode crescer ou encolher 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. As 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 LLM, isso pode ser essential para gerenciar as grandes quantidades de memória necessárias para armazenar pesos de modelo e cálculos intermediários.
Gerenciamento de memória no SO vs. vLLM
Esta imagem contrasta o gerenciamento de memória tradicional do sistema operacional com a abordagem de gerenciamento de memória usada no vLLM.
- Gerenciamento de memória do sistema operacional: Em sistemas operacionais tradicionais, processos (por exemplo, Processo A e Processo B) recebem páginas de memória alocadas (Página 0, Página 1, and so forth.) na memória física. Essa alocação pode levar à fragmentação ao longo do tempo, pois os processos solicitam e liberam memória.
- Gerenciamento de memória vLLM: A estrutura 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 blocos alocados do cache KV (KV Bloco 0, KV Bloco 1, and so forth.). Essa abordagem ajuda a minimizar a fragmentação e otimiza o uso da memória, permitindo um serviço de modelo mais rápido e eficiente.
Mecanismo de Atenção em LLMs
Mecanismo de Atenção em LLMs
O mecanismo de atenção é um componente elementary dos modelos de transformadores, que são comumente usados para LLMs. Este diagrama ilustra a fórmula de atenção e seus componentes:
- Consulta (Q): Um novo token na etapa do decodificador ou o último token que o modelo viu.
- Chave (Ok): 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, escalando 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 rendimento de serviço
![vLLM: Atendimento LLM fácil, rápido e barato com PagedAttention](https://i0.wp.com/www.unite.ai/wp-content/uploads/2024/07/Screenshot-2024-07-14-172325.png?resize=401%2C265&ssl=1)
vLLM: Atendimento LLM fácil, rápido e barato com PagedAttention
Esta imagem apresenta uma comparação do rendimento de serviço entre diferentes estruturas (HF, TGI e vLLM) usando modelos LLaMA em diferentes configurações de {hardware}.
- LLaMA-13B, A100-40GB: O vLLM atinge uma taxa de transferência 14x – 24x maior do que os transformadores HuggingFace (HF) e 2,2x – 2,5x maior do que a inferência de geração de texto HuggingFace (TGI).
- LLaMA-7B, A10G:Tendências semelhantes são observadas, com o vLLM superando significativamente o HF e o TGI.
vLLM: Uma nova arquitetura de atendimento ao LLM
O vLLM, desenvolvido por pesquisadores da UC Berkeley, representa um salto significativo na tecnologia de atendimento de LLM. Vamos explorar seus principais recursos e inovações:
Atenção Paginada
No coração do vLLM está o PagedAttention, um novo algoritmo de atenção inspirado no gerenciamento de memória digital em sistemas operacionais. Veja como ele funciona:
– Particionamento de cache de chave-valor (KV): Em vez de armazenar todo o cache KV de forma contígua na memória, o PagedAttention o divide em blocos de tamanho fixo.
– Armazenamento não contíguo:Esses blocos podem ser armazenados de forma não contígua na memória, permitindo um gerenciamento de memória mais flexível.
– Alocação sob demanda: Os blocos são alocados somente quando necessário, reduzindo o desperdício de memória.
– Compartilhamento Eficiente: Várias sequências podem compartilhar blocos, permitindo otimizações para técnicas como amostragem paralela e busca de 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 PagedAttention:
(Bloco 1) -> Endereço Físico A
(Bloco 2) -> Endereço Físico C
(Bloco 3) -> Endereço Físico B
…
(Alocação de memória não contígua)
“`
Essa abordagem reduz significativamente a fragmentação da memória e permite um uso muito mais eficiente da memória da GPU.
Dosagem Contínua
O vLLM implementa batching contínuo, que processa solicitações dinamicamente conforme elas chegam, em vez de esperar para formar lotes de tamanho fixo. Isso leva a menor latência e maior rendimento.
Exemplo:
Think about um fluxo de solicitações recebidas:
“`
Tempo 0ms: A solicitação A chega
Tempo 10ms: Iniciar processamento da solicitação A
Tempo 15ms: A solicitação B chega
Tempo 20ms: Iniciar processamento da solicitação B (em paralelo com A)
Tempo 25ms: A solicitação C chega
…
“`
Com o processamento em lote contínuo, o vLLM pode começar a processar cada solicitação imediatamente, em vez de esperar para agrupá-las em lotes predefinidos.
Amostragem paralela eficiente
Para aplicativos que exigem múltiplas amostras de saída por immediate (por exemplo, assistentes de escrita criativa), os recursos de compartilhamento de memória do vLLM brilham. Ele pode gerar múltiplas saídas enquanto reutiliza o cache KV para prefixos compartilhados.
Código de exemplo usando vLLM:
from vllm import LLM, SamplingParams llm = LLM(mannequin="meta-llama/Llama-2-13b-hf") prompts = ("The way forward for AI is") # Generate 3 samples per immediate sampling_params = SamplingParams(n=3, temperature=0.8, max_tokens=100) outputs = llm.generate(prompts, sampling_params) for output in outputs: print(f"Immediate: {output.immediate}") for i, out in enumerate(output.outputs): print(f"Pattern {i + 1}: {out.textual content}")
Este código gera eficientemente múltiplas amostras para o immediate fornecido, aproveitando as otimizações do vLLM.
Comparação de desempenho do vLLM
Para realmente apreciar o impacto do vLLM, vamos analisar algumas comparações de desempenho:
Comparação de rendimento
Com base nas informações fornecidas, o vLLM supera significativamente outras soluções de serviço:
– Até 24x maior rendimento em comparação com os transformadores Hugging Face
– 2,2x a 3,5x maior rendimento do que o Hugging Face Textual content Era Inference (TGI)
Ilustração:
“`
Taxa de transferência (Tokens/segundo)
|
| ****
| ****
| ****
| **** ****
| **** **** ****
| **** **** ****
|————————
HF TGI vLLM
“`
Eficiência de memória
O PagedAttention do vLLM resulta em uso de memória quase ultimate:
– Apenas cerca de 4% de desperdício de memória, em comparação com 60-80% em sistemas tradicionais
– Essa eficiência permite atender modelos maiores ou lidar com mais solicitações simultâneas com o mesmo {hardware}
Introdução ao vLLM
Agora que exploramos os benefícios do vLLM, vamos explicar o processo de configuração e utilização em seus projetos.
6.1 Instalação
A instalação do vLLM é simples usando pip:
!pip set up vllm
6.2 Uso básico para inferência offline
Aqui está um exemplo simples de uso do vLLM para geração de texto offline:
from vllm import LLM, SamplingParams # Initialize the mannequin llm = LLM(mannequin="meta-llama/Llama-2-13b-hf") # Put together prompts prompts = ( "Write a brief poem about synthetic intelligence:", "Clarify quantum computing in easy phrases:" ) # Set sampling parameters sampling_params = SamplingParams(temperature=0.8, max_tokens=100) # Generate responses outputs = llm.generate(prompts, sampling_params) # Print the outcomes for output in outputs: print(f"Immediate: {output.immediate}") print(f"Generated textual content: {output.outputs(0).textual content}n")
Este script demonstra como carregar um modelo, definir parâmetros de amostragem e gerar texto para vários prompts.
6.3 Configurando um servidor vLLM
Para servir on-line, o vLLM fornece um servidor de API compatível com OpenAI. Veja 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 material-Kind: software/json" -d '{ "mannequin": "meta-llama/Llama-2-13b-hf", "immediate": "The advantages of synthetic intelligence embody:", "max_tokens": 100, "temperature": 0.7 }'
Essa configuração permite que você ofereça ao seu LLM uma interface compatível com a API do OpenAI, facilitando a integração em aplicativos existentes.
Tópicos avançados sobre vLLM
Embora o vLLM ofereça melhorias significativas no atendimento de LLM, há considerações adicionais e tópicos avançados a serem explorados:
7.1 Quantização do modelo
Para um serviço ainda mais eficiente, especialmente em {hardware} com memória limitada, técnicas de quantização podem ser empregadas. Embora o vLLM em si não suporte quantização atualmente, ele pode ser usado em conjunto com modelos quantizados:
from transformers import AutoModelForCausalLM, AutoTokenizer import torch # Load a quantized mannequin model_name = "meta-llama/Llama-2-13b-hf" mannequin = AutoModelForCausalLM.from_pretrained(model_name, device_map="auto", load_in_8bit=True) tokenizer = AutoTokenizer.from_pretrained(model_name) # Use the quantized mannequin with vLLM from vllm import LLM llm = LLM(mannequin=mannequin, tokenizer=tokenizer)
7.2 Inferência Distribuída
Para modelos extremamente grandes ou aplicativos de alto tráfego, a inferência distribuída entre várias GPUs ou máquinas pode ser necessária. Embora o vLLM não suporte isso nativamente, ele pode ser integrado a sistemas distribuídos usando frameworks como Ray:
import ray from vllm import LLM @ray.distant(num_gpus=1) class DistributedLLM: def __init__(self, model_name): self.llm = LLM(mannequin=model_name) def generate(self, immediate, params): return self.llm.generate(immediate, params) # Initialize distributed LLMs llm1 = DistributedLLM.distant("meta-llama/Llama-2-13b-hf") llm2 = DistributedLLM.distant("meta-llama/Llama-2-13b-hf") # Use them in parallel result1 = llm1.generate.distant("Immediate 1", sampling_params) result2 = llm2.generate.distant("Immediate 2", sampling_params) # Retrieve outcomes print(ray.get((result1, result2)))
7.3 Monitoramento e Observabilidade
Ao servir LLMs em produção, o monitoramento é essential. Embora o vLLM não forneça monitoramento integrado, você pode integrá-lo com ferramentas como Prometheus e Grafana:
from prometheus_client import start_http_server, Abstract from vllm import LLM # Outline metrics REQUEST_TIME = Abstract('request_processing_seconds', 'Time spent processing request') # Initialize vLLM llm = LLM(mannequin="meta-llama/Llama-2-13b-hf") # Expose metrics start_http_server(8000) # Use the mannequin with monitoring @REQUEST_TIME.time() def process_request(immediate): return llm.generate(immediate) # Your serving loop right here
Essa configuração permite que você monitore métricas como tempo de processamento de solicitações, que podem ser visualizadas nos painéis do Grafana.
Conclusão
Atender grandes modelos de linguagem de forma eficiente é uma tarefa complexa, mas essential na period da IA. O vLLM, com seu algoritmo inovador PagedAttention e implementação otimizada, representa um avanço significativo para tornar a implantação de LLM mais acessível e econômica.
Ao melhorar drasticamente o rendimento, reduzir o desperdício de memória e habilitar opções de serviço mais flexíveis, o vLLM abre novas possibilidades para integrar modelos de linguagem poderosos em uma ampla gama de aplicativos. Não importa se você está construindo um chatbot, um sistema de geração de conteúdo ou qualquer outro aplicativo alimentado por PNL, entender e aproveitar ferramentas como o vLLM será a chave para o sucesso.