PUBLICIDADE

Fine-tuning de LLMs com LoRA e QLoRA: guia atualizado com TRL, PEFT e Unsloth

06/10/2026
14 visualizações
10 min de leitura
Aprenda a ajustar um LLM com LoRA e QLoRA usando as versões atuais de Transformers 5, PEFT, TRL 1.x e bitsandbytes: dataset, código completo, hiperparâmetros, como evitar erro de memória e como fundir o adaptador.
Imagem principal do post

Fine-tuning supervisionado (SFT) é a forma mais direta de ensinar um modelo de linguagem a seguir o seu formato, o seu tom ou o vocabulário do seu domínio. O problema é que ajustar todos os pesos de um LLM exige uma quantidade de memória fora do alcance da maioria. A saída prática é combinar três ideias: PEFT, LoRA e QLoRA. Este guia explica como elas funcionam e mostra o passo a passo com as versões atuais das ferramentas (conferidas em 06/10/2026), incluindo o que mudou no ecossistema Hugging Face e os erros mais comuns.

Resumo em vídeo

Prefere assistir antes de ler? O vídeo abaixo, produzido com o NotebookLM, apresenta o tema em cerca de 7 minutos, do problema de hardware até o uso do modelo final. O guia escrito, logo depois, traz as versões e os comandos atualizados em outubro de 2026.

Quando vale a pena fazer fine-tuning

Antes de treinar, vale se perguntar se o problema não se resolve com um bom prompt ou com RAG (consulta a documentos). Fine-tuning compensa quando você precisa de um comportamento consistente: respostas num formato fixo, um estilo de atendimento, classificação ou extração em um domínio específico, ou um modelo pequeno que imite bem uma tarefa. Para "ensinar fatos novos" que mudam toda semana, RAG costuma ser mais barato e fácil de atualizar.

Full fine-tuning, LoRA e QLoRA

PUBLICIDADE
  • Full fine-tuning: atualiza todos os pesos do modelo. É preciso guardar gradientes e estados do otimizador para bilhões de parâmetros. O artigo do QLoRA cita que ajustar um LLaMA de 65B em 16 bits exige mais de 780 GB de memória de GPU.
  • LoRA (Low-Rank Adaptation): congela os pesos originais e treina apenas pequenas matrizes de baixo posto (A e B) acopladas às camadas lineares. O número de parâmetros treináveis costuma ficar bem abaixo de 1% do total. O método vem do artigo original do LoRA.
  • QLoRA: LoRA sobre um modelo base quantizado em 4 bits, proposto por Dettmers e colegas. Com isso, um modelo de 65B passa a caber em uma única GPU de 48 GB, e modelos na faixa de 7B a 8B treinam em GPUs de consumo.
Imagem complementar

As três inovações do QLoRA

  1. NF4 (4-bit NormalFloat): tipo de dado de 4 bits pensado para pesos com distribuição aproximadamente normal.
  2. Double Quantization: quantiza também as constantes de quantização, economizando cerca de 0,37 bit por parâmetro (perto de 3 GB em um modelo de 65B).
  3. Paged Optimizers: usam memória unificada da NVIDIA para jogar os picos de memória do otimizador para a RAM da CPU quando a VRAM aperta.

Versões atuais das ferramentas (06/10/2026)

O ecossistema mudou bastante em pouco tempo: Transformers e Datasets estão na série 5.x, e o TRL já passou para a 1.x. Versões conferidas direto no PyPI:

PacoteVersãoLançamentoPara que serve
transformers5.18.030/09/2026carregar modelos e tokenizers
peft0.21.201/10/2026adaptadores LoRA/QLoRA
trl1.14.129/09/2026SFTTrainer e outros métodos de pós-treino
bitsandbytes0.50.227/08/2026quantização 4 e 8 bits, otimizadores paged
datasets5.1.005/10/2026leitura e preparo dos dados
accelerate1.15.009/09/2026execução distribuída
liger-kernel0.8.430/09/2026kernels que reduzem memória (opcional)
unsloth2026.9.1401/10/2026treino mais rápido e com menos VRAM (opcional)
vllm0.31.005/10/2026servir o modelo depois do treino

