Pular para o conteúdo
🧠Inteligência em Código
📚 Tutoriais8 min de leitura

Como Fazer Fine-Tuning com Hugging Face Transformers

Guia passo a passo para fazer fine-tuning de modelos de linguagem usando a biblioteca Transformers do Hugging Face.

#huggingface#fine-tuning#transformers#python

Lembro da primeira vez que tentei treinar um modelo do zero para classificação de texto em português. Semanas de trabalho, milhares de exemplos coletados manualmente, GPU alugada por dias — e o resultado foi medíocre comparado a um BERT pré-treinado que eu fine-tunei em horas com cem vezes menos dados.

Essa experiência me ensinou a diferença entre trabalhar duro e trabalhar inteligente em ML. Fine-tuning é uma das técnicas de maior alavancagem que existe: você pega um modelo treinado em bilhões de tokens e o especializa no seu domínio com recursos que qualquer desenvolvedor tem acesso. Vou mostrar exatamente como fiz isso em projetos reais. Se depois de dominar o fine-tuning você quiser expor o modelo como serviço, confira o tutorial de API REST com FastAPI.

Por que Fine-Tuning?

Modelos pré-treinados como BERT, RoBERTa e GPT são poderosos mas genéricos. Eles foram treinados em enormes volumes de texto da internet e possuem conhecimento geral sobre linguagem, mas não conhecem o seu domínio específico.

O fine-tuning é o processo de continuar o treinamento de um modelo pré-treinado com seus próprios dados. O resultado é um modelo que combina o conhecimento linguístico geral com expertise no seu domínio específico — seja classificação de sentimento, detecção de spam, chatbot de suporte técnico, geração de código, entre outros.

A principal vantagem é que você precisa de muito menos dados do que treinar um modelo do zero. Um modelo BERT pode ser fine-tunado com apenas alguns milhares de exemplos e ainda assim produzir resultados excelentes.

Requisitos

  • Python 3.10 ou superior
  • GPU NVIDIA com CUDA (recomendado) ou CPU
  • 8 GB de RAM (mínimo); 16 GB recomendado para modelos maiores

Instalação

pip install transformers datasets accelerate peft bitsandbytes scikit-learn

Para verificar se a GPU está disponível:

import torch
print(f"GPU disponível: {torch.cuda.is_available()}")
print(f"Dispositivo: {torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'CPU'}")

1. Carregar Dataset

O Hugging Face Hub tem milhares de datasets prontos. Aqui vamos usar um dataset de análise de sentimento em português:

from datasets import load_dataset, Dataset, DatasetDict
import pandas as pd

# Opção 1: Usar dataset público do Hugging Face Hub
# O dataset "imdb" é em inglês, mas serve para ilustrar o processo
# Para português, use seu próprio dataset (ver Opção 2)
dataset = load_dataset("imdb")
# Colunas: "text" (texto da review) e "label" (0=negativo, 1=positivo)

# Opção 2: Usar um CSV com seus dados (recomendado para dados em português)
# Estrutura esperada do CSV: coluna "texto" e coluna "label" (0 ou 1)
#
# df = pd.read_csv("reviews_portugues.csv")
# # Garantir que os nomes de coluna estão corretos
# df = df.rename(columns={"review": "texto", "sentimento": "label"})
# df["label"] = df["label"].map({"positivo": 1, "negativo": 0})
# dataset = Dataset.from_pandas(df)
# # Dividir em treino/validação/teste
# split = dataset.train_test_split(test_size=0.2, seed=42)
# dataset = split["train"].train_test_split(test_size=0.1, seed=42)
# dataset = DatasetDict({
#     "train": dataset["train"],
#     "validation": dataset["test"],
#     "test": split["test"]
# })

print(f"Total de exemplos (treino): {len(dataset['train'])}")
print(f"Colunas disponíveis: {dataset['train'].column_names}")
print(f"\nExemplo de entrada:")
print(dataset["train"][0])

Para usar datasets locais em formato JSON ou CSV:

from datasets import load_dataset

# A partir de arquivos locais
dataset = load_dataset("json", data_files={
    "train": "dados/treino.json",
    "validation": "dados/validacao.json",
    "test": "dados/teste.json"
})

2. Tokenização

A tokenização converte texto em IDs numéricos que o modelo entende. Cada modelo tem seu próprio tokenizador — é importante usar o tokenizador do mesmo modelo que você vai fazer fine-tuning:

