thamu _

MLflow Autologging et suivi zero configuration

par Thamu Mnyulwa 7 min de lecture

Le moyen le plus rapide de rendre l’experiment tracking reel n’est pas de construire d’abord une abstraction de logging parfaite.

C’est d’ajouter une ligne avant le code d’entrainement et de laisser MLflow capturer automatiquement les details repetitifs.

C’est la promesse de MLflow autologging. Tu actives une integration, tu entraines le modele normalement, et MLflow enregistre les parametres, les metriques, les artefacts modele, les signatures, les input examples, les informations dataset et les metadonnees framework que l’integration sait capturer.

Pour l’experimentation initiale, c’est important. Cela supprime un probleme frequent dans les petits projets ML : l’equipe veut loguer ses experiences, mais le logging manuel est incoherent, incomplet ou ajoute seulement apres qu’un resultat semble prometteur.

Autologging change le comportement par defaut. Le tracking commence avant que le resultat interessant apparaisse.

Ce que fait vraiment autologging

MLflow propose un point d’entree generique, mlflow.autolog(), et des integrations specifiques comme mlflow.sklearn.autolog().

La fonction generique est utile lorsque tu veux activer largement les integrations supportees par MLflow :

import mlflow

mlflow.autolog()

Dans du code de production, je prefere souvent l’autologging specifique au framework, car l’intention est plus explicite :

import mlflow.sklearn

mlflow.sklearn.autolog()

Les donnees capturees dependent de la bibliotheque. Pour scikit-learn, MLflow peut loguer les parametres de l’estimator, les training scores, les modeles entraines, les model signatures, les input examples et les metadonnees de classe de l’estimator. Pour GridSearchCV et RandomizedSearchCV, MLflow cree aussi un parent run pour la recherche et des child runs imbriques pour les combinaisons de parametres.

Cette structure parent-child compte. Le tuning d’hyperparametres n’est pas une seule experience. C’est un ensemble controle d’experiences reliees. Autologging donne cette structure sans t’obliger a ecrire a la main la gestion des runs autour de chaque modele candidat.

Un exemple minimal zero configuration

Cet exemple utilise scikit-learn parce qu’il montre clairement le comportement. Le sujet n’est pas le modele. Le sujet est la surface de tracking.

import mlflow
import mlflow.sklearn
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import roc_auc_score
from sklearn.model_selection import train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

mlflow.set_tracking_uri("sqlite:///mlflow.db")
mlflow.set_experiment("autologging-baseline")

mlflow.sklearn.autolog()

