Guia Definitivo: Alinhamento de LLMs com DPO usando Unsloth

Enquanto o Supervised Fine-Tuning (SFT) ensina o modelo a como falar (formato, estilo e sintaxe), o alinhamento ensina o modelo a como pensar e o que preferir. Durante muito tempo, o RLHF (Reinforcement Learning from Human Feedback) foi o padrão da indústria, mas sua arquitetura complexa, exigindo múltiplos modelos rodando simultaneamente (Reward Model, Reference Model), o tornava instável e caro.

É aqui que entra o DPO (Direct Preference Optimization). O DPO elimina a necessidade de um modelo de recompensa separado, otimizando diretamente a política do modelo base usando uma perda estatística ajustada.

Neste guia, vamos estruturar um pipeline completo de DPO utilizando a biblioteca Unsloth (que acelera o treinamento em até 2x e reduz drasticamente o uso de VRAM) e a biblioteca TRL (Transformer Reinforcement Learning) da Hugging Face.


1. O Dataset de Preferências (Chosen vs. Rejected)

O coração do DPO é o dataset. Em vez de apenas fornecer a resposta certa, você fornece um prompt e duas saídas: uma que o modelo deve imitar (chosen) e outra que ele deve evitar (rejected).

Isso é especialmente crítico em domínios que exigem rigor técnico e raciocínio lógico. A diferença entre uma resposta aceita e rejeitada não é apenas sobre tom de voz, mas sobre a metodologia e o Chain of Thought (CoT) aplicado.

Estrutura do Dataset (Formato JSONL)

{
  "prompt": "Paciente do sexo masculino, 45 anos, relata dor no peito irradiando para o braço esquerdo há 30 minutos, acompanhada de sudorese fria. Qual a suspeita e conduta?",
  "chosen": "A apresentação clínica é altamente sugestiva de Síndrome Coronariana Aguda (SCA), possivelmente um Infarto Agudo do Miocárdio (IAM). A conduta imediata envolve acionamento do serviço de emergência, monitoramento de sinais vitais, administração de AAS (se não houver contraindicações) e realização de um ECG de 12 derivações em até 10 minutos após o primeiro contato médico para classificar o risco e guiar a terapia de reperfusão.",
  "rejected": "O paciente provavelmente está tendo um ataque cardíaco. Você deve dar aspirina imediatamente e fazer uma cirurgia de ponte de safena. Pode ser ansiedade também, então espere um pouco para ver se melhora."
}

Nota: No cenário acima, o chosen demonstra diretrizes estruturadas e seguras, enquanto o rejected pula etapas diagnósticas e fornece conclusões precipitadas. É essa "bússola moral e técnica" que o DPO ajusta.


2. Configurando o Ambiente com Unsloth

O Unsloth otimiza as operações matemáticas por trás do LoRA (Low-Rank Adaptation) e da atenção, permitindo rodar fine-tuning de modelos pesados (como Llama 3 ou Mistral) em GPUs de consumo.

Instalação das dependências

pip install "unsloth[colab-new] @ git+https://github.com/unslothai/unsloth.git"
pip install --no-deps trl peft accelerate bitsandbytes

Carregando o Modelo

import torch
from unsloth import FastLanguageModel
from datasets import load_dataset
from trl import DPOTrainer, DPOConfig

# Configurações do modelo
max_seq_length = 2048 
dtype = None # Auto detecção (Bfloat16 se suportado)
load_in_4bit = True # Essencial para economizar VRAM

# 1. Carregando o Modelo e Tokenizer via Unsloth
model, tokenizer = FastLanguageModel.from_pretrained(
    model_name = "mistralai/Mistral-7B-Instruct-v0.2",
    max_seq_length = max_seq_length,
    dtype = dtype,
    load_in_4bit = load_in_4bit,
)

# 2. Aplicando PEFT / LoRA
model = FastLanguageModel.get_peft_model(
    model,
    r = 16, # Rank do LoRA (capacidade de aprendizado)
    target_modules = ["q_proj", "k_proj", "v_proj", "o_proj",
                      "gate_proj", "up_proj", "down_proj"],
    lora_alpha = 16,
    lora_dropout = 0, # Unsloth exige dropout = 0 para otimização
    bias = "none",
    use_gradient_checkpointing = "unsloth", 
)

3. O Treinamento (DPOTrainer)

