Só gostaria de um feedback dessa questão, pois se o modelo errar uma label de 10->9 ou mesmo 10->7 é um erro absoluto de categoria por regressão não seria melhor aplicado neste caso?
import torch
import numpy as np
from sklearn.metrics import mean_squared_error, mean_absolute_error, root_mean_squared_error
from datasets import load_dataset, DatasetDict, Value
from transformers import (
AutoTokenizer,
AutoModelForSequenceClassification,
DataCollatorWithPadding,
Trainer,
TrainingArguments
)
# ----- 1. Setup e Dataset (Igual ao anterior) -----
checkpoint_model = "distilbert-base-uncased"
tokenizer = AutoTokenizer.from_pretrained(checkpoint_model)
model = AutoModelForSequenceClassification.from_pretrained(
checkpoint_model,
num_labels=1,
problem_type="regression"
)
essays_data = load_dataset("csv", data_files="/content/redacoes.csv")
data_split = essays_data["train"].train_test_split(test_size=0.2, shuffle=True, seed=42)
essays_data = DatasetDict({
"training": data_split["train"],
"test": data_split["test"]
})
# Tokenização (Mantendo a otimização de padding dinâmico)
def tokenizer_fn(batch):
return tokenizer(batch["essay"], truncation=True, max_length=384)
tokenized_dataset = essays_data.map(tokenizer_fn, batched=True, remove_columns=["essay"])
# Tratamento de Labels
tokenized_dataset = tokenized_dataset.rename_column("score", "label")
tokenized_dataset = tokenized_dataset.cast_column("label", Value("float32"))
tokenized_dataset.set_format(type="torch", columns=["input_ids", "attention_mask", "label"])
# Data Collator
data_collator = DataCollatorWithPadding(tokenizer)
# ----- 2. Função de Métricas -----
# O Trainer nos dá as predições e os labels reais.
# Aqui calculamos o quão "longe" a nota predita está da real.
def compute_metrics(eval_pred):
predictions, labels = eval_pred
# O Trainer retorna as predições como numpy arrays.
# Se o modelo retornar logits, às vezes vem dentro de uma tupla, mas em regressão simples geralmente é direto.
# O .squeeze() garante que o array tenha o shape correto (ex: [8] em vez de [8,1])
predictions = predictions.squeeze() if isinstance(predictions, np.ndarray) else predictions[0].squeeze()
mse = mean_squared_error(labels, predictions)
rmse = root_mean_squared_error(labels, predictions)
mae = mean_absolute_error(labels, predictions)
return {"mse": mse, "rmse": rmse, "mae": mae}
# ----- 3. Modelo -----
model = AutoModelForSequenceClassification.from_pretrained(
checkpoint_model,
num_labels=1,
problem_type="regression"
)
# ----- 4. Configuração do Treino (TrainingArguments) -----
training_args = TrainingArguments(
output_dir="./resultado_trainer",
learning_rate=2e-5,
per_device_train_batch_size=8,
per_device_eval_batch_size=8,
num_train_epochs=3,
weight_decay=0.01,
eval_strategy="epoch", # Avalia ao final de cada época
save_strategy="epoch", # Salva o modelo ao final de cada época
load_best_model_at_end=True, # No final, carrega o melhor checkpoint (menor loss)
metric_for_best_model="mae", # Usa o MAE para decidir qual é o "melhor" modelo
greater_is_better=False, # Para erro (MAE/RMSE), menor é melhor
logging_dir='./logs', # Onde salvar os logs
logging_steps=10,
fp16=True, # [Otimização] Usa precisão mista (treina mais rápido em GPU T4/P100)
push_to_hub=False, # Mude para True se quiser subir pro HF automaticamente
)
# ----- 5. Trainer -----
trainer = Trainer(
model=model,
args=training_args,
train_dataset=tokenized_dataset["training"],
eval_dataset=tokenized_dataset["test"],
data_collator=data_collator,
compute_metrics=compute_metrics, # Injetamos nossa lógica de avaliação aqui
)
# ----- 6. Executar -----
print("Iniciando treinamento com Trainer API...")
trainer.train()
# ----- 7. Avaliação Final e Salvamento -----
print("\n--- Resultados Finais no Test Set ---")
metrics = trainer.evaluate()
print(metrics)
trainer.save_model("./meu_modelo_final_trainer")
print("Modelo salvo com sucesso.")