Modelos e plataformas de IA

O Guia Completo para Ajustar Llama 3 ou Qualquer Outro Modelo de Código Aberto

mm
Adicione Unite.AI às suas fontes preferidas no Google

Ajustar modelos de linguagem grandes (LLMs) como Llama 3 envolve adaptar um modelo pré-treinado a tarefas específicas usando um conjunto de dados específico do domínio. Esse processo aproveita o conhecimento pré-existente do modelo, tornando-o eficiente e econômico em comparação com o treinamento do zero. Neste guia, vamos percorrer os passos para ajustar Llama 3 usando QLoRA (Quantized LoRA), um método eficiente em parâmetros que minimiza o uso de memória e custos computacionais.

Visão Geral do Ajuste

Ajuste envolve várias etapas importantes:

  1. Seleção de um Modelo Pré-Treinado: Escolha um modelo base que se alinhe com a arquitetura desejada.
  2. Coleta de um Conjunto de Dados Relevantes: Coletar e pré-processar um conjunto de dados específico para a tarefa.
  3. Ajuste: Adaptar o modelo usando o conjunto de dados para melhorar seu desempenho em tarefas específicas.
  4. Avaliação: Avaliar o modelo ajustado usando métricas qualitativas e quantitativas.

Conceitos e Técnicas

Ajuste de Modelos de Linguagem de Grande Escala

Ajuste de Modelos de Linguagem de Grande Escala

Ajuste Completo

Ajuste completo atualiza todos os parâmetros do modelo, tornando-o específico para a nova tarefa. Esse método requer recursos computacionais significativos e é frequentemente impraticável para modelos muito grandes.

Ajuste Eficiente em Parâmetros (PEFT)

PEFT atualiza apenas um subconjunto dos parâmetros do modelo, reduzindo os requisitos de memória e custo computacional. Essa técnica evita a perda catastrófica de conhecimento e mantém o conhecimento geral do modelo.

Adaptação de Baixo Nível (LoRA) e Quantized LoRA (QLoRA)

LoRA ajusta apenas algumas matrizes de baixo nível, enquanto QLoRA quantiza essas matrizes para reduzir ainda mais a pegada de memória.

Métodos de Ajuste

  1. Ajuste Completo: Isso envolve treinar todos os parâmetros do modelo no conjunto de dados específico da tarefa. Embora esse método possa ser muito eficaz, também é computacionalmente caro e requer significativa memória.
  2. Ajuste Eficiente em Parâmetros (PEFT): PEFT atualiza apenas um subconjunto dos parâmetros do modelo, tornando-o mais eficiente em termos de memória. Técnicas como LoRA e QLoRA se enquadram nessa categoria.

O que é LoRA?

Comparando métodos de ajuste: QLORA melhora LoRA com quantização de precisão de 4 bits e otimizador de páginas para gerenciamento de picos de memória

Comparando métodos de ajuste: QLORA melhora LoRA com quantização de precisão de 4 bits e otimizador de páginas para gerenciamento de picos de memória

LoRA é um método de ajuste aprimorado onde, em vez de ajustar todos os pesos do modelo pré-treinado, duas matrizes menores que aproximam a matriz maior são ajustadas. Essas matrizes constituem o adaptador LoRA. Esse adaptador ajustado é então carregado no modelo pré-treinado e usado para inferência.

Principais Vantagens de LoRA:

  • Eficiência de Memória: LoRA reduz a pegada de memória ajustando apenas matrizes pequenas em vez de todo o modelo.
  • Reutilização: O modelo original permanece inalterado, e vários adaptadores LoRA podem ser usados com ele, facilitando o manejo de várias tarefas com requisitos de memória mais baixos.

O que é Quantized LoRA (QLoRA)?

QLoRA leva LoRA um passo adiante, quantizando os pesos do adaptador LoRA para uma precisão mais baixa (por exemplo, 4 bits em vez de 8 bits). Isso reduz ainda mais o uso de memória e os requisitos de armazenamento, mantendo um nível comparável de eficácia.

Principais Vantagens de QLoRA:

  • Eficiência de Memória Ainda Maior: Ao quantizar os pesos, QLoRA reduz significativamente os requisitos de memória e armazenamento do modelo.
  • Mantenha o Desempenho: Apesar da precisão reduzida, QLoRA mantém níveis de desempenho próximos aos de modelos de precisão total.

Adaptação Específica de Tarefa

Durante o ajuste, os parâmetros do modelo são ajustados com base no novo conjunto de dados, ajudando-o a entender e gerar conteúdo relevante para a tarefa específica. Esse processo retém o conhecimento linguístico geral adquirido durante o pré-treinamento, enquanto adapta o modelo às nuances do domínio alvo.