X, y = load_breast_cancer(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

model = Pipeline(
    steps=[
        ("scaler", StandardScaler()),
        ("classifier", LogisticRegression(max_iter=1000, random_state=42)),
    ]
)

with mlflow.start_run(run_name="logistic-regression-baseline"):
    model.fit(X_train, y_train)

    probabilities = model.predict_proba(X_test)[:, 1]
    holdout_auc = roc_auc_score(y_test, probabilities)

    mlflow.log_metric("holdout_auc", holdout_auc)
    print(f"holdout_auc: {holdout_auc:.4f}")

La plupart du logging vient de mlflow.sklearn.autolog(). Le mlflow.log_metric("holdout_auc", ...) explicite reste utile parce que l’evaluation holdout est une decision de modelisation, pas quelque chose que l’integration peut toujours deduire correctement.

Le bon modele mental est donc simple : utilise autologging pour une capture large et repetable, puis ajoute du logging manuel pour les metriques business, les slices de donnees ou les regles de validation.

Recherche d’hyperparametres sans child runs manuels

La valeur devient plus evidente lorsque tu ajoutes une recherche de parametres.

import mlflow
import mlflow.sklearn
from sklearn.datasets import load_breast_cancer
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV, train_test_split
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

mlflow.set_tracking_uri("sqlite:///mlflow.db")
mlflow.set_experiment("autologging-grid-search")
mlflow.sklearn.autolog()

X, y = load_breast_cancer(return_X_y=True, as_frame=True)
X_train, X_test, y_train, y_test = train_test_split(
    X,
    y,
    test_size=0.2,
    random_state=42,
    stratify=y,
)

pipeline = Pipeline(
    steps=[
        ("scaler", StandardScaler()),
        ("classifier", LogisticRegression(max_iter=1000, random_state=42)),
    ]
)

search = GridSearchCV(
    estimator=pipeline,
    param_grid={
        "classifier__C": [0.01, 0.1, 1.0, 10.0],
        "classifier__solver": ["lbfgs"],
    },
    scoring="roc_auc",
    cv=3,
)

with mlflow.start_run(run_name="logistic-regression-grid-search"):
    search.fit(X_train, y_train)
    mlflow.log_metric("holdout_score", search.score(X_test, y_test))

Avec l’autologging scikit-learn active, le run de recherche enregistre la configuration de recherche, la meilleure combinaison de parametres, l’estimator de recherche entraine et les resultats de cross-validation. Les candidats apparaissent comme des child runs relies, pas comme une pile plate d’experiences sans relation.

C’est la difference entre tracking et archeologie. Six semaines plus tard, tu peux voir quelles combinaisons ont ete testees, laquelle a gagne et comment le modele choisi s’est comporte sur le holdout set.

Les bons reglages a choisir consciemment

Autologging reduit la friction, mais ce n’est pas magique. Il faut encore decider ce qui doit etre logue.

L’API generique mlflow.autolog() expose des controles comme :

import mlflow

mlflow.autolog(
    log_models=True,
    log_model_signatures=True,
    log_input_examples=True,
    log_datasets=True,
    disable_for_unsupported_versions=True,
    extra_tags={
        "team": "applied-ml",
        "project": "customer-risk",
    },
)

Ces options doivent etre traitees comme une policy.

Pour des experiences locales rapides, loguer les modeles et les input examples est utile. Pour des centaines de runs de tuning, loguer chaque modele peut devenir couteux et bruyant. Si les donnees contiennent des champs sensibles, le dataset logging et les input examples doivent etre revus avant d’etre actives sur un tracking server partage.

Le but n’est pas de tout activer pour toujours. Le but est d’avoir de bons defaults et de connaitre leurs limites.

La ou zero configuration s’arrete

Le tracking zero configuration est le plus fort lorsque le code d’entrainement suit le chemin normal d’une bibliotheque supportee. Il est plus faible lorsque le comportement important vit en dehors de la bibliotheque modele.

Exemples :

  • Une etape custom de feature generation change la population d’entrainement.
  • Un filtre de qualite de donnees retire un segment client.
  • Un threshold est choisi apres l’entrainement.
  • Une metrique de fairness, de latence ou de cout est calculee hors de l’estimator.
  • Une decision de production depend d’une regle business autour de la sortie du modele.

Autologging ne comprendra pas ces decisions si tu ne les logues pas.

C’est pourquoi le meilleur pattern n’est pas “autologging au lieu du logging manuel”. C’est “autologging d’abord, logging explicite la ou la logique business commence”.

with mlflow.start_run(run_name="risk-model-v3"):
    model.fit(X_train, y_train)

    mlflow.log_params(
        {
            "training_window_days": 180,
            "minimum_account_age_days": 30,
            "decision_threshold": 0.72,
        }
    )

    mlflow.log_metrics(
        {
            "holdout_auc": holdout_auc,
            "approval_rate": approval_rate,
            "manual_review_rate": manual_review_rate,
        }
    )

La bibliotheque modele peut capturer les internes de l’estimator. Les decisions systeme restent la responsabilite de l’equipe engineering.

Comment je l’utiliserais en equipe

Dans un workflow d’equipe, je mettrais autologging dans le template de projet.

  1. Definir la tracking URI et le nom d’experiment a la frontiere de l’application.
  2. Activer l’integration autologging specifique au framework pres du point d’entree d’entrainement.
  3. Utiliser des run names et tags explicites pour version de dataset, version de code, environnement et owner.
  4. Loguer manuellement les metriques business.
  5. Desactiver le model logging pour les grands sweeps si le stockage devient trop bruyant.
  6. Garder le model logging actif pour les finalistes qui peuvent etre enregistres ou deployes.
  7. Associer le run a un environnement verrouille, comme uv.lock, pour qu’il reste reproductible.

Cela donne le meme baseline aux contributeurs juniors et seniors. Personne n’a besoin de memoriser tous les appels MLflow avant de lancer une experience utile, mais l’equipe garde un endroit pour ajouter de la precision quand le projet devient serieux.

Le takeaway

MLflow autologging ne remplace pas le design d’experimentation. Il enleve la friction de la premiere couche de tracking.

C’est important, parce que c’est souvent la que les equipes echouent. Elles savent qu’elles doivent loguer les runs, mais le code de logging arrive tard, est copie de maniere incoherente ou est oublie pendant l’iteration rapide.

Avec mlflow.sklearn.autolog() ou mlflow.autolog(), le comportement par defaut change. Les parametres, metriques, artefacts modele, signatures et structures de recherche sont captures automatiquement lorsque l’integration le supporte. Le logging manuel devient alors plus cible : hypotheses de donnees, metriques business, thresholds, slices de validation et decisions de deploiement.

C’est une repartition saine du travail. Laisse MLflow capturer le comportement de la bibliotheque. Rends l’equipe engineering explicite sur le comportement produit.

Sources

Share