Engenharia de prompts

Acelerando a Inferência de Modelos de Linguagem Grande: Técnicas para Implantação Eficiente

mm
Adicione Unite.AI às suas fontes preferidas no Google
LLM Inference Speed up

Os modelos de linguagem grande (LLMs) como GPT-4, LLaMA e PaLM estão empurrando os limites do que é possível com o processamento de linguagem natural. No entanto, implantar esses modelos maciços em ambientes de produção apresenta desafios significativos em termos de requisitos computacionais, uso de memória, latência e custo. À medida que os LLMs continuam a crescer em tamanho e capacidade, otimizar o desempenho da inferência é fundamental para aplicações do mundo real.

Neste mergulho técnico, exploraremos técnicas de ponta para acelerar a inferência de LLM, permitindo tempos de resposta mais rápidos, maior throughput e utilização mais eficiente de recursos de hardware. Cobriremos métodos que variam de técnicas de precisão numérica e mecanismos de atenção inovadores a inovações arquiteturais projetadas explicitamente para geração de texto eficiente.

Vamos começar entendendo por que a inferência de LLM é tão desafiadora em comparação com modelos de NLP tradicionais.

O Desafio da Inferência com Modelos de Linguagem Grande

Antes do advento dos LLMs, o processamento de linguagem natural dependia de modelos menores focados em tarefas específicas, como classificação de texto, reconhecimento de entidades nomeadas e análise de sentimento. Embora ainda computacionalmente intensivos, esses modelos podiam ser implantados em hardware modesto e seguiam processos de inferência relativamente diretos.

Os LLMs, por outro lado, representam uma mudança de paradigma. Esses modelos são treinados em conjuntos de dados vastos usando bilhões de parâmetros, permitindo que realizem uma ampla gama de tarefas de linguagem com notável proficiência. No entanto, esse poder vem com um custo – demandas computacionais dramaticamente aumentadas durante tanto o treinamento quanto a inferência.

Um dos principais desafios é a natureza autoregressiva da geração de texto com LLMs. Para produzir texto humano-like, esses modelos preveem um token (palavra ou subpalavra) de cada vez, com cada novo token dependendo da saída gerada anteriormente. Essa dependência sequencial impede a paralelização eficiente e resulta em requisitos computacionais que escalam polynomialmente com o comprimento da sequência.

Além disso, os LLMs frequentemente exigem sequências de entrada longas (prompt) para estabelecer o contexto necessário para a geração de texto de alta qualidade. Comprimentos de entrada mais longos exigem mais memória para armazenar estados intermediários e matrizes de atenção, sobrecarregando ainda mais os recursos de hardware.

Com esses desafios únicos, técnicas de otimização tradicionais, como quantização e gráficos de computação estáticos, podem ser insuficientes, lutando para manter o desempenho do LLM enquanto fornecem acelerações significativas. Vamos mergulhar em algumas das principais estratégias projetadas explicitamente para acelerar a inferência de LLM.

Técnicas de Precisão Numérica

From 32-Bit to 16-Bit Precision

From 32-Bit to 16-Bit Precision

Uma das vias para acelerar a inferência de LLM é aproveitar a precisão numérica reduzida para pesos e ativações do modelo. As estruturas de aprendizado de máquina modernas, como PyTorch e TensorFlow, geralmente empregam precisão de ponto flutuante de 32 bits (FP32) por padrão. No entanto, pesquisas mostraram que os LLMs podem manter alta precisão mesmo quando operando em precisões mais baixas, como 16 bits (FP16), 8 bits inteiros (INT8) ou até 4 bits inteiros (INT4).

A redução da precisão numérica oferece vários benefícios:

  • Pegada de Memória Reduzida: Representações de precisão mais baixa exigem menos memória, permitindo que modelos maiores ou tamanhos de lote se encaixem dentro das mesmas restrições de hardware.
  • Cômputo Mais Rápido: Muitos CPUs e GPUs modernos fornecem instruções especializadas e aceleração de hardware para aritmética de precisão mais baixa, permitindo acelerações significativas.
  • Melhor Eficiência Energética: Com requisitos de memória menores e cômputos mais rápidos, a inferência de precisão mais baixa pode se traduzir em consumo de energia reduzido – uma vantagem crucial para implantações de borda e móveis.