Quase tudo exige Python 3.10 ou superior. Se você tem tutoriais antigos em mente, duas mudanças valem atenção: no Transformers 5 o argumento torch_dtype virou dtype, e no TRL o SFTTrainer aceita o nome do modelo como texto e recebe peft_config e quantization_config diretamente.

Escolhendo o modelo base

O SFTTrainer do TRL trabalha com modelos de linguagem causais (decoder-only). Modelos encoder-decoder, como o FLAN-T5, não entram nessa receita. Algumas opções atuais, com o que foi verificado no Hugging Face:

ModeloID no Hugging FaceObservação
Qwen3 8BQwen/Qwen3-8Btexto, Apache 2.0, sem aprovação prévia; ótimo ponto de partida
Qwen3.5 4B / 9BQwen/Qwen3.5-4B, Qwen/Qwen3.5-9Bgeração mais nova, Apache 2.0; arquitetura multimodal, exige mais cuidado no treino
Gemma 4 E4Bgoogle/gemma-4-E4B-itApache 2.0, multimodal
Phi-4 minimicrosoft/Phi-4-mini-instructsucessor do Phi-3 mini, bom para hardware limitado
Granite 4.0 microibm-granite/granite-4.0-micromodelo pequeno da IBM, bom para testes rápidos
Llama 3.1 8B / 3.2 3Bmeta-llama/Llama-3.1-8B-Instructexige aceitar a licença da Meta e logar com token do Hugging Face
Mistral 7B Instruct v0.3mistralai/Mistral-7B-Instruct-v0.3versão atual da linha 7B

Neste tutorial usamos o Qwen/Qwen3-8B: é texto puro, tem licença permissiva, não exige aprovação e o TRL já sabe ajustar o template de chat dele para treinar só nas respostas do assistente.

Preparando o dataset

A qualidade dos exemplos pesa bem mais que a quantidade. O trabalho LIMA mostrou que cerca de mil exemplos muito bem curados já mudam muito o comportamento de um modelo. Comece pequeno, avalie e só então aumente.

O formato mais prático é JSONL (um JSON por linha), que dá para ler em streaming. O TRL aceita conversas no formato de mensagens e aplica sozinho o template de chat do modelo:

{"messages": [
  {"role": "system", "content": "Você é o assistente da loja X. Responda em português, de forma curta."},
  {"role": "user", "content": "Vocês entregam em Maracanaú?"},
  {"role": "assistant", "content": "Entregamos sim! O frete por motoboy varia conforme o bairro."}
]}

O TRL também aceita o formato prompt-completion (campos prompt e completion), em que a perda é calculada só na resposta. Com o formato de mensagens, ligue assistant_only_loss=True para o mesmo efeito. Cada linha do arquivo vai em uma única linha real; as quebras acima são só para leitura.

Passo 1: instalar as bibliotecas

pip install -U transformers peft trl bitsandbytes datasets accelerate

Precisa de uma GPU NVIDIA com CUDA, porque o bitsandbytes faz a quantização de 4 bits nela. No Colab, a GPU gratuita (T4, 16 GB) já serve para modelos de 4B a 8B.

Passo 2: treinar com QLoRA usando o SFTTrainer

No TRL atual não é preciso montar o modelo à mão: o SFTTrainer carrega o modelo a partir do nome, aplica a quantização e envolve o adaptador LoRA. Um único bloco de código faz tudo:

import torch
from datasets import load_dataset
from peft import LoraConfig
from transformers import BitsAndBytesConfig
from trl import SFTConfig, SFTTrainer

MODELO = "Qwen/Qwen3-8B"

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",             # tipo NF4
    bnb_4bit_use_double_quant=True,        # quantização dupla
    bnb_4bit_compute_dtype=torch.bfloat16, # use float16 na GPU T4
)

peft_config = LoraConfig(
    r=16,
    lora_alpha=32,
    lora_dropout=0.05,
    target_modules="all-linear",           # LoRA em todas as camadas lineares
    task_type="CAUSAL_LM",
)

dataset = load_dataset("json", data_files="dataset.jsonl", split="train")