Com o modelo pronto, passamos para o DPOTrainer. O hiperparâmetro mais importante aqui é o beta. Ele atua como um regularizador KL, controlando o quanto o modelo pode desviar da sua política de referência original. Um beta típico varia entre 0.1 e 0.5.

# Carregar o dataset formatado (Hugging Face datasets)
dataset = load_dataset("seu_usuario/seu_dataset_dpo", split="train")

# Configurações do DPO
dpo_config = DPOConfig(
    beta = 0.1, # Fator de regularização KL
    per_device_train_batch_size = 2,
    gradient_accumulation_steps = 4,
    learning_rate = 5e-6, # Atenção: LR no DPO deve ser BEM menor que no SFT
    lr_scheduler_type = "cosine",
    max_steps = 200,
    optim = "adamw_8bit", # Otimizador em 8-bit para poupar memória
    output_dir = "outputs_dpo",
)

trainer = DPOTrainer(
    model = model,
    ref_model = None, # O Unsloth gerencia o ref_model automaticamente sob o capô
    tokenizer = tokenizer,
    train_dataset = dataset,
    args = dpo_config,
)

# Iniciar o treinamento
trainer.train()

4. Monitorando a Perda (Loss) e Evitando o Colapso

O treinamento DPO é mais sensível e propenso a over-fitting do que o SFT padrão. Se não for monitorado, o modelo pode sofrer de Reward Hacking (onde ele encontra uma brecha estatística para maximizar a recompensa sem melhorar a utilidade real).

Ao monitorar os logs no Weights & Biases (W&B) ou TensorBoard, observe estas três métricas cruciais:

  1. Margem de Recompensa (Reward Margin): A diferença entre a recompensa da resposta chosen e a rejected. Ela deve aumentar ao longo do tempo e depois estabilizar.
  2. Loss: A perda do DPO deve cair consistentemente. Se começar a subir ou oscilar violentamente, seu learning_rate está muito alto ou seu beta está muito baixo.
  3. Chosen vs Rejected Rewards: Ambas podem diminuir em valores absolutos, mas a linha da Rejected Reward deve cair muito mais rápido que a da Chosen.

5. Próximos Passos e Exportação

Após a conclusão do treinamento, você vai querer testar o modelo e possivelmente quantizá-lo para rodar localmente de forma eficiente (ex: via Ollama ou LM Studio). O Unsloth facilita a exportação direta para o formato GGUF.

# Salvar o modelo LoRA padrão
model.save_pretrained("modelo_dpo_lora")

# Exportar diretamente para GGUF (Quantização Q4_K_M - excelente custo-benefício de VRAM/Velocidade)
model.save_pretrained_gguf("modelo_dpo_gguf", tokenizer, quantization_method = "q4_k_m")

Para aprofundar seus estudos, construir datasets robustos e acompanhar as atualizações das bibliotecas usadas neste guia, confira os materiais abaixo:

Artigos e Documentação Oficial

  • Paper Original do DPO (arXiv): "Direct Preference Optimization: Your Language Model is Secretly a Reward Model" (Rafailov et al., 2023) - O artigo acadêmico fundamental que introduziu a técnica e a matemática por trás da eliminação do modelo de recompensa.
  • Documentação do TRL (Hugging Face): Guia oficial do DPOTrainer detalhando todos os hiperparâmetros disponíveis para ajuste fino.
  • Repositório Oficial do Unsloth: GitHub da biblioteca. Vale a pena acompanhar as releases, pois eles adicionam suporte otimizado para novos modelos de ponta constantemente.

Ferramentas e Datasets para Alinhamento

  • Argilla: Uma excelente plataforma open-source para curadoria de dados e criação de datasets de preferências humanas com interface gráfica.
  • UltraFeedback (Hugging Face): Um dos maiores e mais utilizados datasets open-source de preferências (Chosen/Rejected) para treinar modelos de alinhamento.

Inferência e Quantização (Rodando o Modelo Localmente)

  • llama.cpp: O motor principal (escrito em C/C++) para rodar os arquivos .gguf que exportamos no Passo 5, extraindo o máximo de performance da CPU e GPU.
  • Ollama e LM Studio: As melhores interfaces para carregar o seu modelo GGUF alinhado e conversar com ele na sua máquina local, garantindo total privacidade dos dados.

Subscribe to Kodjao Labs

Don’t miss out on the latest issues. Sign up now to get access to the library of members-only issues.
[email protected]
Inscreva-se