optuna

Par mkurman · zorai

npx skills add https://github.com/mkurman/zorai --skill optuna

name: optuna description: Framework d'optimisation d'hyperparamètres (Optuna). API Define-by-run avec construction automatique de l'espace de recherche, samplers état de l'art (TPE, CMA-ES, NSGA-II, GPSampler), pruning efficace (Median, Hyperband, ASHA), optimisation multi-objectif, optimisation contrainte, exécution parallèle distribuée et tableau de bord de visualisation. S'intègre avec PyTorch, PyTorch Lightning, TensorFlow, Keras, XGBoost, LightGBM, CatBoost, MLflow, W&B et scikit-learn. license: MIT license tags: [hyperparameter-optimization, pruning, multi-objective-optimization, experiment-search, optuna] metadata: skill-author: K-Dense Inc. ------|----------|-------------| | TPESampler | Tuning ML général | Tree-structured Parzen Estimator ; par défaut, bon pour la plupart des cas | | CMAESSampler | Continu, basse dimension (<100) | Covariance Matrix Adaptation ; efficace pour les paramètres numériques | | NSGAIISampler | Multi-objectif (2-3 objectifs) | Optimisation du front de Pareto | | GPSampler | Évaluations coûteuses | Basé sur Gaussian Process ; efficace en nombre d'échantillons | | RandomSampler | Baseline, débogage | Échantillonnage aléatoire uniforme | | GridSampler | Petits espaces discrets | Recherche en grille exhaustive | | QMCSampler | Espaces continus | Quasi-Monte Carlo, meilleure couverture que le random |

Utilisation:

import optuna
sampler = optuna.samplers.TPESampler(seed=42, n_startup_trials=10)
study = optuna.create_study(sampler=sampler)

4. Pruning (Early Stopping)

Arrêtez les trials peu prometteurs tôt pour économiser du calcul :

def objective(trial):
    for epoch in range(100):
        accuracy = train_and_evaluate(...)
        # Rapporter la valeur intermédiaire
        trial.report(accuracy, epoch)
        # Vérifier s'il faut pruner
        if trial.should_prune():
            raise optuna.TrialPruned()
    return accuracy

Sélection du Pruner:

  • MedianPruner: Prune si la valeur intermédiaire du trial est sous la médiane à la même étape
  • HyperbandPruner: Successive halving ; efficace pour un grand nombre de trials
  • SuccessiveHalvingPruner: Similaire à Hyperband, configuration plus simple
  • ThresholdPruner: Prune sous un seuil absolu
  • PatientPruner: Prune après N epochs sans amélioration

Intégration avec PyTorch Lightning:

from optuna.integration import PyTorchLightningPruningCallback

trainer = pl.Trainer(
    callbacks=[PyTorchLightningPruningCallback(trial, monitor="val_acc")],
    max_epochs=100,
)

5. Optimisation Multi-Objectif

def objective(trial):
    accuracy = train_and_get_accuracy(trial)
    latency_ms = measure_latency(trial)
    return accuracy, latency_ms  # Retourner un tuple

study = optuna.create_study(
    directions=["maximize", "minimize"],
    sampler=optuna.samplers.NSGAIISampler(),
)

study.optimize(objective, n_trials=200)

# Obtenir le front de Pareto
best_trials = study.best_trials
for trial in best_trials:
    print(f"Params: {trial.params}, Values: {trial.values}")

6. Exécution Distribuée / Parallèle

Multi-processus sur une seule machine:

study.optimize(objective, n_trials=100, n_jobs=8)  # 8 workers parallèles

Multi-nœud via stockage partagé (SQLite):

# Sur tous les nœuds, partager le même nom d'étude et le même stockage
study = optuna.create_study(
    study_name="distributed_study",
    storage="sqlite:///optuna_study.db",
    load_if_exists=True,
)
study.optimize(objective, n_trials=500)

Multi-nœud via RDB (PostgreSQL/MySQL):

