Sintonização do hiperparâmetro com Optuna & MLflow

Os hiperparâmetros de ajuste são um passo crítico no ciclo de vida do CD4ML para evitar overfitting e otimizar a precisão da previsão. Neste caderno, automatizamos a varredura do hiperparámetro sobre a força de regularização α\alpha do nosso formato fechado RidgeDemandRegressor usando Optuna.

Por que Optuna?

  • Pesquisa eficiente: Em vez da pesquisa em grade, Optuna usa um amostrador Parzen Estimator (TPE) estruturado em árvore para sugerir valores, concentrando-se em regiões promissoras no espaço de registro.
  • Integração: Realizamos 25 ensaios, registrando cada seleção de parâmetros e as métricas de validação resultantes para MLflow como uma corrida aninhada dentro de um dos pais hyperparameter_tuning para preservar a história da experiência.
Cell 02Code
from pathlib import Path

import matplotlib.pyplot as plt
import mlflow
from nyc_taxi_demand_forecasting.configuration import ProjectConfigLoader
from nyc_taxi_demand_forecasting.models.tuning import DemandModelTuner

# Load project configuration
config_path = Path("../configs/project.yaml")
config = ProjectConfigLoader().load(config_path)

# Execute Optuna study search
tuner = DemandModelTuner()
result = tuner.select_best(
    dataset_path=config.features.training_dataset_path,
    target_column=config.training.target_column,
    test_size=config.training.test_size,
    feast_config=config.feast,
    mlflow_config=config.mlflow,
)

print("Tuning completed successfully!")
print(f"Optimal Alpha regularization: {result.alpha:.4f}")
print(
    f"Best Validation Mean Absolute Error (MAE): {result.validation_mae:.4f}"
)
Stream
/home/gabriel-menezes/Documents/repos/mlops/.venv/lib/python3.11/site-packages/ibis/backends/duckdb/__init__.py:332: DeprecationWarning: fetch_arrow_table() is deprecated, use to_arrow_table() instead.
  meta = result.fetch_arrow_table()
Stream
Tuning completed successfully!
Optimal Alpha regularization: 9917.0641
Best Validation Mean Absolute Error (MAE): 10.9974

Recuperar e Plotizar Métricas de MLflow

Podemos consultar o MLflow Tracking Server usando mlflow.search_runs para visualizar o desempenho em todo o nosso espaço hiperparâmetro.

Cell 04Code
# Retrieve all trial runs under the active experiment
experiment = mlflow.get_experiment_by_name("nyc_taxi_demand_forecasting")
runs = mlflow.search_runs(
    experiment_ids=[experiment.experiment_id],
    filter_string="tags.mlflow.runName LIKE 'tune_ridge_trial_%'",
)

# Extract parameters and metrics
runs["alpha"] = runs["params.alpha"].astype(float)
runs["mae"] = runs["metrics.mae"].astype(float)
runs = runs.sort_values("start_time").reset_index(drop=True)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 5))

# Plot 1: Optimization History
ax1.plot(
    runs.index + 1,
    runs["mae"],
    marker="o",
    color="#1f77b4",
    linewidth=2,
)
best_idx = runs["mae"].idxmin()
best_mae = runs.loc[best_idx, "mae"]
best_alpha = runs.loc[best_idx, "alpha"]

ax1.axhline(best_mae, color="red", linestyle="--", alpha=0.7)
ax1.annotate(
    f"Best Trial #{best_idx + 1}\nMAE: {best_mae:.4f}",
    xy=(best_idx + 1, best_mae),
    xytext=(20, 25),
    textcoords="offset points",
    arrowprops=dict(facecolor="black", shrink=0.08, width=1, headwidth=6),
    fontsize=10,
)
ax1.set_title("Optimization History (MAE over Trials)", fontsize=12)
ax1.set_xlabel("Trial Number", fontsize=10)
ax1.set_ylabel("Validation MAE", fontsize=10)
ax1.grid(True, alpha=0.3)

# Plot 2: Parameter Search Space
ax2.scatter(
    runs["alpha"],
    runs["mae"],
    color="#e6550d",
    s=60,
    alpha=0.8,
    edgecolors="k",
)
ax2.set_xscale("log")
ax2.axvline(best_alpha, color="red", linestyle="--", alpha=0.7)
ax2.annotate(
    f"Best Alpha: {best_alpha:.4f}",
    xy=(best_alpha, best_mae),
    xytext=(20, 25),
    textcoords="offset points",
    arrowprops=dict(facecolor="black", shrink=0.08, width=1, headwidth=6),
    fontsize=10,
)
ax2.set_title("Parameter Search Space (MAE vs Alpha)", fontsize=12)
ax2.set_xlabel("Regularization Weight (Alpha, log-scale)", fontsize=10)
ax2.set_ylabel("Validation MAE", fontsize=10)
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()
Notebook output image
ChartNotebook output image