Tech

Otimizando memória para inferência e ajuste fino de modelos de linguagem grande

Grandes modelos de linguagem (LLMs) como GPT-4, Bloom e LLaMA alcançaram capacidades notáveis ​​ao escalar até bilhões de parâmetros. No entanto, a implantação desses modelos massivos para inferência ou ajuste fino é um desafio devido aos seus imensos requisitos de memória. Neste weblog técnico, exploraremos técnicas para estimar e otimizar o consumo de memória durante a inferência LLM e o ajuste fino em várias configurações de {hardware}.

Compreendendo os requisitos de memória

A memória necessária para carregar um LLM é determinada principalmente pelo número de parâmetros e pela precisão numérica usada para armazenar os parâmetros. Uma regra simples é:

  • Carregar um modelo com X bilhões de parâmetros requer aproximadamente 4X GB de VRAM em 32 bits precisão flutuante
  • Carregar um modelo com X bilhões de parâmetros requer aproximadamente 2X GB de VRAM em 16 bits precisão bfloat16/float16

Por exemplo, carregar o modelo GPT-3 de parâmetro 175B exigiria aproximadamente 350 GB de VRAM com precisão bfloat16. Atualmente, as maiores GPUs disponíveis comercialmente, como NVIDIA A100 e H100, oferecem apenas 80 GB de VRAM, necessitando de paralelismo de tensor e técnicas de paralelismo de modelo.

Durante a inferência, o consumo de memória é dominado pelos parâmetros do modelo e pelos tensores de ativação temporários produzidos. Uma estimativa de alto nível para o pico de uso de memória durante a inferência é a soma da memória necessária para carregar os parâmetros do modelo e a memória para ativações.

Quantificando a memória de inferência

Vamos quantificar os requisitos de memória para inferência usando o modelo OctoCode, que possui cerca de 15 bilhões de parâmetros no formato bfloat16 (~31GB). Usaremos a biblioteca Transformers para carregar o modelo e gerar texto:

</pre>
from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
import torch
mannequin = AutoModelForCausalLM.from_pretrained("bigcode/octocoder",
torch_dtype=torch.bfloat16,
device_map="auto",
pad_token_id=0)
tokenizer = AutoTokenizer.from_pretrained("bigcode/octocoder")
pipe = pipeline("text-generation", mannequin=mannequin, tokenizer=tokenizer)
immediate = "Query: Please write a Python perform to transform bytes to gigabytes.nnAnswer:"
consequence = pipe(immediate, max_new_tokens=60)(0)("generated_text")(len(immediate):)
def bytes_to_gigabytes(bytes):
return bytes / 1024 / 1024 / 1024
bytes_to_gigabytes(torch.cuda.max_memory_allocated())
<pre>

Saída:

O pico de uso de memória da GPU é de cerca de 29 GB, o que se alinha com nossa estimativa de 31 GB para carregar os parâmetros do modelo no formato bfloat16.

Otimizando Memória de Inferência com Quantização

Embora bfloat16 seja a precisão comum usada para treinar LLMs, os pesquisadores descobriram que quantizar os pesos do modelo para tipos de dados de menor precisão, como inteiros de 8 bits (int8) ou inteiros de 4 bits, pode reduzir significativamente o uso de memória com perda mínima de precisão para tarefas de inferência como geração de texto.

Vamos ver a economia de memória com a quantização de 8 e 4 bits do modelo OctoCode:

</div>
# 8-bit quantization
mannequin = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_8bit=True, 
pad_token_id=0)
pipe = pipeline("text-generation", mannequin=mannequin, tokenizer=tokenizer)
consequence = pipe(immediate, max_new_tokens=60)(0)("generated_text")(len(immediate):)
bytes_to_gigabytes(torch.cuda.max_memory_allocated())</pre>
Output:
# 4-bit quantization
mannequin = AutoModelForCausalLM.from_pretrained("bigcode/octocoder", load_in_4bit=True,
low_cpu_mem_usage=True, pad_token_id=0)
pipe = pipeline("text-generation", mannequin=mannequin, tokenizer=tokenizer)
consequence = pipe(immediate, max_new_tokens=60)(0)("generated_text")(len(immediate):)
bytes_to_gigabytes(torch.cuda.max_memory_allocated())
</pre>
<pre>

