Optuna : trouve les bons réglages de ton modèle en 100 essais au lieu de 10 000

Optuna : trouve les bons réglages de ton modèle en 100 essais au lieu de 10 000

De quoi avez-vous besoin

Version de Python

3.x

Packages

  • {"nom": "optuna", "version": "4.x"}
  • {"nom": "scikit-learn", "version": "1.5"}

Difficulté

Intermédiaire

Tu as entraîné ton premier modèle de machine learning. Il tourne, mais tu le sens bridé. Alors tu ouvres ton script et tu commences à tourner les boutons : un peu plus d'arbres, une profondeur plus grande, un learning rate qui baisse. Trois heures plus tard, tu ne sais plus ce que tu as testé et le meilleur score est noyé quelque part dans l'historique de ton terminal. Ce problème a un nom, l'optimisation d'hyperparamètres, et une solution : Optuna.

Optuna est une bibliothèque Python qui cherche les bons réglages de ton modèle à ta place. Au lieu d'essayer toutes les combinaisons (une grille de 10 valeurs par paramètre sur 5 paramètres, c'est déjà 100 000 essais) ou de miser sur la chance, elle suit une approche bayésienne : chaque essai informe le suivant. Elle apprend quelles zones de l'espace méritent d'être creusées et lesquelles ignorer. Résultat, tu décroches un excellent réglage en 100 essais là où une grille en aurait exigé des milliers.

Le principe tient en trois lignes. Tu écris une fonction objectif qui reçoit un objet trial et renvoie un score. Chaque appel à trial.suggest_... pioche une valeur candidate dans un intervalle que tu définis. Optuna appelle ta fonction encore et encore, et ajuste ses prochains tirages en fonction des scores obtenus.

Côté tirages, tu as le choix : suggest_int('nom', 50, 300) renvoie un entier entre 50 et 300, suggest_float gère les réels, suggest_categorical('activation', ['relu', 'tanh']) pioche dans une liste, et suggest_loguniform explore un espace sur plusieurs ordres de grandeur, parfait pour un learning rate entre 1e-5 et 1e-1.

1. Installer Optuna

bash
pip install optuna scikit-learn

2. Écrire la fonction objectif

On va optimiser un RandomForestClassifier sur le jeu de données breast cancer, déjà embarqué dans scikit-learn. Aucun téléchargement nécessaire, le code tourne tel quel. Notre objectif renvoie la précision moyenne en validation croisée à 5 plis : plus elle est haute, mieux c'est.

python
import optuna
from sklearn.datasets import load_breast_cancer
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import cross_val_score

data = load_breast_cancer()
X, y = data.data, data.target

def objectif(trial):
    modele = RandomForestClassifier(
        n_estimators=trial.suggest_int("n_estimators", 50, 300),
        max_depth=trial.suggest_int("max_depth", 3, 20),
        min_samples_split=trial.suggest_int("min_samples_split", 2, 20),
        random_state=42,
    )
    score = cross_val_score(modele, X, y, cv=5, scoring="accuracy").mean()
    return score

3. Lancer la recherche

Une fois la fonction écrite, on crée une étude et on la lance. Le paramètre direction indique si l'on cherche à maximiser ou minimiser le score. On fixe 100 essais, largement assez pour un problème de ce calibre.

python
etude = optuna.create_study(direction="maximize")
etude.optimize(objectif, n_trials=100)

print("Meilleurs paramètres :", etude.best_params)
print("Meilleur score :", etude.best_value)

4. Couper les essais perdants

Cent essais, c'est bien. Mais certains sont condamnés d'avance, et on le sait vite. Le pruning permet d'abandonner un essai en cours dès que son score intermédiaire est nettement en dessous des autres. On appelle trial.report() à chaque étape, puis trial.should_prune() pour décider d'arrêter les frais.

python
def objectif_avec_pruning(trial):
    modele = RandomForestClassifier(
        n_estimators=trial.suggest_int("n_estimators", 50, 300),
        max_depth=trial.suggest_int("max_depth", 3, 20),
        random_state=42,
    )
    scores = []
    for k in range(2, 6):
        score = cross_val_score(modele, X, y, cv=k, scoring="accuracy").mean()
        scores.append(score)
        trial.report(score, k)
        if trial.should_prune():
            raise optuna.TrialPruned()
    return sum(scores) / len(scores)

etude = optuna.create_study(direction="maximize")
etude.optimize(objectif_avec_pruning, n_trials=100)
print(etude.best_params, etude.best_value)

5. Comprendre le résultat

Optuna ne se contente pas de cracher les meilleurs paramètres. Elle te dit aussi lesquels ont le plus d'impact, et comment la recherche a progressé au fil des essais. Deux lignes pour y voir clair :

python
fig = optuna.visualization.plot_param_importances(etude)
fig.show()

optuna.visualization.plot_optimization_history(etude).show()

En une centaine de lignes, tu as transformé un tâtonnement artisanal en recherche automatisée et guidée. Si tu veux reprendre une étude plus tard, passe storage='sqlite:///etude.db' à create_study et Optuna sauvegarde tout sur disque. La prochaine fois qu'un modèle te résiste, ne tourne plus les boutons au hasard : écris une fonction objectif, laisse Optuna explorer, et récupère le réglage qui gagne. Ton seul vrai travail devient de choisir quels paramètres méritent d'être testés.