Ajuste na Prática

Ajuste Completo vs. PEFT

  • Ajuste Completo: Envolve treinar o modelo inteiro, o que pode ser computacionalmente caro e requer significativa memória.
  • PEFT (LoRA e QLoRA): Ajusta apenas um subconjunto de parâmetros, reduzindo os requisitos de memória e prevenindo a perda catastrófica de conhecimento, tornando-se uma alternativa mais eficiente.

Etapa de Implementação

  1. Configuração do Ambiente: Instalar bibliotecas necessárias e configurar o ambiente de computação.
  2. Carregar e Pré-processar o Conjunto de Dados: Carregar o conjunto de dados e pré-processá-lo em um formato adequado para o modelo.
  3. Carregar o Modelo Pré-Treinado: Carregar o modelo base com configurações de quantização se estiver usando QLoRA.
  4. Tokenização: Tokenizar o conjunto de dados para prepará-lo para o treinamento.
  5. Treinamento: Ajustar o modelo usando o conjunto de dados preparado.
  6. Avaliação: Avaliar o desempenho do modelo em tarefas específicas usando métricas qualitativas e quantitativas.

Guia Passo a Passo para Ajustar LLM

Configurando o Ambiente

Vamos usar um caderno Jupyter para este tutorial. Plataformas como Kaggle, que oferecem uso gratuito de GPU, ou Google Colab são ideais para executar esses experimentos.

1. Instalar Bibliotecas Necessárias

Primeiro, certifique-se de que as bibliotecas necessárias estão instaladas:

!pip install -qqq -U bitsandbytes transformers peft accelerate datasets scipy einops evaluate trl rouge_score

2. Importar Bibliotecas e Configurar o Ambiente


<p>import os
import torch
from datasets import load_dataset
from transformers import (
AutoModelForCausalLM, AutoTokenizer, BitsAndBytesConfig, TrainingArguments,
pipeline, HfArgumentParser
)
from trl import ORPOConfig, ORPOTrainer, setup_chat_format, SFTTrainer
from tqdm import tqdm
import gc
import pandas as pd
import numpy as np
from huggingface_hub import interpreter_login</p>

<p># Desabilitar logging do Weights and Biases
os.environ['WANDB_DISABLED'] = "true"
interpreter_login()</p>

3. Carregar o Conjunto de Dados

Vamos usar o conjunto de dados DialogSum para este tutorial:

Pré-processar o conjunto de dados de acordo com os requisitos do modelo, incluindo a aplicação de modelos apropriados e garantindo que o formato de dados seja adequado para o ajuste​ (Hugging Face)​​ (DataCamp)​.


<p>dataset_name = "neil-code/dialogsum-test"
dataset = load_dataset(dataset_name)</p>

Inspecione a estrutura do conjunto de dados:


print(dataset['test'][0])

4. Criar Configuração BitsAndBytes

Para carregar o modelo em formato de 4 bits:


<p>compute_dtype = getattr(torch, "float16")
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type='nf4',
bnb_4bit_compute_dtype=compute_dtype,
bnb_4bit_use_double_quant=False,
)</p>

5. Carregar o Modelo Pré-Treinado

Usando o modelo Phi-2 da Microsoft (MSFT ) para este tutorial:


<p>model_name = 'microsoft/phi-2'
device_map = {"": 0}
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)</p>

6. Tokenização

Configurar o tokenizador:


<p>tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True,
padding_side="left",
add_eos_token=True,
add_bos_token=True,
use_fast=False
)
tokenizer.pad_token = tokenizer.eos_token</p>

Ajuste de Llama 3 ou Outros Modelos

Ao ajustar modelos como Llama 3 ou outros modelos de código aberto de ponta, há considerações e ajustes específicos necessários para garantir o desempenho ótimo. Aqui estão as etapas detalhadas e insights sobre como abordar isso para diferentes modelos, incluindo Llama 3, GPT-3 e Mistral.

5.1 Usando Llama 3

Seleção do Modelo:

  • Certifique-se de ter o identificador de modelo correto do hub de modelos do Hugging Face. Por exemplo, o modelo Llama 3 pode ser identificado como meta-llama/Meta-Llama-3-8B no Hugging Face.
  • Certifique-se de solicitar acesso e fazer login na sua conta do Hugging Face se necessário para modelos como Llama 3​ (Hugging Face)​​

Tokenização:

  • Use o tokenizador apropriado para Llama 3, garantindo que seja compatível com o modelo e suporte recursos necessários como padding e tokens especiais.

