O Que e Fine-Tuning e Quando Usar?
Fine-tuning e o processo de continuar o treinamento de um modelo de linguagem pre-treinado usando um dataset especializado. Em vez de partir do zero, voce ajusta os pesos do modelo para que ele aprenda padroes, vocabulario, estilos de resposta e formatos especificos do seu dominio.
A analogia mais clara: e como contratar um generalista altamente qualificado e treinalo intensivamente nas especificidades da sua empresa. Ele ja sabe trabalhar -- voce so esta moldando esse conhecimento para o seu contexto.
Quando vale fazer fine-tuning:
- Voce quer um formato de saida extremamente consistente (JSON, codigo, templates)
- Seu dominio tem terminologia ou estilo muito especifico
- Voce executa a mesma tarefa milhoes de vezes e quer reduzir o tamanho dos prompts (= custo)
- Prompt engineering chegou ao limite de qualidade
- Voce precisa que o modelo foque num nicho especifico
Quando NAO vale:
- Voce quer que o modelo saiba fatos novos (use RAG)
- Voce tem menos de 50-100 exemplos de qualidade
- Voce precisa de resultados amanha (fine-tuning demora horas a dias)
- A tarefa funciona bem com um prompt bem feito
---
Fine-Tuning vs RAG vs Prompt Engineering
Estas tres tecnicas parecem competidoras, mas sao complementares. A escolha depende do problema.
| Criterio | Prompt Engineering | RAG | Fine-Tuning |
|---|---|---|---|
| Implementacao | Minutos | Horas/dias | Dias/semanas |
| Custo | Zero | Baixo (infra) | Medio a alto |
| Dados necessarios | Nenhum | Documentos | 50-10k exemplos |
| Atualizacao do conhecimento | Imediata | Imediata | Requer re-treino |
| Consistencia de formato | Media | Media | Alta |
| Reducao de tokens | Nao | Nao | Sim |
| Ideal para | Ajustes rapidos | Conhecimento dinamico | Estilo/formato fixo |
Recomendacao pratica: comece com prompt engineering. Se voce bater no teto de qualidade, adicione RAG para injetar contexto relevante. So considere fine-tuning quando RAG + prompts ainda nao entregar o que voce precisa -- ou quando o custo de tokens for inaceitavel em producao.
---
Fine-Tuning no GPT-4o-mini (OpenAI): Passo a Passo
A OpenAI permite fine-tuning nos modelos gpt-4o-mini, gpt-3.5-turbo e outros. O processo tem tres etapas: preparar o dataset, fazer o upload e criar o job de treinamento.
Preparando o Dataset
O formato exigido e JSONL (JSON Lines) -- um objeto JSON por linha, no formato de conversa:
{"messages": [{"role": "system", "content": "Classifique sentimentos: POSITIVO, NEGATIVO ou NEUTRO."}, {"role": "user", "content": "O produto chegou rapido e superou minhas expectativas!"}, {"role": "assistant", "content": "POSITIVO"}]}
{"messages": [{"role": "system", "content": "Classifique sentimentos: POSITIVO, NEGATIVO ou NEUTRO."}, {"role": "user", "content": "Demorou 3 semanas e o produto veio danificado."}, {"role": "assistant", "content": "NEGATIVO"}]}
{"messages": [{"role": "system", "content": "Classifique sentimentos: POSITIVO, NEGATIVO ou NEUTRO."}, {"role": "user", "content": "O produto e ok, nada demais."}, {"role": "assistant", "content": "NEUTRO"}]}
Diretrizes para o dataset:
- Minimo de 10 exemplos (recomendado: 50-500+)
- Qualidade > quantidade: exemplos ruins ensinam comportamentos ruins
- Cada exemplo deve ser representativo do caso de uso real
- Varie os exemplos -- nao repita o mesmo padrao com palavras diferentes
- Separe 10-20% para validacao (parametro
validation_file)
Script para gerar e validar o dataset:
import json
def criar_exemplo(system: str, user: str, assistant: str) -> dict:
return {"messages": [
{"role": "system", "content": system},
{"role": "user", "content": user},
{"role": "assistant", "content": assistant}
]}
def salvar_jsonl(exemplos: list, caminho: str):
with open(caminho, "w", encoding="utf-8") as f:
for ex in exemplos:
f.write(json.dumps(ex, ensure_ascii=False) + "\n")
def validar_jsonl(caminho: str) -> bool:
with open(caminho, "r", encoding="utf-8") as f:
for i, linha in enumerate(f, 1):
try:
obj = json.loads(linha)
assert "messages" in obj
for msg in obj["messages"]:
assert "role" in msg and "content" in msg
except Exception as e:
print(f"Erro na linha {i}: {e}")
return False
print(f"Dataset valido! {i} exemplos.")
return True
Upload e Criacao do Job
from openai import OpenAI
client = OpenAI()
# 1. Upload do arquivo de treino
with open("dataset_treino.jsonl", "rb") as f:
arquivo = client.files.create(file=f, purpose="fine-tune")
print(f"Arquivo criado: {arquivo.id}")
# 2. Upload do arquivo de validacao (opcional mas recomendado)
with open("dataset_validacao.jsonl", "rb") as f:
arquivo_val = client.files.create(file=f, purpose="fine-tune")
# 3. Criar o job de fine-tuning
job = client.fine_tuning.jobs.create(
training_file=arquivo.id,
validation_file=arquivo_val.id,
model="gpt-4o-mini-2024-07-18",
hyperparameters={
"n_epochs": 3,
"batch_size": "auto",
"learning_rate_multiplier": "auto"
},
suffix="meu-classificador-v1"
)
print(f"Job criado: {job.id}")
print(f"Status: {job.status}")
Monitorando e Usando o Modelo Fine-Tuned
import time
from openai import OpenAI
client = OpenAI()
def monitorar_job(job_id: str):
while True:
job = client.fine_tuning.jobs.retrieve(job_id)
print(f"Status: {job.status}")
if job.status in ("succeeded", "failed", "cancelled"):
if job.status == "succeeded":
print(f"Modelo: {job.fine_tuned_model}")
return job
eventos = client.fine_tuning.jobs.list_events(job_id, limit=3)
for ev in reversed(eventos.data):
print(f" [{ev.created_at}] {ev.message}")
time.sleep(30)
def usar_modelo(modelo_id: str, mensagem: str) -> str:
response = client.chat.completions.create(
model=modelo_id,
messages=[
{"role": "system", "content": "Classifique sentimentos."},
{"role": "user", "content": mensagem}
],
temperature=0
)
return response.choices[0].message.content
modelo = "ft:gpt-4o-mini-2024-07-18:minha-org:classificador-v1:abc123"
print(usar_modelo(modelo, "Adorei o atendimento!")) # POSITIVO
---
Fine-Tuning Local com LoRA/QLoRA
Para modelos open-source (LLaMA 3, Mistral, Qwen, Gemma), e possivel fazer fine-tuning localmente sem pagar por API. LoRA (Low-Rank Adaptation) e QLoRA (LoRA quantizado) reduzem drasticamente a memoria necessaria.
Configurando Ambiente
pip install transformers datasets peft accelerate bitsandbytes trl
nvidia-smi # verificar CUDA
Requisitos minimos:
- LoRA em modelo 7B: ~16GB VRAM (RTX 4080/4090, A100)
- QLoRA 4-bit em modelo 7B: ~8GB VRAM (RTX 3080/4070)
- QLoRA 4-bit em modelo 13B: ~12-14GB VRAM
Codigo com Transformers + PEFT
import torch
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig, TrainingArguments
from peft import LoraConfig, get_peft_model, TaskType
from trl import SFTTrainer
MODEL_ID = "meta-llama/Meta-Llama-3-8B-Instruct"
OUTPUT_DIR = "./llama3-finetuned"
# Configuracao QLoRA 4-bit
bnb_config = BitsAndBytesConfig(
load_in_4bit=True,
bnb_4bit_use_double_quant=True,
bnb_4bit_quant_type="nf4",
bnb_4bit_compute_dtype=torch.bfloat16
)
tokenizer = AutoTokenizer.from_pretrained(MODEL_ID)
tokenizer.pad_token = tokenizer.eos_token
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID, quantization_config=bnb_config, device_map="auto"
)
lora_config = LoraConfig(
r=16, lora_alpha=32,
target_modules=["q_proj", "v_proj", "k_proj", "o_proj"],
lora_dropout=0.05, bias="none",
task_type=TaskType.CAUSAL_LM
)
model = get_peft_model(model, lora_config)
model.print_trainable_parameters()
# trainable params: 6,815,744 || all params: 8,037,367,808 (0.0848%)
def formatar_exemplo(ex):
return f"<|system|>\n{ex['system']}\n<|user|>\n{ex['input']}\n<|assistant|>\n{ex['output']}"
dados_raw = [
{"system": "Voce e um assistente de culinaria.", "input": "Como faco arroz perfeito?", "output": "Use 2 partes de agua para 1 de arroz..."},
]
dataset = Dataset.from_list([{"text": formatar_exemplo(d)} for d in dados_raw])
args = TrainingArguments(
output_dir=OUTPUT_DIR, num_train_epochs=3,
per_device_train_batch_size=2, gradient_accumulation_steps=4,
learning_rate=2e-4, fp16=True, logging_steps=10,
save_strategy="epoch", report_to="none"
)
trainer = SFTTrainer(
model=model, train_dataset=dataset, args=args,
dataset_text_field="text", max_seq_length=512, packing=False
)
trainer.train()
trainer.model.save_pretrained(OUTPUT_DIR)
print("Fine-tuning concluido!")
---
Avaliando a Qualidade do Fine-Tuning
Fine-tuning sem avaliacao e um desperdicio. Use estas metricas e estrategias:
Metricas automaticas:
- Loss de validacao -- deve cair ao longo do treino sem subir ao final (overfitting)
- Perplexity -- quanto menor, mais o modelo entende os exemplos
- Accuracy por categoria -- para classificacao, meca por classe
Avaliacao humana (gold standard):
- Crie 50-100 casos de teste com resposta esperada
- Compare: modelo base vs fine-tuned vs GPT-4o como referencia
- Use escala de 1-5 para qualidade, relevancia e formato
from openai import OpenAI
client = OpenAI()
def avaliar_modelo(modelo_base, modelo_finetuned, casos_teste):
resultados = {"base": [], "finetuned": []}
for caso in casos_teste:
for modelo, chave in [(modelo_base, "base"), (modelo_finetuned, "finetuned")]:
resp = client.chat.completions.create(
model=modelo,
messages=[
{"role": "system", "content": caso["system"]},
{"role": "user", "content": caso["input"]}
],
temperature=0
)
obtido = resp.choices[0].message.content.strip()
resultados[chave].append({
"input": caso["input"],
"esperado": caso["expected"],
"obtido": obtido,
"correto": obtido == caso["expected"].strip()
})
n = len(casos_teste)
acc_base = sum(r["correto"] for r in resultados["base"]) / n
acc_ft = sum(r["correto"] for r in resultados["finetuned"]) / n
print(f"Acuracia base: {acc_base:.1%}")
print(f"Acuracia fine-tuned: {acc_ft:.1%}")
print(f"Melhoria: {(acc_ft - acc_base):.1%}")
return resultados
---
Custo e Tempo Estimados
| Cenario | Modelo | Exemplos | Epochs | Tempo estimado | Custo estimado |
|---|---|---|---|---|---|
| Classificacao simples | gpt-4o-mini | 100 | 3 | 5-15 min | US$ 0,30 |
| Classificacao medio | gpt-4o-mini | 1.000 | 3 | 20-40 min | US$ 3,00 |
| Tarefa complexa | gpt-4o-mini | 5.000 | 3 | 1-2h | US$ 15,00 |
| LLaMA 3 8B (LoRA) | local | 1.000 | 3 | 30-60 min | Custo eletrico |
| LLaMA 3 8B (LoRA) | RunPod A100 | 5.000 | 3 | 1-2h | US$ 3-8 |
Obs: o custo da OpenAI para fine-tuning do gpt-4o-mini e de US$ 3,00 por 1M tokens de treino. Verifique a pagina de precos -- valores mudam.
---
Erros Comuns
Dataset pequeno ou desequilibrado: com menos de 50 exemplos, o modelo overfita. Com classes desequilibradas (90% de uma classe), ele aprende a ignorar as minoritarias.
Exemplos inconsistentes: se voce tem exemplos similares com respostas diferentes, o modelo nao converge. Revise manualmente antes de enviar.
Nao separar validacao: sem conjunto de validacao, voce nao sabe se esta sofrendo overfitting. Sempre separe 10-20% dos dados.
Re-usar o modelo fine-tuned para outro dominio: modelos fine-tuned tendem a esquecer capacidades gerais (catastrophic forgetting). Use-os apenas para a tarefa treinada.
Nao testar incrementalmente: treine com 100 exemplos, avalie, depois 500, avalie novamente. Escale so quando ver melhoria consistente.
Epochs demais: mais epochs nao e sempre melhor. A loss de validacao pode subir enquanto a de treino cai -- isso e overfitting. Monitore a curva de validacao.
---
Perguntas Frequentes
1. Quantos exemplos preciso para fine-tuning?
Depende da complexidade da tarefa. Para classificacao com 2-3 classes, 100 exemplos de qualidade podem ser suficientes. Para geracao de texto com estilo especifico, 500-2000 exemplos sao mais seguros. A OpenAI aceita a partir de 10, mas 50+ e o minimo pratico.
2. Fine-tuning muda o conhecimento do modelo?
Nao diretamente. Fine-tuning ajusta o comportamento, o estilo e o formato das respostas -- nao injeta fatos novos. Se voce quer que o modelo saiba informacoes recentes ou proprietarias, use RAG.
3. Posso fazer fine-tuning em GPT-4o (nao mini)?
Sim, a OpenAI disponibiliza fine-tuning para gpt-4o mas o custo e significativamente maior. Para a maioria dos casos, gpt-4o-mini fine-tuned supera o GPT-4o base em tarefas especificas.
4. O que e catastrophic forgetting?
E quando o modelo fine-tuned perde capacidades gerais ao especializar-se. Mais comum em modelos pequenos e com datasets grandes. A OpenAI mitiga isso no fine-tuning via API -- em modelos locais, tecnicas como regularizacao e replay de dados ajudam.
5. LoRA vs QLoRA: qual usar?
Use QLoRA se voce tem GPU com menos de 24GB VRAM -- o 4-bit reduz a memoria pela metade sem perda significativa de qualidade. Use LoRA sem quantizacao se tiver hardware suficiente e quiser o maximo de qualidade.
6. Posso publicar ou vender um modelo fine-tuned?
Depende da licenca do modelo base. Modelos como LLaMA 3 tem licencas que permitem uso comercial com restricoes. Modelos da OpenAI via fine-tuning API ficam na infraestrutura deles -- voce nao recebe os pesos, apenas acesso via API.