Embora poderosa, a técnica de precisão numérica introduz alguma perda de precisão em comparação com a operação FP32. A chave é avaliar cuidadosamente essa troca entre ganhos computacionais e possível degradação de desempenho para o seu caso de uso específico.

Existem duas principais abordagens para quantização com LLMs:

Quantização Pós-Treinamento (PTQ): Neste método, um LLM é primeiro treinado usando precisão FP32 padrão. Após o treinamento, os pesos do modelo são quantizados (convertidos) para um formato de precisão mais baixa, como INT8 ou INT4. A PTQ é direta de implementar, mas pode levar a maiores quedas de precisão.

Treinamento Consciente de Quantização (QAT): Com o QAT, o processo de quantização é simulado durante a própria fase de treinamento. Isso permite que o modelo aprenda a compensar erros de quantização, minimizando a degradação de precisão quando o modelo quantizado final é implantado. O QAT é mais envolvido, mas frequentemente produz melhores resultados em comparação com a PTQ.

Para aplicação prática, alguém pode aproveitar modelos pré-quantizados disponíveis em plataformas como Hugging Face, que hospeda uma variedade de modelos otimizados por meio de diferentes métodos de quantização. Por exemplo, se um modelo quantizado usando Auto-GPTQ for desejado, os usuários podem facilmente carregá-lo usando a biblioteca de transformadores do Hugging Face. Além disso, para quantizar um modelo, ferramentas como AutoGPTQ podem ser utilizadas, que se integram perfeitamente com bibliotecas existentes para comprimir o modelo de forma eficiente.

Aqui está um exemplo de carregar um modelo Llama-2-7b pré-quantizado usando a biblioteca de transformadores do Hugging Face:

from transformers import AutoModelForCausalLM, AutoTokenizer

<p>model_id = "TheBloke/Llama-2-7b-Chat-GPTQ"
tokenizer = AutoTokenizer.from_pretrained(model_id)
model = AutoModelForCausalLM.from_pretrained(model_id)
E para quantização personalizada, alguém pode seguir esses passos usando a ferramenta AutoGPTQ:</p>

<p>from transformers import AutoModelForCausalLM, AutoTokenizer, GPTQConfig</p>

<p>model_id = "llama-2-7b-original"
tokenizer = AutoTokenizer.from_pretrained(model_id)
quantization_config = GPTQConfig(bits=4, dataset="seu-dataset", tokenizer=tokenizer)
model = AutoModelForCausalLM.from_pretrained(model_id, quantization_config=quantization_config)</p>

Lembre-se de que a quantização pode exigir ajuste fino pós-quantização ou engenharia de prompt para manter a qualidade do modelo. Para nova quantização, você pode contribuir para a comunidade publicando seus modelos quantizados em plataformas como o Hugging Face.

Always certifique-se de equilibrar entre o tamanho do modelo, requisitos computacionais e desempenho ao selecionar a estratégia de quantização para o seu caso de uso específico.

 

O Algoritmo de Atenção Flash

O mecanismo de atenção multi-cabeça é um componente central dos LLMs baseados em transformadores, permitindo que o modelo capture dependências de longo alcance e representações contextualizadas. No entanto, essa operação de atenção é computacionalmente ineficiente para a geração de texto autoregressiva, pois exige a recomputação de muitos dos mesmos valores para cada novo token.

O algoritmo de Atenção Flash, introduzido no papel FlashAttention, fornece uma abordagem mais eficiente em termos de memória e mais amigável à paralelização para a operação de atenção. Em vez de recomputar valores de atenção para cada token, a Atenção Flash armazena e reutiliza matrizes-chave/valor intermediárias, evitando cálculos redundantes.

Essa otimização não apenas reduz a sobrecarga computacional, mas também melhora os padrões de acesso à memória, levando a uma melhor utilização da largura de banda de memória da GPU e paralelismo.

Embora os detalhes da Atenção Flash sejam bastante envolvidos, a ideia geral é decompor a operação de atenção em duas fases:

  1. Somatório de Embedding de Prefixo: Essa fase computa e armazena embeddings de chave/valor para todos os tokens de entrada, permitindo a reutilização eficiente durante a geração.
  2. Atenção Causal: A operação de atenção real, agora otimizada para aproveitar os embeddings de chave/valor armazenados da primeira fase.