Saída:

Com a quantização de 8 bits, o requisito de memória cai de 31 GB para 15 GB, enquanto a quantização de 4 bits reduz ainda mais para apenas 9,5 GB! Isso permite executar o modelo OctoCode de 15B de parâmetro em GPUs de consumo como o RTX 3090 (24GB VRAM).

No entanto, observe que uma quantização mais agressiva, como a de 4 bits, às vezes pode levar à degradação da precisão em comparação com a precisão de 8 bits ou bfloat16. Há uma compensação entre economia de memória e precisão que os usuários devem avaliar para seu caso de uso.

A quantização é uma técnica poderosa que pode permitir a implantação de LLM em ambientes com recursos limitados, como instâncias de nuvem, dispositivos de borda ou até mesmo telefones celulares, reduzindo drasticamente o consumo de memória.

Estimando memória para ajuste fino

Embora a quantização seja usada principalmente para inferência eficiente, técnicas como paralelismo de tensores e paralelismo de modelos são cruciais para gerenciar requisitos de memória durante o treinamento ou ajuste fino de grandes modelos de linguagem.

O pico de consumo de memória durante o ajuste fino é normalmente 3 a 4 vezes maior que o inferido devido aos requisitos adicionais de memória para:

  • Gradientes
  • Estados do otimizador
  • Ativações do passe direto armazenadas para retropropagação

Uma estimativa conservadora é que o ajuste fino de um LLM com X bilhões de parâmetros requer cerca de 4 * (2X) = 8XGB de VRAM com precisão bfloat16.

Por exemplo, o ajuste fino do modelo LLaMA de parâmetro 7B exigiria aproximadamente 7 * 8 = 56 GB de VRAM por GPU com precisão bfloat16. Isso excede a capacidade de memória das GPUs atuais, necessitando de técnicas distribuídas de ajuste fino.

Técnicas de ajuste fino distribuídas

Vários métodos de ajuste fino distribuído foram propostos para superar as restrições de memória da GPU para modelos grandes:

  1. Paralelismo de dados: a abordagem clássica de paralelismo de dados reproduction todo o modelo em várias GPUs enquanto divide e distribui os lotes de dados de treinamento. Isso reduz o tempo de treinamento linearmente com o número de GPUs, mas não reduz o pico de exigência de memória em cada GPU.
  2. ZeRO Estágio 3: uma forma avançada de paralelismo de dados que particiona os parâmetros do modelo, gradientes e estados do otimizador entre GPUs. Reduz a memória em comparação com o paralelismo de dados clássico, mantendo apenas os dados particionados necessários em cada GPU durante as diferentes fases de treinamento.
  3. Paralelismo tensorial: em vez de replicar o modelo, o paralelismo tensorial divide os parâmetros do modelo em linhas ou colunas e os distribui pelas GPUs. Cada GPU opera em um conjunto particionado de parâmetros, gradientes e estados de otimização, levando a economias substanciais de memória.
  4. Paralelismo de pipeline: esta técnica particiona as camadas do modelo em diferentes GPUs/employees, com cada dispositivo executando um subconjunto de camadas. As ativações são passadas entre trabalhadores, reduzindo o pico de memória, mas aumentando a sobrecarga de comunicação.

Estimar o uso de memória para esses métodos distribuídos não é trivial, pois a distribuição de parâmetros, gradientes, ativações e estados do otimizador varia entre as técnicas. Além disso, diferentes componentes, como o corpo do transformador e o cabeçote de modelagem da linguagem, podem apresentar diferentes comportamentos de alocação de memória.

A solução LLMem