study = optuna.create_study(
    study_name="large_scale_study",
    storage="postgresql://user:pass@host:5432/optuna",
    load_if_exists=True,
)

7. Visualisation

from optuna.visualization import (
    plot_optimization_history,
    plot_param_importances,
    plot_parallel_coordinate,
    plot_contour,
    plot_slice,
)

# Progression de l'optimisation au fil des trials
plot_optimization_history(study)

# Classement de l'importance des hyperparamètres
plot_param_importances(study)

# Parallel coordinate plot pour l'analyse haute dimension
plot_parallel_coordinate(study)

# Slice plot montrant la relation paramètre-valeur
plot_slice(study)

# Contour plot pour les interactions entre paires de paramètres
plot_contour(study, params=["learning_rate", "n_layers"])

Tableau de bord Web (optuna-dashboard):

pip install optuna-dashboard
optuna-dashboard sqlite:///optuna_study.db
# S'ouvre à http://localhost:8080

8. Intégration PyTorch Lightning

import pytorch_lightning as pl
import optuna
from optuna.integration import PyTorchLightningPruningCallback

def objective(trial):
    # Suggérer les hyperparamètres
    lr = trial.suggest_float("lr", 1e-5, 1e-1, log=True)
    batch_size = trial.suggest_categorical("batch_size", [32, 64, 128, 256])
    n_layers = trial.suggest_int("n_layers", 1, 6)

    model = MyLightningModule(lr=lr, n_layers=n_layers)
    trainer = pl.Trainer(
        max_epochs=50,
        callbacks=[PyTorchLightningPruningCallback(trial, monitor="val_loss")],
        logger=False,
    )
    trainer.fit(model, train_dataloaders=train_loader, val_dataloaders=val_loader)

    return trainer.callback_metrics["val_loss"].item()

study = optuna.create_study(direction="minimize")
study.optimize(objective, n_trials=50)

9. Intégration HuggingFace Transformers

from transformers import Trainer, TrainingArguments
import optuna

def hp_space(trial):
    return {
        "learning_rate": trial.suggest_float("learning_rate", 1e-6, 1e-4, log=True),
        "per_device_train_batch_size": trial.suggest_categorical("batch_size", [8, 16, 32]),
        "num_train_epochs": trial.suggest_int("num_epochs", 1, 5),
        "warmup_ratio": trial.suggest_float("warmup_ratio", 0.0, 0.3),
    }

trainer = Trainer(
    model=model,
    args=training_args,
    train_dataset=train_dataset,
    eval_dataset=eval_dataset,
)

best_run = trainer.hyperparameter_search(
    hp_space=hp_space,
    n_trials=30,
    direction="minimize",
)

10. Stockage d'Artefacts et d'Attributs

def objective(trial):
    model = train_model(trial)
    # Stocker des attributs arbitraires
    trial.set_user_attr("model_architecture", str(model))
    trial.set_user_attr("training_time_seconds", 3600)
    return evaluate(model)

# Récupérer plus tard
for trial in study.trials:
    print(trial.user_attrs.get("training_time_seconds"))

Installation

pip install optuna
# Optionnel : tableau de bord
pip install optuna-dashboard
# Optionnel : fonctionnalités OptunaHub
pip install optunahub

Patterns Clés pour l'Entraînement ML

  1. Toujours utiliser log=True pour les learning rates, batch sizes et autres paramètres sensibles à l'échelle
  2. Définir n_startup_trials à 10-20 pour que TPE se réchauffe avec exploration aléatoire
  3. Utiliser le pruning agressivement pour les trials deep learning coûteux — économise 50-80% du calcul
  4. Pour la reproductibilité, définir seed sur le sampler et study.optimize()
  5. Stocker les valeurs intermédiaires avec trial.report() même sans pruning — permet une meilleure analyse

Références

Voir scripts/optuna_lightning_template.py pour un modèle complet d'entraînement PyTorch Lightning + Optuna. Voir references/advanced_samplers.md pour une comparaison détaillée des samplers et des conseils de sélection.

Skills similaires