args = SFTConfig(
    output_dir="./qwen3-lora",
    per_device_train_batch_size=1,
    gradient_accumulation_steps=8,         # batch efetivo de 8
    learning_rate=1e-4,
    num_train_epochs=2,
    max_length=1024,
    optim="paged_adamw_8bit",
    gradient_checkpointing=True,
    assistant_only_loss=True,              # treina só nas respostas do assistente
    bf16=True,                             # na T4: bf16=False, fp16=True
    model_init_kwargs={"dtype": torch.bfloat16},
    logging_steps=10,
    save_strategy="epoch",
)

trainer = SFTTrainer(
    model=MODELO,
    args=args,
    train_dataset=dataset,
    peft_config=peft_config,
    quantization_config=bnb_config,
)
trainer.train()
trainer.save_model("./qwen3-lora")

Pontos de atenção neste código

  • Não faça os dois: use get_peft_model à mão ou passe peft_config ao trainer. Se você já embrulhou o modelo, passe o modelo pronto ao SFTTrainer sem o peft_config; fazer os dois embrulha o adaptador duas vezes.
  • Tipo numérico: a T4 não suporta bfloat16. Nela use bnb_4bit_compute_dtype=torch.float16, fp16=True, bf16=False e dtype float16 em model_init_kwargs. Em placas Ampere ou mais novas (RTX 30/40/50, A100, L4), prefira bfloat16.
  • Dtype do modelo: quando o modelo é passado como texto, o TRL carrega em float32 se você não indicar dtype. Por isso o model_init_kwargs acima, para não gastar memória à toa.
  • Treinar só na resposta: assistant_only_loss=True exige que o template de chat marque as respostas do assistente. Para famílias conhecidas, como o Qwen3, o TRL ajusta o template sozinho; em outros modelos, confira.
  • Padrões do SFTConfig: a taxa de aprendizado padrão é 2e-5, pensada para treino completo. Para adaptadores, a documentação sugere algo perto de 1e-4.

Hiperparâmetros que funcionam como ponto de partida

ParâmetroValor inicialO que faz
r (rank)8, 16, 32 ou 64tamanho do adaptador. Se o LoRA cobre todas as camadas, o rank tem impacto pequeno no resultado
lora_alphaproporcional ao rank (ex.: 2×r)escala a magnitude das atualizações
target_modules"all-linear"aplica LoRA em todas as camadas lineares, sem depender do nome delas em cada arquitetura. É o ajuste mais importante para aproximar o resultado do treino em 16 bits
learning_rate1e-4 a 2e-4o artigo do QLoRA usou 2e-4 em modelos até 13B e 1e-4 nos de 33B e 65B
batch por GPU / acumulação1 / 4 a 16simula um batch maior sem estourar a VRAM
max_length512 a 1024 (o padrão do TRL é 1024)a memória cresce rápido com sequências longas
optimpaged_adamw_8bitotimizador paged de 8 bits
épocas1 a 3mais épocas em dataset pequeno tende a decorar em vez de generalizar

Como evitar o erro CUDA Out of Memory

  1. Batch 1 com acumulação: reduza per_device_train_batch_size para 1 e compense em gradient_accumulation_steps.
  2. Gradient checkpointing: descarta ativações e recalcula no backward. No SFTConfig ele já vem ligado por padrão.
  3. Reduza o max_length: é a alavanca mais eficaz. Veja a distribuição de tamanhos do seu dataset e corte no necessário.
  4. Otimizador paged: paged_adamw_8bit move o estado do otimizador para a RAM nos picos.
  5. Offload de ativações: activation_offloading=True manda ativações para a RAM da CPU, com um custo de tempo.
  6. Packing e padding-free: packing=True junta exemplos curtos na mesma linha e reduz o desperdício com padding; ambos funcionam melhor com FlashAttention.
  7. Liger Kernel: use_liger_kernel=True (com o pacote liger-kernel instalado) reduz o pico de memória.
  8. Modelo ou rank menor: se nada resolver, troque para um modelo de 4B ou diminua o r.

Uma nota: o TRL usa por padrão a perda chunked_nll, que economiza memória, mas ela não é compatível com PEFT nem com Liger. Em QLoRA, portanto, você não aproveita esse ganho.

Atalho: Unsloth