from transformers import AutoTokenizer

# Modelo BERT treinado para português
model_name = "neuralmind/bert-base-portuguese-cased"
tokenizer = AutoTokenizer.from_pretrained(model_name)

def tokenize(examples):
    """Tokeniza um batch de exemplos."""
    return tokenizer(
        examples["text"],          # coluna com o texto (ajuste para o nome da sua coluna)
        padding="max_length",
        truncation=True,
        max_length=128             # BERT tem limite de 512, mas 128 é suficiente para reviews
    )

# Aplicar tokenização ao dataset inteiro de forma eficiente
tokenized_dataset = dataset.map(tokenize, batched=True)

# Verificar resultado
print(f"Tokens de um exemplo: {tokenized_dataset['train'][0]['input_ids'][:20]}...")
print(f"Comprimento: {len(tokenized_dataset['train'][0]['input_ids'])}")

3. Configurar o Modelo

Carregamos o modelo pré-treinado e adicionamos uma cabeça de classificação no topo:

from transformers import AutoModelForSequenceClassification

# 2 classes: positivo (1) e negativo (0)
model = AutoModelForSequenceClassification.from_pretrained(
    model_name,
    num_labels=2,
    id2label={0: "NEGATIVO", 1: "POSITIVO"},
    label2id={"NEGATIVO": 0, "POSITIVO": 1}
)

# Verificar parâmetros treináveis
total_params = sum(p.numel() for p in model.parameters())
trainable_params = sum(p.numel() for p in model.parameters() if p.requires_grad)
print(f"Parâmetros totais: {total_params:,}")
print(f"Parâmetros treináveis: {trainable_params:,}")

4. Treinar com o Trainer

O Trainer do Hugging Face cuida de todo o loop de treinamento, avaliação, logging e checkpoints automaticamente:

from transformers import TrainingArguments, Trainer
import numpy as np
from sklearn.metrics import accuracy_score, f1_score

def compute_metrics(eval_pred):
    """Calcula métricas de avaliação durante o treinamento."""
    logits, labels = eval_pred
    predictions = np.argmax(logits, axis=-1)
    return {
        "accuracy": accuracy_score(labels, predictions),
        "f1": f1_score(labels, predictions, average="weighted"),
    }

training_args = TrainingArguments(
    output_dir="./resultados-fine-tuning",
    num_train_epochs=3,                # 3 épocas é um bom ponto de partida
    per_device_train_batch_size=16,
    per_device_eval_batch_size=32,
    warmup_steps=500,                  # Aquecimento do learning rate
    weight_decay=0.01,                 # Regularização L2
    learning_rate=2e-5,                # Taxa de aprendizado baixa para fine-tuning
    logging_dir="./logs",
    logging_steps=50,
    eval_strategy="epoch",
    save_strategy="epoch",
    load_best_model_at_end=True,
    metric_for_best_model="f1",        # Salvar o modelo com melhor F1
    fp16=True,                         # Usar float16 para treinar mais rápido (GPU)
    report_to="none",                  # Desativar W&B/MLflow por padrão
)

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=tokenized_dataset["train"],
    eval_dataset=tokenized_dataset["test"],   # IMDB usa "test" como validação
    compute_metrics=compute_metrics,
)

# Iniciar treinamento
print("Iniciando fine-tuning...")
trainer.train()

# Avaliar no conjunto de teste
print("\nAvaliação no conjunto de teste:")
results = trainer.evaluate(tokenized_dataset["test"])
print(f"Accuracy: {results['eval_accuracy']:.4f}")
print(f"F1 Score: {results['eval_f1']:.4f}")

5. Usar o Modelo Treinado

Após o treinamento, salve e use o modelo em produção:

# Salvar modelo e tokenizador
model.save_pretrained("./meu-modelo-sentimento")
tokenizer.save_pretrained("./meu-modelo-sentimento")

print("Modelo salvo em ./meu-modelo-sentimento")

Para carregar e usar em produção:

from transformers import pipeline

# Carregar modelo treinado
classifier = pipeline(
    "text-classification",
    model="./meu-modelo-sentimento",
    tokenizer="./meu-modelo-sentimento"
)

# Testar
textos = [
    "Esse produto é incrível! Chegou antes do prazo e funciona perfeitamente.",
    "Péssima experiência. O produto veio com defeito e o suporte não ajudou.",
    "Produto ok, dentro do esperado.",
]