Ao separar essas fases, a Atenção Flash pode aproveitar operações de GPU altamente paralelas, acelerando significativamente o gargalo de atenção na inferência de LLM.

Aqui está uma breve ilustração conceitual de implementação da Atenção Flash com um LLM:

from transformers import AutoModelForCausalLM
import torch
from flash_attention import flash_attention

<p># Carregar um LLM como OctoCoder
model = AutoModelForCausalLM.from_pretrained("bigcode/octocoder")</p>

<p># Prompt de sistema de exemplo que guia o modelo para ser um melhor assistente de codificação
system_prompt = "..."</p>

<p># Preparando uma entrada mais longa com o prompt de sistema
long_prompt = system_prompt + "Pergunta: Por favor, escreva uma função em Python que transforma bytes em Gigabytes."</p>

<p># Convertendo o modelo para a otimização da Atenção Flash
model.to_bettertransformer()</p>

<p># Executando o modelo com Atenção Flash
start_time = time.time()
with torch.backends.cuda.sdp_kernel(enable_flash=True):
result = model.generate(long_prompt, max_new_tokens=60)
print(f"Gerado em {time.time() - start_time} segundos.")

Embora a Atenção Flash ofereça ganhos de desempenho impressionantes, ela funciona dentro da arquitetura de transformador existente. Para liberar totalmente o potencial da inferência de LLM acelerada, precisamos explorar inovações arquiteturais projetadas especificamente para essa tarefa.

Podando LLMs

Podar LLMs é uma técnica para reduzir o tamanho do modelo enquanto mantém a funcionalidade. Ela usa um estimador de importância de peso baseado em aproximações de matriz de Hessian. No poda, grupos de pesos menos importantes são removidos, e então o modelo é ajustado para recuperar a precisão. O pacote LLM-Pruner oferece scripts para poda com várias estratégias suportadas. A poda inclui descoberta de dependências, estimativa de contribuições de grupo e uma etapa de recuperação envolvendo um breve treinamento pós-implantação.

Aqui está um exemplo simplificado de código Python demonstrando o uso do LLM-Pruner para um modelo LLaMa:

from transformers import AutoModelForSequenceClassification
from pruning import LLMPruner

<p># Carregar o modelo LLaMa pré-treinado
model = AutoModelForSequenceClassification.from_pretrained("llama-base")</p>

<p># Inicializar o podador com a configuração desejada
pruner = LLMPruner(
model,
pruning_ratio=0.25,
block_mlp_layers=(4, 30),
block_attention_layers=(4, 30),
pruner_type='taylor'
)</p>

<p># Executar a poda
pruned_model = pruner.prune()</p>

<p># Ajustar o modelo podado
pruned_model.fine_tune(dados_de_treinamento)

Essa esboço de código representa carregar um modelo LLaMa pré-treinado, configurar o podador com configurações específicas (como quais camadas podar e o tipo de podador), executar o processo de poda e, finalmente, ajustar o modelo podado.

Observe que, para uma implementação real, você precisaria preencher detalhes como o nome específico do modelo, caminhos para os dados, e parâmetros adicionais para o processo de ajuste. Além disso, esteja ciente de que esse código é uma representação conceitual, e a sintaxe real pode variar dependendo da biblioteca e das versões usadas.

Inovações Arquiteturais para Geração de Texto Eficiente

A arquitetura de transformador, embora altamente eficaz para tarefas de modelagem de linguagem, foi projetada como um modelo de sequência-para-sequência de propósito geral. Quando implantando LLMs para tarefas de geração de texto com contextos de entrada longos, os pesquisadores encontraram que arquiteturas mais especializadas podem melhorar significativamente a eficiência da inferência sem sacrificar a qualidade.

Aqui estão algumas das principais inovações arquiteturais que permitem inferência de LLM mais rápida:

Alibi: A arquitetura Alibi, introduzida no papel PAL-Instruction, separa a modelagem do contexto de entrada longo do processo de geração de texto em si. Ela usa uma representação comprimida do contexto de entrada (o “alibi”) para inicializar o processo de geração, evitando a necessidade de processar a sequência de entrada completa repetidamente durante a geração autoregressiva.

