Using hyperparameter-search in Trainer

Hi all!

I’m using Optuna for hyper-parameter search, but I have a doubt/problem.

Here the performance report obtained during fine-tuning a pretrained BERT for Polarity Classification:

Epoch Training Loss Validation Loss Accuracy F1 Precision Recall
1 0.546600 0.438429 0.795547 0.749214 0.745114 0.753995
2 0.277000 0.457287 0.786100 0.742984 0.735595 0.753490
3 0.207700 0.595937 0.800270 0.743335 0.751293 0.736927

Optuna says:

[I 2021-07-23 10:27:45,517] Trial 0 finished with value: 0.7433345815390376 and parameters: {‘learning_rate’: 4.5470513013108546e-05, ‘warmup_steps’: 0.6, ‘weight_decay’: 0.07700782690380507}. Best is trial 0 with value: 0.7433345815390376.

So it seems that as best value for the run it takes the score of the last row, even tough I specified load_best_model=True and metric_for_best_model="eval_f1"

Here my code snippet:

from sklearn.metrics import precision_recall_fscore_support, accuracy_score

def compute_metrics(pred):
    labels = pred.label_ids
    preds = pred.predictions.argmax(-1)
    precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='macro')
    acc = accuracy_score(labels, preds)
    return {
        'accuracy': acc,
        'f1': f1,
        'precision': precision,
        'recall': recall
    }

class MemorySaverCallback(TrainerCallback):
    "A callback that deleted the folder in which checkpoints are saved, to save memory"
    def __init__(self, run_name):
        super(MemorySaverCallback, self).__init__()
        self.run_name = run_name

    def on_train_begin(self, args, state, control, **kwargs):
        print("Removing dirs...")
        if os.path.isdir(f'./{self.run_name}'):
            import shutil
            shutil.rmtree(f'./{self.run_name}')
        else:
            print("\n\nDirectory does not exists")

training_args = TrainingArguments(
    RUN_NAME, 
    num_train_epochs=15,
    per_device_train_batch_size=64,
    per_device_eval_batch_size=64,
    evaluation_strategy="epoch",
    logging_strategy="steps",
    logging_steps=1,
    logging_first_step=False,
    overwrite_output_dir=True,
    save_strategy="no",
    save_total_limit=1,
    load_best_model_at_end=True,
    metric_for_best_model="eval_f1",
)

trainer = Trainer(
    model_init=partial(MyNet,2),
    args=training_args, 
    train_dataset=training_opos.select(range(2000)), 
    eval_dataset=validating_opos,
    compute_metrics=compute_metrics,
    callbacks=[EarlyStoppingCallback(early_stopping_patience=2), MemorySaverCallback(RUN_NAME)]
)

def my_hp_space_optuna(trial):
    return {
        "learning_rate": trial.suggest_float("learning_rate", 2e-6, 2e-4, log=True),
        "warmup_steps":  trial.suggest_float("warmup_steps", 0., 0.9, step=0.3),
        "weight_decay":  trial.suggest_float("weight_decay", 1e-6, 1e-1)
    }
def my_objective(metrics):
    return metrics["eval_f1"]

sa = trainer.hyperparameter_search(
    direction="maximize", 
    n_trials=1,
    hp_space=my_hp_space_optuna, 
    compute_objective=my_objective
)

Optuna version=2.8.0
Transformers version=4.6.1

Thanks in advance!

3 Likes