for texto in textos:
    resultado = classifier(texto)[0]
    print(f"\nTexto: {texto}")
    print(f"  → {resultado['label']} (confiança: {resultado['score']:.1%})")

Resultado Esperado

Texto: Esse produto é incrível! Chegou antes do prazo e funciona perfeitamente.
  → POSITIVO (confiança: 98.3%)

Texto: Péssima experiência. O produto veio com defeito e o suporte não ajudou.
  → NEGATIVO (confiança: 97.1%)

Texto: Produto ok, dentro do esperado.
  → POSITIVO (confiança: 62.4%)

Fine-Tuning Eficiente com LoRA (para modelos grandes)

Para modelos com bilhões de parâmetros, fazer fine-tuning completo exige GPUs caras. O LoRA (Low-Rank Adaptation) resolve isso treinando apenas matrizes de adaptação de baixa dimensão, reduzindo os parâmetros treináveis em até 10.000x:

from peft import LoraConfig, get_peft_model, TaskType
from transformers import AutoModelForCausalLM

# Carregar modelo base (ex: Llama ou similar)
base_model = AutoModelForCausalLM.from_pretrained(
    "meta-llama/Llama-3.2-3B",
    load_in_8bit=True,  # Quantização 8-bit para economizar VRAM
    device_map="auto"
)

# Configurar LoRA
lora_config = LoraConfig(
    task_type=TaskType.CAUSAL_LM,
    r=8,              # Rank da decomposição (menor = mais eficiente, menos expressivo)
    lora_alpha=16,    # Escala para os pesos LoRA
    lora_dropout=0.1,
    target_modules=["q_proj", "v_proj"],  # Quais layers aplicar LoRA
)

# Aplicar LoRA ao modelo
model_lora = get_peft_model(base_model, lora_config)
model_lora.print_trainable_parameters()
# Saída: trainable params: 4,194,304 || all params: 3,215,681,536 || trainable%: 0.13

Com LoRA, é possível fazer fine-tuning de modelos de 3B parâmetros em uma GPU de 8 GB de VRAM — algo impraticável com treinamento completo.

Dicas Importantes

  1. Comece pequeno: use um subset dos dados (1.000–5.000 exemplos) para validar o pipeline completo antes de treinar com o dataset inteiro. Isso evita desperdiçar horas de GPU em configurações erradas.

  2. Learning rate baixo: para fine-tuning, use taxas entre 2e-5 e 5e-5. Taxas mais altas podem destruir o conhecimento pré-treinado do modelo (catastrofic forgetting).

  3. Poucas épocas: 2 a 5 épocas geralmente são suficientes. Mais do que isso tende a causar overfitting.

  4. Early stopping: monitore a loss de validação e pare o treinamento quando ela parar de diminuir:

from transformers import EarlyStoppingCallback

trainer = Trainer(
    ...
    callbacks=[EarlyStoppingCallback(early_stopping_patience=2)]
)
  1. Dados de qualidade: a qualidade do dataset é mais importante que a quantidade. 500 exemplos bem rotulados superam 5.000 exemplos com ruído.

  2. Balanceamento: se o dataset for muito desbalanceado (ex: 90% positivo, 10% negativo), use técnicas de oversampling ou pesos de classe:

import torch
# Pesos para compensar desbalanceamento (mais peso para a classe minoritária)
class_weights = torch.tensor([1.0, 9.0])  # [peso_classe_0, peso_classe_1]

Próximos Passos

  • Fine-tuning com LoRA para modelos de 7B+ parâmetros: use QLoRA (quantização 4-bit + LoRA) para treinar modelos grandes em GPUs acessíveis.
  • RLHF básico: ajuste o modelo com feedback humano usando a biblioteca trl.
  • Publicar no Hub: compartilhe seu modelo fine-tunado na comunidade Hugging Face com model.push_to_hub("seu-usuario/nome-do-modelo").
  • Inferência eficiente: use quantização INT8 ou INT4 para acelerar a inferência em produção sem perda significativa de qualidade.
Paulo Cesar

Sobre o autor

Paulo Cesar

Desenvolvedor sênior com mais de 20 anos de experiência em desenvolvimento de software, IA aplicada, automação e sistemas financeiros. Criador do Inteligência em Código, onde compartilha conhecimento prático sobre inteligência artificial para desenvolvedores brasileiros.