Embeddings Rotatórias: Em vez de usar embeddings de posição padrão, a técnica de embeddings rotatórios emprega matrizes de rotação para codificar informações de posição de forma mais eficiente. Essa abordagem mostrou melhorar o desempenho e permitir o processamento de sequências de entrada mais longas.

Atenção de Consulta Múltipla (MQA): Na atenção tradicional, cada token de saída atende à sequência de entrada inteira, resultando em cômputo redundante. A MQA reformula a operação de atenção para compartilhar cômputos entre vários tokens de saída, reduzindo a complexidade geral.

Atenção de Consulta Múltipla

Atenção de Consulta Múltipla

Atenção de Consulta Agrupada (GQA): Construindo sobre a MQA, a GQA agrupa tokens de saída em clusters e computa a atenção conjuntamente para cada cluster. Essa abordagem reduz ainda mais os requisitos computacionais, mantendo a geração de texto de alta qualidade.

Embora ainda em pesquisa e desenvolvimento ativo, essas inovações arquiteturais demonstraram acelerações impressionantes para tarefas de inferência de LLM, especialmente quando combinadas com técnicas como Atenção Flash e otimização de precisão numérica.

Considerações de Implantação no Mundo Real

Além dos algoritmos e arquiteturas centrais, existem várias considerações práticas e trade-offs a serem navegados ao implantar LLMs em ambientes de produção:

Aceleração de Hardware: Embora os CPUs possam lidar com a inferência de LLM, os GPUs e outros aceleradores, como os TPUs do Google , são essenciais para alcançar alto throughput e baixa latência. Escolher o hardware certo e otimizar o uso de memória é crucial.

Batching e Paralelismo: Para aproveitar totalmente o paralelismo do hardware, estratégias como inferência em lote (processamento de múltiplas entradas simultaneamente) e paralelismo de modelo (distribuição de um LLM em vários dispositivos) podem aumentar significativamente o throughput.

Quantização vs. Qualidade Trade-Off: O grau de quantização (8-bit, 4-bit, etc.) afetará diretamente a velocidade da inferência e o uso de memória, mas também afeta a qualidade da saída. Essa troca deve ser cuidadosamente avaliada para cada caso de uso.

Destilação de Modelo: Uma alternativa à quantização, as técnicas de destilação de modelo podem comprimir grandes LLMs em modelos de estudante menores e mais eficientes, mantendo alta precisão.

Cache e Runtimes Otimizados: Runtimes de aprendizado de máquina otimizados, como o TensorRT da NVIDIA , e frameworks projetados para servir LLMs (por exemplo, o Conjunto de Inferência Componível da MosaicML) podem fornecer ganhos de desempenho significativos por meio de técnicas como fusão de operadores, otimização de kernel e estratégias de cache inteligentes.

O caminho para a implantação ótima de LLMs frequentemente envolve combinar várias técnicas, considerando cuidadosamente os requisitos específicos da aplicação, as restrições de infraestrutura e os alvos de desempenho.

Conclusão

À medida que os modelos de linguagem grande continuam sua evolução rápida, acelerar o desempenho da inferência se torna cada vez mais crucial para permitir aplicações do mundo real e democratizar o acesso a essas poderosas capacidades de IA.

Neste guia técnico, exploramos técnicas de ponta que variam desde otimização de precisão numérica e algoritmos de atenção inovadores, como a Atenção Flash, até inovações arquiteturais projetadas para geração de texto eficiente. Embora cada abordagem ofereça seus próprios vantagens, o verdadeiro poder frequentemente reside em combinar várias estratégias, navegando os trade-offs intricados entre velocidade, uso de memória e qualidade da saída.

Olhando para o futuro, podemos esperar pesquisa e desenvolvimento contínuos nesse domínio, impulsionados pela demanda insaciável por LLMs mais capazes e acessíveis. Desde aceleração de hardware e compressão de modelo até arquiteturas completamente novas, a busca por inferência de LLM eficiente permanece uma fronteira emocionante no mundo do processamento de linguagem natural e inteligência artificial.

Eu passei os últimos cinco anos me imergindo no fascinante mundo de Aprendizado de Máquina e Aprendizado Profundo. Minha paixão e expertise me levaram a contribuir para mais de 50 projetos de engenharia de software diversificados, com um foco particular em IA/ML. Minha curiosidade contínua também me levou em direção ao Processamento de Linguagem Natural, um campo que estou ansioso para explorar mais.