đ MLflow â Lifecycle, Tracking, Registry & MLOps
Guide complet IDEO-Lab sur la plateforme open-source de MLOps (Suivi, Projets, ModĂšles).
Concept : MLOps
Qu'est-ce que MLOps ? (DevOps pour le ML).
MLOps ML LifecycleLes 4 Composants
Tracking, Projects, Models, Registry.
Tracking Models RegistryArchitecture
Tracking Server, Backend Store, Artifact Store.
Architecture Tracking ServerTracking : Concepts
Experiment (Expérience), Run (Exécution).
Experiment RunTracking : Logging (API)
log_param, log_metric, log_artifact.
Tracking : Serveur
Local (file://) vs Distant (http://, databricks://).
Tracking : Autologging
mlflow.autolog() (Scikit-learn, TensorFlow...).
Outil : mlflow ui
L'interface Web (mlflow ui) (Comparaison de Runs).
API : start_run() (Contexte)
Utilisation de with mlflow.start_run():.
Projects : Concept (Reproductibilité)
Empaqueter le code (MLproject file).
Projects : Fichier MLproject
name, conda_env, docker_env, entry_points.
CLI : mlflow run
Exécuter un projet (local, ou git@...).
Models : Concept (Le "Format")
Le format ("flavor") universel (Agnostique).
Models FormatModels : Flavors (Saveurs)
python_function (pyfunc), scikit-learn, tensorflow...
API : log_model() (Sauvegarde)
Sauvegarder le modĂšle (model.pkl + MLmodel file).
Registry : Concept (Gouvernance)
Le "Git" des modĂšles (Gestion de versions).
Model Registry GouvernanceRegistry : Registered Model
Versions (v1, v2), Stage (Staging, Production, Archived).
Registry : Workflow (API/UI)
mlflow.register_model(), transition_model_version_stage().
Déploiement : serve
mlflow models serve (API REST locale).
Déploiement : pyfunc.load_model
Charger (load_model) et Prédire (.predict()).
ĂcosystĂšme : Databricks
Intégration native (HÎte managé pour Tracking & Registry).
Databricks IntégrationMLOps (DevOps pour le Machine Learning)
MLOps est une culture (comme DevOps) qui vise Ă industrialiser (mettre en production) et maintenir le cycle de vie du Machine Learning de maniĂšre fiable et reproductible.
Le ProblĂšme (Sans MLOps)
Le ML est "expérimental". Un Data Scientist peut avoir 50 "Notebooks" (Jupyter) avec des noms comme test_v2_final.ipynb, test_v3_final_CORRECTED.ipynb.
ProblĂšmes :
- Reproductibilité : Impossible de savoir quels "hyperparamÚtres" (inputs) ont produit le "meilleur modÚle" (output).
- Déploiement : Comment transformer ce
.ipynben une API REST fiable ? - Gouvernance : Quelle version du modĂšle tourne en Production ?
Solution : Apache MLflow
MLflow (créé par Databricks, 100% open-source) est une plateforme agnostique (elle fonctionne avec Scikit-learn, TensorFlow, PyTorch, R...) pour gérer le cycle de vie (lifecycle) complet du ML.
Les 4 Piliers (Composants)
MLflow est divisĂ© en 4 composants (qui peuvent ĂȘtre utilisĂ©s ensemble ou sĂ©parĂ©ment) :
- MLflow Tracking (2.1) : (Le CĆur) L'API/UI pour enregistrer (logger) les expĂ©riences (paramĂštres, mĂ©triques).
- MLflow Projects (4.1) : (Reproductibilité) Un format (
MLproject) pour empaqueter (package) le code (avec ses dépendancesconda/docker). - MLflow Models (5.1) : (Format) Un format "standard" (
MLmodel) pour sauvegarder les modÚles. - MLflow Model Registry (6.1) : (Gouvernance) Un registre (catalogue) centralisé pour gérer les versions de modÚles (Staging, Production).
| Composant | Objectif (ProblÚme Résolu) | Artefacts Clés |
|---|---|---|
| MLflow Tracking | Reproductibilité (Expériences). (Quels paramÚtres ont donné quel score ?). | Run (Exécution), Métriques, ParamÚtres, UI (Comparaison). |
| MLflow Projects | Reproductibilité (Exécution). (Comment ré-exécuter ce code sur une autre machine ?). | MLproject (Fichier YAML), conda.yaml, docker_env. |
| MLflow Models | Portabilité (Format). (Comment packager ce modÚle (Scikit) pour qu'il soit lisible (ex: par Spark) ?). | MLmodel (Fichier YAML), Flavors (pyfunc). |
| MLflow Model Registry | Gouvernance (DĂ©ploiement). (Quelle version (v5) est en "Production" ? Laquelle est en "Staging" ?). | Registered Model, Versions, Stages (Ătapes). |
L'architecture de MLflow Tracking (le cĆur) sĂ©pare les MĂ©tadonnĂ©es (Backend) des Fichiers (Artifacts).
(Data Scientist 1)
(mlflow.log_param(...))
â
â (API REST)
âŒ
[ MLFLOW TRACKING SERVER (Serveur) ]
(ex: mlflow server --host 0.0.0.0)
â
â
(Ăcrit MĂ©tadonnĂ©es : Param/Metrics)
â
âŒ
[ 1. BACKEND STORE ]
(ex: BDD (Postgres, MySQL)
ou 'file:/path/mlruns')
â
â
(Ăcrit Fichiers : ModĂšles/Images)
â
âŒ
[ 2. ARTIFACT STORE ]
(ex: S3, ADLS, GCS, HDFS
ou '/path/mlartifacts')
- Tracking Server : Le serveur (service) qui expose l'API REST et l'UI Web.
- Backend Store : (La "BDD") Stocke les MĂ©tadonnĂ©es (Params, Metrics, Tags, Runs). (Peut ĂȘtre
file:(local) oupostgresql://...(Prod)). - Artifact Store : (Le "Disque Dur") Stocke les Artefacts (gros fichiers) (ex: le
model.pkl,graph.png). (Peut ĂȘtrefile:(local) ous3://...(Prod)).
MLflow Tracking organise le travail (similaire Ă un "commit Git").
1. Experiment (Expérience)
C'est le "Dossier" (le "Projet") qui regroupe les exĂ©cutions (Runs) d'un mĂȘme problĂšme.
Exemple : "Prédiction Churn ClientÚle", "Classification d'Images".
Une "Experiment" a un ID (experiment_id) et un Nom.
2. Run (Exécution)
C'est l'"Exécution" (le "Commit"). C'est 1 seule exécution de votre script d'entraßnement (train.py).
Un "Run" (avec un run_id unique) contient :
Parameters (ParamĂštres): Les Inputs (HyperparamĂštres) (ex:learning_rate=0.01,n_estimators=100).Metrics (MĂ©triques): Les Outputs (Scores) (ex:accuracy=0.92,loss=0.15). (Peuvent ĂȘtre loggĂ©s (tracĂ©s) dans le temps (Epochs)).Artifacts (Artefacts): Les Fichiers (Outputs) (gros objets) (ex:model.pkl,confusion_matrix.png,features.txt).Tags (Tags): MĂ©tadonnĂ©es (ex:git_commit,user).
Exemple de "logging" (enregistrement) manuel d'un Run (exécution) depuis un script Python.
import mlflow
# 1. (Optionnel) Définir le serveur de suivi
# (Si omis, logge localement dans ./mlruns)
mlflow.set_tracking_uri("http://mon-serveur-mlflow:5000")
# 2. Définir l'Expérience (Projet)
mlflow.set_experiment("Prediction_Ventes_Decembre")
# 3. Démarrer un nouveau Run (Exécution)
# (Utiliser 'with' est la bonne pratique)
with mlflow.start_run(run_name="Run_RandomForest_v1") as run:
# (Logguer le 'run_id')
print(f"Run ID: {run.info.run_id}")
# 4. Logger les Inputs (HyperparamĂštres)
learning_rate = 0.01
n_estimators = 100
mlflow.log_param("learning_rate", learning_rate)
mlflow.log_param("n_estimators", n_estimators)
# (... (Code d'entraĂźnement du modĂšle) ...)
# model = ...
# 5. Logger les Outputs (Métriques/Scores)
accuracy = 0.92
loss = 0.15
mlflow.log_metric("accuracy", accuracy)
mlflow.log_metric("loss", loss)
# (Logger une métrique sur la durée (ex: epochs))
for epoch in range(10):
mlflow.log_metric("epoch_loss", loss_par_epoch, step=epoch)
# 6. Logger les Fichiers (Artefacts)
# (Sauvegarder un fichier texte)
mlflow.log_text("feature_list.txt", "feature1, feature2")
# (Sauvegarder une image (ex: matplotlib))
mlflow.log_figure(fig, "confusion_matrix.png")
# (Sauvegarder le ModĂšle (voir 5.3))
mlflow.sklearn.log_model(model, "model_sklearn")
# (Le Run est 'Terminé' (FINISHED) à la fin du 'with')
Mode 1 : Local (file://)
C'est le mode par défaut si vous ne configurez rien.
Action : MLflow crée un dossier ./mlruns (dans votre dossier local) à cÎté de votre script.
- Backend Store :
./mlruns(Fichiers) - Artifact Store :
./mlruns/[experiment_id]/[run_id]/artifacts/
Usage : Développement rapide, tests locaux.
Inconvénient : Ne fonctionne pas pour le travail d'équipe (les logs sont sur votre PC).
Mode 2 : Distant (http://) (Production)
C'est le mode "Production" (centralisé).
Architecture :
- (Admin) Déploie un serveur (VM/Container).
- (Admin) Installe une BDD (ex: Postgres) (pour le "Backend Store").
- (Admin) Crée un Bucket (ex: S3, ADLS) (pour l'"Artifact Store").
- (Admin) Lance le Serveur de Suivi (Tracking Server) :
$ mlflow server \ --host 0.0.0.0 \ --port 5000 \ --backend-store-uri postgresql://... \ --default-artifact-root s3://mon-bucket-mlflow/ - (Data Scientist) Configure son client (variable d'env) :
$ export MLFLOW_TRACKING_URI="http://[IP_SERVEUR]:5000" $ python train.py
Résultat : Toutes les expériences (de toute l'équipe) sont centralisées (BDD) et les artefacts (modÚles) sont stockés (S3).
Le "logging" manuel (2.2) (log_param, log_metric) est verbeux.
Autologging (mlflow.autolog()) est une fonctionnalité "magique" qui s'accroche (hooks) aux librairies ML populaires (Scikit-learn, TensorFlow, PyTorch...) et enregistre automatiquement tout (Params, Metrics, ModÚle).
import mlflow
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score
# (Données X_train, y_train...)
# 1. Activer l'Autolog (AVANT 'fit')
mlflow.sklearn.autolog()
with mlflow.start_run() as run:
# 2. Définir le modÚle
rf = RandomForestClassifier(
n_estimators=100,
max_depth=5
)
# 3. EntraĂźner
rf.fit(X_train, y_train) # <--- Magie ici
# 4. Prédire
preds = rf.predict(X_test)
accuracy = accuracy_score(y_test, preds)
# 5. (Logguer la métrique finale)
mlflow.log_metric("accuracy", accuracy)
# --- RĂSULTAT (Automatique) ---
# MLflow a AUTOMATIQUEMENT loggué :
# Params: { n_estimators: 100, max_depth: 5, ... }
# Metrics: { training_accuracy: 0.95, ... }
# Artifacts: { model: (le model.pkl), ... }
mlflow ui (Interface Web)mlflow ui est l'interface web (locale) pour visualiser les résultats (Runs) loggés par MLflow Tracking.
Usage (Mode Local)
Si vous avez loggé localement (Mode 1 - ./mlruns), vous pouvez lancer l'UI :
# (Lance l'UI Web sur http://127.0.0.1:5000) $ mlflow ui # (ou, si le backend/artifact est distant) $ mlflow ui --backend-store-uri ... --default-artifact-root ...
Fonctionnalités (UI)
- Vue (Experiment) : Liste tous les "Runs" (lignes) avec les "Params" et "Metrics" (colonnes).
- Tri & Filtre : "Trier par
accuracy(DESC)", "Filtrern_estimators = 100". - Comparaison (Compare) : (Le plus puissant) Sélectionner 2 (ou N) "Runs" pour les comparer (visualiser les différences de Params/Metrics, Graphes...).
- Vue (Run) : Voir les détails (Artefacts (
model.pkl), Tags...).
mlflow.start_run() (Contexte)Il y a deux façons de gérer un "Run" (Exécution) :
1. Manuel (start_run / end_run)
# (Approche "Legacy" / Manuelle)
try:
mlflow.start_run()
mlflow.log_param("p1", 1)
# (Si le code crashe ici...)
if (error):
raise Exception("Oups")
mlflow.log_metric("m1", 0.9)
mlflow.end_run(status="FINISHED")
except Exception as e:
# (Le run reste 'RUNNING' (Actif)
# si on ne le ferme pas manuellement)
mlflow.end_run(status="FAILED")
2. Contexte (with ... as ...) (Python)
L'utilisation du "Context Manager" (with) est la meilleure pratique (plus propre et plus sûre).
# (Le 'with' gĂšre le try/except/finally)
try:
with mlflow.start_run(run_name="Mon Run") as run:
mlflow.log_param("p1", 1)
if (error):
raise Exception("Oups") # (Déclenche une exception)
mlflow.log_metric("m1", 0.9)
# (Si le 'with' se termine SANS exception,
# MLflow met le statut Ă 'FINISHED')
except Exception as e:
# (Si le 'with' se termine AVEC une exception,
# MLflow met le statut Ă 'FAILED')
print("Run a échoué.")
MLflow Projects est une convention (un standard) pour empaqueter (packager) du code (Data Science) afin de le rendre reproductible.
Le ProblĂšme
Un Data Scientist (Alice) vous envoie son script train.py (et un Run ID MLflow). Vous (Bob) essayez de le lancer (python train.py).
Ăchec : "ModuleNotFoundError: No module named 'tensorflow'".
(Bob n'a pas le bon conda env, les bonnes versions de libs, ou les bons paramÚtres qu'Alice a utilisés).
Solution (MLproject)
Un "MLflow Project" est un dossier (ou un dépÎt Git) qui contient :
- Le Code (ex:
train.py). - Un Fichier
MLproject(4.2) : (Le "manifeste") Définit les "points d'entrée" (main) et les commandes. - Un Fichier d'Environnement (ex:
conda.yaml) : (Le "lockfile") Définit les dépendances (tensorflow==2.10,scikit-learn==1.2).
(Voir 4.3) Bob n'exécute plus python train.py. Il exécute mlflow run .... MLflow lit conda.yaml, crée l'environnement (isolé), puis exécute le code (reproductible).
MLproject (Le Manifeste)Le fichier MLproject (un YAML à la racine du projet) définit les points d'entrée (entry points).
# Fichier: MLproject (YAML)
# (Nom du projet)
name: MonProjetExample
# (Environnement requis)
# (Peut ĂȘtre 'conda.yaml', 'python_env.yaml'
# ou 'docker_env')
conda_env: conda.yaml
# (Points d'entrée = commandes 'exec')
entry_points:
# (Point d'entrée 'main')
main:
# (ParamĂštres attendus)
parameters:
data_file: {type: string, default: "data.csv"}
learning_rate: {type: float, default: 0.01}
# (La commande à exécuter)
command: "python train.py --data {data_file} --lr {learning_rate}"
# (Point d'entrée 'validate')
validate:
command: "python validate.py"
mlflow runLa commande mlflow run est l'exécuteur de "MLflow Projects" (4.1).
Flux d'Exécution (mlflow run ...)
mlflow run . -e main -P learning_rate=0.05- MLflow lit
MLproject(4.2). - Il lit
conda.yaml(défini dansMLproject). - Il crée un environnement
conda(isolé) (ex:./mlflow-env/) et installe les dépendances (tensorflow...). - Il active l'environnement
conda. - Il exécute la
command:du point d'entrée "main" (en passant les-P).python train.py --data data.csv --lr 0.05
Exécution (DépÎt Git)
mlflow run peut exécuter un projet directement depuis Git (pour la reprod.) :
# (Clone le dépÎt, crée l'env, exécute)
$ mlflow run https://github.com/mon-repo/mon-projet-ml \
--version main \
-P alpha=0.5
MLflow Models est une convention (un format standard) pour empaqueter (packager) un modĂšle ML (issu de n'importe quel framework) afin qu'il puisse ĂȘtre rĂ©utilisĂ© (ex: servi en API REST, chargĂ© dans Spark).
Le Dossier "ModĂšle"
Un "ModĂšle MLflow" n'est pas 1 fichier. C'est un dossier qui contient :
MLmodel(Le Manifeste) : Un fichierYAML(crucial) qui définit le modÚle, ses "Flavors" (5.2), et ses dépendances (conda.yaml).- Les Fichiers du ModÚle : (ex:
model.pkl(Scikit),saved_model.pb(TensorFlow)). conda.yaml: L'environnement exact (dépendances) requis pour *exécuter* ce modÚle.
Les "Flavors" (Saveurs) sont la clĂ© du format MLmodel (5.1). Elles dĂ©crivent les diffĂ©rentes façons dont ce modĂšle peut ĂȘtre compris (chargĂ©).
Exemple (Fichier MLmodel d'un modĂšle Scikit-learn)
# Fichier: /.../mon-modele/MLmodel (YAML)
artifact_path: model_sklearn
flavors:
# Flavor 1 : "scikit-learn" (Natif)
# (Sait qu'il faut utiliser 'pickle.load()')
sklearn:
pickled_model: model.pkl
sklearn_version: 1.2.0
# Flavor 2 : "python_function" (pyfunc) (Générique)
# (Le "wrapper" universel)
python_function:
loader_module: mlflow.sklearn
python_version: 3.9
env: conda.yaml
# Dépendances requises pour exécuter ce modÚle
conda_env: conda.yaml
Le "Flavor" pyfunc (Le plus important)
python_function (pyfunc) est le "format universel". Il garantit que *n'importe quel* modĂšle (Scikit, TF, PyTorch) expose la mĂȘme API (signature) : une fonction .predict(dataframe).
Usage : Permet au MLflow Model Server (7.1) de servir (API REST) n'importe quel type de modĂšle, sans connaĂźtre sa technologie sous-jacente.
log_model() (Sauvegarde)L'API log_model() (ex: mlflow.sklearn.log_model) est la fonction (utilisée dans un "Run" (2.2)) qui crée le Dossier ModÚle (5.1) (MLmodel, conda.yaml, model.pkl) et l'enregistre (upload) dans l'Artifact Store (1.3).
import mlflow.sklearn
from sklearn.ensemble import RandomForestClassifier
# (EntraĂźner le modĂšle)
model = RandomForestClassifier()
model.fit(X_train, y_train)
# (Commencer un Run)
with mlflow.start_run() as run:
# ... (log_param, log_metric) ...
# 1. Sauvegarder (Logguer) le ModĂšle
mlflow.sklearn.log_model(
sk_model = model,
# (Nom du dossier dans les "Artifacts")
artifact_path = "model_rf",
# (Optionnel) (Enregistre aussi
# le 'conda.yaml' actuel)
conda_env = "conda.yaml"
)
run_id = run.info.run_id
# (Résultat : Le modÚle est dans
# s3://.../[exp_id]/[run_id]/artifacts/model_rf/)
ProblÚme : MLflow Tracking (2.1) est un "chaos" (des milliers de "Runs" expérimentaux). Comment savoir quel "Run" (ex: run_id=abc123) est le meilleur, et lequel est actuellement utilisé en Production ?
Solution : MLflow Model Registry (Registre)
Le Model Registry (Registre de ModÚles) est le systÚme de gouvernance (Dev -> Staging -> Prod) de MLflow. C'est le "catalogue" centralisé des modÚles "promus" (approuvés).
Il nécessite un Tracking Server (2.3) distant (ex: Postgres + S3). (Ne fonctionne pas avec file://).
Workflow (Conceptuel)
- (Data Scientist) Exécute 100 "Runs" (Tracking).
- (DS) (UI) Trouve le "Run" (
abc123) (Meilleur score). - (DS) (UI) Clique "Register Model" (Enregistrer). (Crée
Modele_A,Version 1). - (Manager) (UI) Reçoit une demande, valide, et passe
Version 1au "Stage" (Ătape) "Staging". - (CI/CD) Le systĂšme (ex: Jenkins) dĂ©ploie automatiquement la
Version 1(Staging). - (Manager) (UI) Valide les tests, et passe
Version 1au "Stage" "Production".
Registered Model, Version, StageLe Registre (Registry) utilise 3 objets :
[ 1. Registered Model ] (ex: "Prediction_Churn")
(Le "Nom" du modĂšle)
â
ââ [ 2. Version 1 ] (ex: 'run_id=abc123')
â (Stage: "Archived")
â
ââ [ 2. Version 2 ] (ex: 'run_id=def456')
â (Stage: "Staging")
â
ââ [ 2. Version 3 ] (ex: 'run_id=ghi789')
(Stage: "Production")
- 1. Registered Model (ModÚle Enregistré) : Le "nom" unique (global) du modÚle (ex: "Prediction_Churn").
- 2. Version : Un "snapshot" (pointeur) vers un
Run ID (2.1)(Tracking) spĂ©cifique. (ex: "Version 1", "Version 2"...). - 3. Stage (Ătape) : (Legacy) Une "Ă©tiquette" (Tag) assignĂ©e Ă une Version (
Staging,Production,Archived).
Note : Les "Stages" (Production/Staging) sont obsolĂštes (deprecated) au profit des "Tags" (key=value) et des "Aliases" (Pointeurs) (plus flexibles).
1. Enregistrer un ModĂšle (Tracking -> Registry)
Lier un "Run" (Tracking) Ă un "Nom" (Registry).
(Python)
# (Option A : En 1 fois, pendant le 'log_model')
with mlflow.start_run() as run:
mlflow.sklearn.log_model(
model,
"model",
# (Crée "Version 1" de "MonModele")
registered_model_name="MonModele"
)
# (Option B : AprĂšs le Run)
run_id = "abc123..."
model_uri = f"runs:/{run_id}/model"
mlflow.register_model(model_uri, "MonModele")
2. Promouvoir un ModĂšle (Staging/Prod)
(Python)
client = mlflow.tracking.MlflowClient()
# (Passer la "Version 5" du modĂšle en "Production")
client.transition_model_version_stage(
name="MonModele",
version=5,
stage="Production"
)
mlflow models serveMLflow inclut un serveur web (REST API) (basé sur Flask) intégré, pour le prototypage rapide (non-recommandé pour la haute performance en production).
Il sert (sert) n'importe quel modÚle (loggé) qui a un "Flavor" pyfunc (5.2).
# (Syntaxe)
mlflow models serve -m [URI_MODELE] -p [PORT]
# 1. Servir un modĂšle depuis un "Run"
$ mlflow models serve \
-m "runs:/[run_id]/model_rf" \
-p 5001
# 2. Servir un modĂšle depuis le "Registry" (Prod)
$ mlflow models serve \
-m "models:/MonModele/Production" \
-p 5001
# (Le serveur démarre sur http://127.0.0.1:5001)
# 3. RequĂȘter (POST /invocations)
$ curl http://127.0.0.1:5001/invocations \
-H 'Content-Type: application/json' \
-d '{"dataframe_split": {"columns": ["col1"], "data": [[1.0]]}}'
pyfunc.load_model (API Custom)Pour la production (haute performance), au lieu d'utiliser mlflow models serve, on utilise mlflow.pyfunc.load_model à l'intérieur de notre propre serveur web (ex: FastAPI, Flask + Gunicorn).
Exemple (API FastAPI + MLflow)
import mlflow
import pandas as pd
from fastapi import FastAPI
# 1. Définir l'URI du modÚle (Production)
model_uri = "models:/MonModele/Production"
# 2. Charger le modÚle (pyfunc) au démarrage
# (MLflow gĂšre (conda) l'environnement)
model = mlflow.pyfunc.load_model(model_uri)
app = FastAPI()
@app.post("/predict")
def predict(data: dict):
# (data = {"col1": [1.0], "col2": [0.5]})
# 3. Convertir en DataFrame
df = pd.DataFrame(data)
# 4. Prédire
predictions = model.predict(df)
return {"predictions": predictions.tolist()}
Databricks (fondateur de MLflow) est la plateforme managée (SaaS) pour MLflow. Elle fournit une version "HÎte" (Hosted) et intégrée de MLflow.
| CritÚre | MLflow Open Source (DIY) | MLflow sur Databricks (Managé) |
|---|---|---|
| Tracking Server | Manuel (VM, BDD, S3, Sécurité). | Automatique (Intégré à chaque Workspace). |
| Model Registry | Manuel (Installation BDD...). | Automatique (Intégré, UI améliorée, ACLs). |
| UI (Interface) | mlflow ui (Basique). | Intégrée (Rich UI, Comparaison avancée, Notebooks). |
| Déploiement | mlflow models serve (Basique). | "Serverless Real-Time Inference" (Managé, Auto-scale). |
| Autologging | Manuel (mlflow.autolog()). | Automatique (Activé par défaut dans les Notebooks ML). |