Os pesquisadores propuseram recentemente o LLMem, uma solução que estima com precisão o consumo de memória da GPU ao aplicar métodos de ajuste fino distribuídos a LLMs em várias GPUs.

Estimando o uso de memória GPU para LLM pré-treinado de ajuste fino

O LLMem considera fatores como recombinação de parâmetros antes da computação (ZeRO Estágio 3), coleta de saída na passagem para trás (paralelismo de tensor) e as diferentes estratégias de alocação de memória para o corpo do transformador e cabeçote de modelagem de linguagem.

Resultados experimentais mostram que o LLMem pode estimar o pico de uso de memória da GPU para ajuste fino de LLMs em uma única GPU com taxas de erro de até 1,6%, superando a taxa de erro média do DNNMem de última geração de 42,6%. Ao aplicar métodos de ajuste fino distribuídos a LLMs com mais de um bilhão de parâmetros em múltiplas GPUs, o LLMem atinge uma impressionante taxa de erro média de 3,0%.

Ao estimar com precisão os requisitos de memória antecipadamente, o LLMem pode ajudar os usuários a selecionar o método de ajuste fino distribuído mais eficiente que evita problemas de falta de memória e minimiza o tempo de treinamento.

Técnicas Emergentes

Embora a quantização, o paralelismo de tensores e o paralelismo de modelos sejam técnicas estabelecidas, os pesquisadores continuam a explorar novos métodos para ampliar os limites do treinamento e implantação eficientes de LLM.

  1. LoRA e QLoRA: Essas técnicas envolvem o treinamento de um módulo adaptador residual menor para atualizar o LLM pré-treinado com novos conhecimentos, em vez de ajustar diretamente o grande número de parâmetros. Isso pode levar a economias substanciais de memória, mantendo a maior parte do desempenho do modelo.
  2. FlashAtenção: O mecanismo de autoatenção é um gargalo de memória e computação em modelos de transformadores. FlashAttention aproxima a atenção padrão com complexidade linear, reduzindo os requisitos de memória de quadrático para linear no comprimento da sequência de entrada.
  3. Mistura de especialistas: essa abordagem roteia condicionalmente cada amostra de dados de entrada para um modelo especialista especializado, em vez de processá-la por todo o modelo. Essa dispersão dinâmica pode economizar memória ao ativar apenas um subconjunto de especialistas para cada amostra.
  4. Cirurgia de modelo invertido: Os pesquisadores exploraram a compressão do modelo cirúrgico removendo iterativamente componentes menos importantes, como cabeças de atenção, para trocar memória/velocidade por precisão.
  5. Descarregando: finalmente, técnicas que descarregam parâmetros, estados do otimizador ou ativações para CPU RAM ou disco podem complementar a memória limitada da GPU para modelos grandes.

Esses métodos de ponta ilustram o vibrante ecossistema de pesquisa focado na democratização do treinamento e implantação eficiente de LLM em diversos ambientes de {hardware}.

Conclusão

Os requisitos de memória de grandes modelos de linguagem representam desafios significativos para a sua ampla adoção em aplicações do mundo actual. Ao compreender as técnicas de estimativa de memória e aproveitar a quantização, as estratégias de treinamento distribuído e as inovações emergentes, podemos otimizar as implantações de LLM em dispositivos com recursos limitados.

Ferramentas como o LLMem abrem caminho para uma estimativa precisa da memória, permitindo que os usuários selecionem a configuração de ajuste fino mais adequada. À medida que o {hardware} evolui e a pesquisa avança, podemos antecipar treinamento e inferência LLM mais eficientes, impulsionando o progresso no processamento de linguagem pure e na inteligência synthetic.

Encontrar o equilíbrio certo entre capacidade do modelo, precisão e utilização de recursos será essential para desbloquear todo o potencial de grandes modelos de linguagem em diversos domínios e casos de uso. Ao adotar técnicas de otimização de memória, aproximamo-nos de um futuro onde a IA de linguagem de última geração seja acessível, escalável e sustentável.

join the future newsletter Unite AI Mobile Newsletter 1

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button