O Unsloth reescreve partes do treino com kernels otimizados e é compatível com o fluxo do TRL. A documentação do TRL fala em treino até 2 vezes mais rápido e com até 70% menos VRAM, e o projeto lista suporte a Llama, Mistral, Gemma, Qwen e Phi. Os números variam conforme modelo, GPU e max_length, então meça no seu caso. É uma boa opção se você quer treinar no Colab ou em uma placa com pouca memória.

Depois do treino: salvar, fundir e servir

Salvar só o adaptador

O trainer.save_model() grava apenas o adaptador, que fica na casa de dezenas a poucas centenas de megabytes (depende do rank e das camadas), contra vários gigabytes do modelo completo. Para usar, carregue o modelo base e o adaptador juntos.

Fundir o adaptador ao modelo (merge)

Para simplificar o deploy, dá para fundir o adaptador nos pesos. O detalhe: não funda sobre o modelo de 4 bits. Recarregue a base em bfloat16 (ou float16) e funda:

import torch
from peft import AutoPeftModelForCausalLM
from transformers import AutoTokenizer

modelo = AutoPeftModelForCausalLM.from_pretrained(
    "./qwen3-lora", dtype=torch.bfloat16, device_map="cpu"
)
fundido = modelo.merge_and_unload()
fundido.save_pretrained("./qwen3-fundido")
AutoTokenizer.from_pretrained("Qwen/Qwen3-8B").save_pretrained("./qwen3-fundido")

Rodar o merge em CPU evita ocupar a VRAM e é suficiente para modelos desse porte, mas demora mais e pede RAM suficiente para o modelo em 16 bits.

Servir o modelo

Com o modelo fundido, o vLLM serve a pasta com uma API compatível com a da OpenAI. O vLLM também consegue carregar adaptadores LoRA sem fundir. Para uso local mais simples, o Ollama importa modelos por Modelfile, desde que a arquitetura seja suportada por ele.

Checklist rápido

  • Definiu o objetivo e testou antes com prompt ou RAG?
  • Dataset limpo, em JSONL, com um conjunto separado para avaliação?
  • Modelo causal (decoder-only) com licença adequada ao seu uso?
  • Tipo numérico certo para a sua GPU (bf16 em Ampere+, fp16 na T4)?
  • target_modules="all-linear" e paged_adamw_8bit ligados?
  • Comparou as respostas do modelo ajustado com as do original no conjunto de avaliação?

Se for gerar dados sintéticos com outro LLM, confira também os termos de uso do serviço que você usar para criar os exemplos, porque alguns restringem o uso das respostas para treinar outros modelos.

Fontes consultadas: documentação do SFTTrainer (TRL), guia de quantização do PEFT, economia de memória no TRL e o artigo do QLoRA.

PUBLICIDADE
Este post foi útil para você?
🛒
Vai rodar IA no seu computador?

Modelos locais dependem da placa de vídeo: quanto mais VRAM, maiores os modelos e mais rápidas as respostas. Compare os preços de placas RTX na Amazon.

Ver preços na Amazon →
Como associado da Amazon, o blog ganha com compras qualificadas, sem custo extra para você.

Leitura recomendada

💬 Comentários

Nenhum comentário ainda. Conte o que achou, tire uma dúvida ou discorde. Seja o primeiro!

Deixe seu comentário
O e-mail não aparece. Serve só para avisar quando responderem você.
Os comentários passam por aprovação antes de aparecer. Crie uma conta de leitor e, depois do primeiro aprovado, os próximos saem na hora.
Apoie o ConexãoTC

O ConexãoTC é independente e gratuito. Se as notícias fazem parte do seu dia, contribua com qualquer valor pelo PIX e ajude a manter o blog no ar.

QR code PIX para apoiar o ConexãoTC
Aponte a câmera do app do banco
Favorecido: Jean Dgardany C. Lima, editor do ConexãoTC
🗳️ O que você quer ler aqui?

Marque os assuntos que te interessam. Os mais pedidos viram os próximos artigos.

Leitores cadastrados têm as sugestões atendidas primeiro e recebem um aviso quando o artigo sai.
Fique por dentro

Os destaques do dia no seu e-mail, todo dia às 8h.

PUBLICIDADE