Memória e Computação:

  • Ajustar modelos grandes como Llama 3 requer recursos computacionais significativos. Certifique-se de que o ambiente, como uma configuração de GPU poderosa, possa lidar com os requisitos de memória e processamento. Certifique-se de que o ambiente possa lidar com os requisitos de memória, que podem ser mitigados usando técnicas como QLoRA para reduzir a pegada de memória​ (Hugging Face Forums)

Exemplo:

model_name = 'meta-llama/Meta-Llama-3-8B'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)

Tokenização:

Dependendo do caso de uso específico e dos requisitos do modelo, certifique-se de que a configuração do tokenizador esteja correta sem configurações redundantes. Por exemplo, use_fast=True é recomendado para melhor desempenho​ (Hugging Face)​​ (Weights & Biases)​.

tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True,
padding_side="left",
add_eos_token=True,
add_bos_token=True,
use_fast=False
)
tokenizer.pad_token = tokenizer.eos_token

5.2 Usando Outros Modelos Populares (por exemplo, GPT-3, Mistral)

Seleção do Modelo:

  • Para modelos como GPT-3 e Mistral, certifique-se de usar o nome e identificador de modelo corretos do hub de modelos do Hugging Face ou outras fontes.

Tokenização:

  • Similar a Llama 3, certifique-se de que o tokenizador esteja configurado corretamente e seja compatível com o modelo.

Memória e Computação:

  • Cada modelo pode ter requisitos de memória diferentes. Ajuste a configuração do ambiente de acordo.

Exemplo para GPT-3:

model_name = 'openai/gpt-3'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)

Exemplo para Mistral:

model_name = 'mistral-7B'
device_map = {"": 0}
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.float16,
bnb_4bit_use_double_quant=True,
)
original_model = AutoModelForCausalLM.from_pretrained(
model_name,
device_map=device_map,
quantization_config=bnb_config,
trust_remote_code=True,
use_auth_token=True
)

Considerações de Tokenização: Cada modelo pode ter requisitos de tokenização únicos. Certifique-se de que o tokenizador corresponda ao modelo e esteja configurado corretamente.

Exemplo de Tokenizador para Llama 3:

tokenizer = AutoTokenizer.from_pretrained(
model_name,
trust_remote_code=True,
padding_side="left",
add_eos_token=True,
add_bos_token=True,
use_fast=False
)
tokenizer.pad_token = tokenizer.eos_token

Exemplo de Tokenizador para GPT-3 e Mistral:

tokenizer = AutoTokenizer.from_pretrained(
model_name,
use_fast=True
)

7. Testar o Modelo com Inferência Zero-Shot

Avalie o modelo base com uma entrada de amostra:

from transformers import set_seed

<p>set_seed(42)
index = 10
prompt = dataset['test'][index]['dialogue']
formatted_prompt = f"Instrução: Resumir a seguinte conversa.\n{prompt}\nSaída:\n"</p>

<p># Gerar saída
def gen(model, prompt, max_length):
inputs = tokenizer(prompt, return_tensors="pt").to(model.device)
outputs = model.generate(**inputs, max_length=max_length)
return tokenizer.batch_decode(outputs, skip_special_tokens=True)</p>

<p>res = gen(original_model, formatted_prompt, 100)
output = res[0].split('Saída:\n')[1]</p>

<p>print(f'ENTRADA DE PROMPT:\n{formatted_prompt}')
print(f'GERAÇÃO DO MODELO - ZERO SHOT:\n{output}')

8. Pré-processar o Conjunto de Dados

Converter pares de diálogo-resumo em prompts:


<p>def create_prompt_formats(sample):
blurb = "Abaixo está uma instrução que descreve uma tarefa. Escreva uma resposta que apropriadamente complete o pedido."
instruction = "### Instrução: Resumir a conversa abaixo."
input_context = sample['dialogue']
response = f"### Saída:\n{sample['summary']}"
end = "### Fim"</p>

<p>parts = [blurb, instruction, input_context, response, end]
formatted_prompt = "\n\n".join(parts)
sample["text"] = formatted_prompt
return sample</p>

<p>dataset = dataset.map(create_prompt_formats)</p>

Tokenizar o conjunto de dados formatado:


<p>def preprocess_batch(batch, tokenizer, max_length):
return tokenizer(batch["text"], max_length=max_length, truncation=True)</p>

<p>max_length = 1024
train_dataset = dataset["train"].map(lambda batch: preprocess_batch(batch, tokenizer, max_length), batched=True)
eval_dataset = dataset["validation"].map(lambda batch: preprocess_batch(batch, tokenizer, max_length), batched=True)</p>

