Aller au contenu principal

Module 3 — Suivi des expériences avec MLflow

Le mercredi, Alice a lancé 37 entraînements pour comparer trois algorithmes, sept jeux de variables et cinq valeurs de régularisation. Le vendredi, on lui demande : « celui qui donnait 0,84, c'était avec quel jeu de variables ? » Elle ne sait plus. Sans suivi, la moitié du travail expérimental est jetée le vendredi soir.

Le vocabulaire de MLflow

MLflow Tracking organise les essais en trois niveaux :

  • Une expérience est un projet, par exemple churn-telecom-v3.
  • Une exécution (run) est un entraînement individuel : un identifiant, un moment, une graine.
  • Une exécution porte des paramètres (choix figés avant l'entraînement), des métriques (mesures issues de l'entraînement) et des artefacts (fichiers produits : modèle, courbe ROC, matrice de confusion).

Cette séparation compte. Les paramètres sont ce qu'on choisit ; les métriques sont ce qu'on mesure. Confondre les deux dans un même dictionnaire rend l'interface de comparaison inutilisable.

Le squelette d'un entraînement suivi

import mlflow
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import roc_auc_score

mlflow.set_tracking_uri("http://mlflow.interne:5000")
mlflow.set_experiment("churn-telecom-v3")

with mlflow.start_run(run_name="rf-100-arbres-var-v7") as run:
params = {"n_estimators": 100, "max_depth": 12, "graine": 42}
mlflow.log_params(params)
mlflow.log_param("jeu_variables", "v7")

modele = RandomForestClassifier(
n_estimators=params["n_estimators"],
max_depth=params["max_depth"],
random_state=params["graine"],
)
modele.fit(X_apprentissage, y_apprentissage)

auc = roc_auc_score(y_validation, modele.predict_proba(X_validation)[:, 1])
mlflow.log_metric("auc_validation", auc)

mlflow.sklearn.log_model(modele, artifact_path="modele")
mlflow.log_artifact("rapports/matrice_confusion.png")

Cinq appels suffisent à rendre l'exécution comparable, retrouvable et rejouable. L'interface web de MLflow affiche alors un tableau des 37 essais, triable par métrique, filtrable par paramètre, avec un bouton « comparer » qui superpose les courbes.

La journalisation automatique

Pour scikit-learn, PyTorch Lightning, XGBoost ou LightGBM, MLflow propose la journalisation automatique :

mlflow.sklearn.autolog()

with mlflow.start_run():
modele.fit(X_apprentissage, y_apprentissage)

Elle capture tous les hyperparamètres passés à fit, le modèle sérialisé, la signature (types et formes des entrées et sorties) et un exemple d'entrée. Elle évite les oublis, mais elle capture aussi beaucoup de bruit. En pratique, on active autolog puis on ajoute à la main les métriques métier (taux_faux_positifs_a_5_pourcent, AUC_sur_le_segment_pro) qui n'ont aucune raison d'être connues d'un cadre général.

Le serveur partagé

Par défaut, MLflow écrit dans un dossier local mlruns/. Ce mode convient pour explorer seul, jamais pour une équipe. Deux personnes qui pointent chacune sur leur dossier local perdent la comparabilité au premier échange.

Un serveur partagé se monte en une commande :

mlflow server \
--backend-store-uri postgresql://mlflow:xxx@bdd:5432/mlflow \
--default-artifact-root s3://mon-bucket/mlflow-artifacts/ \
--host 0.0.0.0 --port 5000

Deux stockages sont impliqués. La base relationnelle porte les paramètres et les métriques (petits, structurés, interrogeables en SQL). Le stockage objet porte les artefacts (modèles, images, gros fichiers). Séparer les deux est ce qui rend MLflow capable de tenir des centaines de milliers d'exécutions sans étouffer la base.

Nommer et étiqueter, une hygiène qui paie

Un nom d'exécution comme run_2026_09_03_14h27 n'aide personne. Un nom comme rf-100arbres-var-v7-graine42 se lit à froid. Les étiquettes (mlflow.set_tag("branche_git", "feat/nouvelle-var")) attachent le contexte technique à l'exécution ; on retrouve six mois plus tard le commit précis qui a produit un artefact.

Trois étiquettes rendent une équipe autonome :

  • branche_git et commit_git : la version exacte du code
  • jeu_donnees_version : identifiant du snapshot DVC (module 4)
  • auteur : la personne qui a lancé l'entraînement

Comparer trente exécutions en cinq minutes

Une fois la journalisation en place, l'interface MLflow permet quatre gestes qui remplacent des heures de tableur :

  • Trier par métrique et voir les cinq meilleures exécutions.
  • Filtrer sur un paramètre (jeu_variables = v7) pour isoler l'effet des variables du reste.
  • Comparer deux exécutions côte à côte : différences de paramètres mises en évidence, courbes superposées.
  • Charger l'artefact d'un ancien essai en une ligne : mlflow.pyfunc.load_model("runs:/<run_id>/modele").
La journalisation autonome, pas l'objectif

MLflow ne rend pas un modèle meilleur. Il rend le travail expérimental capitalisable : ce qu'on a essayé, ce qui a marché, ce qui n'a pas marché, tout reste accessible pour la personne qui prendra le relais dans six mois. C'est la différence entre un dépôt de connaissances et un souvenir.

En résumé

  • Trois niveaux : expérience, exécution, artefacts ; ne confondez jamais paramètres (choisis) et métriques (mesurées).
  • Cinq appels log_params, log_metric, log_model, log_artifact, log_param suffisent à rendre une exécution retrouvable.
  • La journalisation automatique évite les oublis ; ajoutez à la main les métriques métier.
  • Un serveur partagé (base SQL + stockage objet) est ce qui rend le suivi utile à plus d'une personne.

Le module 4 ajoute le versionnage des données et du modèle, pour que branche_git et jeu_donnees_version deviennent des identifiants opposables.