Solucionado (ver solução)
Solucionado
(ver solução)
1
resposta

[Dúvida] Não seria melhor nesse caso de avaliação usar um método de regressão para maior acuracia?

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. Logo não seria melhor aplicar um método por regressão 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.")
1 resposta
solução!

Olá Israel! Tudo bem?

Entendo sua dúvida e ela faz bastante sentido. Quando estamos lidando com problemas onde a saída é uma escala contínua, como notas ou avaliações, a regressão pode ser uma abordagem mais adequada. Isso ocorre porque métodos de regressão são projetados para lidar com variáveis contínuas, enquanto a classificação é mais adequada para categorizar entradas em grupos discretos.

No seu caso, como você está avaliando redações e as notas podem variar de forma contínua, um modelo de regressão pode capturar melhor as nuances entre diferentes notas.

Por exemplo, se um modelo de classificação errar uma nota de 10 para 9, isso é considerado um erro completo, enquanto na regressão, a diferença de 1 ponto pode ser tratada de forma mais suave, refletindo a proximidade entre as notas.

Pelo código que você compartilhou, parece que você já está usando um modelo de regressão com o AutoModelForSequenceClassification configurado para problem_type="regression". Isso é ótimo, pois permite que o modelo aprenda a prever valores contínuos, ajustando-se melhor a problemas onde a saída não é binária ou categórica.

Parabéns pela curiosidade e dedicação em buscar o método ideal!

Espero ter ajudado e bons estudos!

Caso este post tenha lhe ajudado, por favor, marcar como solucionado