9. Preparar o Modelo para QLoRA

Preparar o modelo para ajuste eficiente em parâmetros:


<p>original_model = prepare_model_for_kbit_training(original_model)</p>

Parâmetros e Seu Impacto

Parâmetros de treinamento desempenham um papel crucial na otimização do desempenho do modelo. Aqui estão alguns parâmetros-chave a considerar:

  1. Taxa de Aprendizado: Controla a velocidade com que o modelo atualiza seus parâmetros. Uma taxa de aprendizado alta pode levar a uma convergência mais rápida, mas pode ultrapassar a solução ótima. Uma taxa de aprendizado baixa garante uma convergência estável, mas pode exigir mais épocas.
  2. Tamanho do Lote: O número de amostras processadas antes que o modelo atualize seus parâmetros. Tamanhos de lote maiores podem melhorar a estabilidade, mas exigem mais memória. Tamanhos de lote menores podem levar a mais ruído no processo de treinamento.
  3. Passos de Acumulação de Gradientes: Esse parâmetro ajuda a simular tamanhos de lote maiores, acumulando gradientes ao longo de várias etapas antes de realizar uma atualização de parâmetro.
  4. Número de Épocas: O número de vezes que o conjunto de dados inteiro é passado pelo modelo. Mais épocas podem melhorar o desempenho, mas podem levar a um ajuste excessivo se não for gerenciado adequadamente.
  5. Decaimento de Peso: Técnica de regularização para prevenir o ajuste excessivo, penalizando pesos grandes.
  6. Agendador de Taxa de Aprendizado: Ajusta a taxa de aprendizado durante o treinamento para melhorar o desempenho e a convergência.

Personalize a configuração de treinamento ajustando parâmetros como taxa de aprendizado, tamanho do lote e passos de acumulação de gradientes com base nos requisitos específicos do modelo e da tarefa. Por exemplo, modelos Llama 3 podem exigir taxas de aprendizado diferentes em comparação com modelos menores​ (Weights & Biases)​​ (GitHub)

Exemplo de Configuração de Treinamento

orpo_args = ORPOConfig(
learning_rate=8e-6,
lr_scheduler_type="linear",max_length=1024,max_prompt_length=512,
beta=0.1,per_device_train_batch_size=2,per_device_eval_batch_size=2,
gradient_accumulation_steps=4,optim="paged_adamw_8bit",num_train_epochs=1,
evaluation_strategy="steps",eval_steps=0.2,logging_steps=1,warmup_steps=10,
report_to="wandb",output_dir="./results/",)

10. Treinar o Modelo

Configure o treinador e inicie o treinamento:

trainer = ORPOTrainer(
model=original_model,
args=orpo_args,
train_dataset=train_dataset,
eval_dataset=eval_dataset,
tokenizer=tokenizer,)
trainer.train()
trainer.save_model("fine-tuned-llama-3")

Avaliando o Modelo Ajustado

Após o treinamento, avalie o desempenho do modelo usando métodos qualitativos e quantitativos.

1. Avaliação Humana

Compare as resumos gerados com os escritos por humanos para avaliar a qualidade.

2. Avaliação Quantitativa

Use métricas como ROUGE para avaliar o desempenho:


from rouge_score import rouge_scorer

<p>scorer = rouge_scorer.RougeScorer(['rouge1', 'rouge2', 'rougeL'], use_stemmer=True)
scores = scorer.score(reference_summary, generated_summary)
print(scores)</p>

Desafios Comuns e Soluções

1. Limitações de Memória

Usar QLoRA ajuda a mitigar problemas de memória, quantizando os pesos do modelo para 4 bits. Certifique-se de ter memória de GPU suficiente para lidar com o tamanho do lote e o tamanho do modelo.

2. Ajuste Excessivo

Monitore as métricas de validação para prevenir o ajuste excessivo. Use técnicas como parada antecipada e decaimento de peso.

3. Treinamento Lento

Otimizar a velocidade de treinamento ajustando o tamanho do lote, a taxa de aprendizado e usando a acumulação de gradientes.

4. Qualidade dos Dados

Certifique-se de que o conjunto de dados seja limpo e bem pré-processado. A qualidade ruim dos dados pode impactar significativamente o desempenho do modelo.

Conclusão

Ajustar modelos de linguagem grandes usando QLoRA é uma maneira eficiente de adaptar modelos pré-treinados grandes a tarefas específicas com custos computacionais reduzidos. Seguindo este guia, você pode ajustar PHI, Llama 3 ou qualquer outro modelo de código aberto para alcançar alto desempenho em suas tarefas específicas.

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.