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
pip install optuna scikit-learn2. É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.
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 score3. 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.
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.
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 :
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.






