Romain Avouac (Insee), Thomas Faria (Insee), Tom Seimandi (Insee)
Difficulté de passer des expérimentations à la mise en production de modèle de machine learning
Tirer parti des meilleures pratiques en génie logiciel
Reproductibilité
Contrôle de version
Automatisation
Surveillance
Collaboration
De nombreux frameworks implémentent les principes du MLOps
Avantages de MLflow
:
1️⃣ Introduction à MLFlow
2️⃣ Un exemple concret: prédiction du code APE pour les entreprises
3️⃣ Servir un modèle de ML à des utilisateurs
4️⃣ Maintenance d’un modèle en production
5️⃣ Distribuer l’optimisation des hyperparamètres
Préparation de l’environnement de travail
Préparation de l’environnement de travail
Si ce n’est pas déjà fait, créez un compte Github
. Créez une copie du dépôt de la formation dans votre espace personnel en forkant le dépôt.
Si ce n’est pas déjà fait, créez un compte sur le SSP Cloud en utilisant votre adresse e-mail professionnelle.
Lancez un service MLflow
en cliquant sur cette URL.
Lancez un service VSCode-python
en cliquant sur cette URL.
Ouvrez le service VSCode-python
et saisissez le mot de passe du service.
Dans VSCode
, ouvrez un terminal et clonez le dépôt que vous venez de fork (modifiez les deux premières lignes) :
Installez les packages nécessaires pour la formation :
Vous êtes prêt !
Introduction aux concepts de MLflow
VSCode
, ouvrez le notebook situé à l’emplacement formation-mlops/notebooks/mlflow-introduction.ipynb
.MLflow
et essayez de créer vos propres expérimentations à partir du code d’exemple fourni dans le notebook. Par exemple, essayez d’ajouter d’autres hyperparamètres à la procédure de grid-search.MLflow
simplifie le suivi de l’entraînement de modèles
Code APE
A l’Insee, précédemment classifié par un algorithme basé sur des règles de décisions
Problématique commune à beaucoup d’Instituts nationaux de statistique
Modèle “sac de n-gram” : plongements lexicaux pour les mots mais aussi pour les n-gram de mots et de caractères
Un modèle très simple et rapide
OVA: One vs. All
Partie 1 : Utilisation d’un modèle personnalisé
src
. Consultez-les. En particulier, le script train.py
est responsable de l’entraînement du modèle. Quelles sont les principales différences avec l’application 1 ?MLflow
intègre le preprocessing ?Partie 2 : Des notebooks à un projet de type package
Le script train.py
est également responsable du logging des expérimentations dans MLFlow
. Notez la manière dont les paramètres de chaque expérimentation vont être passés à la fonction d’entraînement à l’appel du script.
Afin de rendre la procédure d’entraînement d’un modèle plus reproductible, MLFlow
met à disposition la commande mlflow run
. Le fichier MLproject
spécifie la commande et les paramètres qui vont lui être passées. Inspectez ce fichier.
Exécutez un entraînement du modèle à l’aide de MLFlow
. Pour ce faire, ouvrez un terminal (-> Terminal -> New Terminal
) et exécutez la commande suivante :
Dans l’interface de MLflow
, examinez les résultats de votre exécution précédente :
Experiments -> nace-prediction -> <nom_run>
Vous avez entraîné le modèle avec certains paramètres par défaut. Dans le fichier MLproject
, vérifiez les paramètres disponibles. Ré-entraînez un modèle avec différents paramètres (par exemple, dim = 25
).
MLflow
, comparez les 2 modèles en traçant la métrique accuracy par rapport à un paramètre que vous avez modifié (par exemple dim
)
Sélectionnez les 2 expériences -> Compare -> Scatter Plot -> Select your X and Y axis
fasttext
pour le rendre facilement interrogeable depuis Python
.Partie 3 : Requêtage du modèle entraîné en local
predict_mlflow.py
dans le dossier src
du projet. Ce script doit :
fasttext
["vendeur d'huitres", "boulanger"]
).💡 N’oubliez pas de lire la documentation de la fonction predict()
de la classe personnalisée (src/fasttext_wrapper.py
) pour comprendre le format attendu des entrées !
predict_mlflow.py
."COIFFEUR"
et "coiffeur, & 98789"
.k
et essayez de comprendre comment la structure de la sortie a changé en conséquence.MLflow
est polyvalent
MLproject
)Simplicité : porte d’entrée unique qui cache la complexité sous-jacente du modèle
Standardisation : requêtes HTTP -> agnostique au langage de programmation utilisé
Passage à l’échelle : adaptation à la charge de requêtes concurrentes
Modularité : séparation de la gestion du modèle et de sa mise à disposition
Conteneur : environnement autonome et isolé qui encapsule le modèle, l’API et leurs dépendances
Avantages :
Pré-requis technique pour déployer sur Kubernetes
Kubernetes
Partie 1 : exposer localement un modèle de ML en tant qu’API
app
. Consultez-les.export MLFLOW_MODEL_NAME="fasttext"
export MLFLOW_MODEL_VERSION=1
uvicorn app.main:app --root-path /proxy/8000
VSCode
./docs
à votre URL.Partie 2 : déploiement manuel d’un modèle de ML en tant qu’API
Dockerfile
pour voir comment l’image est construite. L’image est automatiquement reconstruite et publiée via Github Actions, si vous êtes intéressé, jetez un coup d’œil à .github/workflows/build_image.yml
. Dans le cadre de cette formation, nous allons tous utiliser cette même image.kubernetes/deployment.yml
et modifiez les lignes surlignées comme suit :deployment.yml
kubernetes/ingress.yml
et modifiez (deux fois) l’URL du point de terminaison de l’API pour qu’elle soit de la forme <votre_prénom>-<votre_nom>-api.lab.sspcloud.fr
.Kubernetes
contenus dans le dossier kubernetes/
dans un terminal pour déployer l’APIingress.yml
.MLFLOW_MODEL_NAME
ou MLFLOW_MODEL_VERSION
(si vous n’avez pas modifié le nom du modèle) dans le fichier deployment.yml
.Kubernetes
pour mettre à jour l’APIPartie 3 : déploiement continu d’un modèle de ML en tant qu’API
⚠️ Les précédentes applications doivent avoir été réalisées avec l’option Git pour pouvoir suivre celle-ci.
Précedement, vous avez déployé votre modèle manuellement. Grâce à ArgoCD
il est possible de déployer un modèle de manière continu, ainsi chaque modification d’un fichier présent dans le dossier kubernetes/
va entrainer le redéploiement automatique en se synchronisation avec votre dépôt Github. Pour vous en convaincre, suivez les étapes ci dessous :
Kubernetes
ne se superposent :ArgoCD
en cliquant sur cette URL. Ouvrez le service, saisissez l’identifiant (admin
) et le mot de passe du service.argocd/template-argocd.yml
et modifiez les lignes surlignées :template-argocd.yml
New App
puis Edit as a YAML
. Copiez-collez le contenu de argocd/template-argocd.yml
et cliquez sur Create
.ingress.yml
./docs
à votre URL.MLFLOW_MODEL_NAME
ou MLFLOW_MODEL_VERSION
(si vous n’avez pas modifié le nom du modèle) dans le fichier deployment.yml
.ArgoCD
synchronise automatiquement les changements depuis votre dépôt Github ou bien forcez la synchronisation. Rafraîchissez votre API et vérifiez sur la page d’accueil qu’elle est désormais basée sur la nouvelle version du modèle.Partie 4 : requêter votre modèle déployé
predict_api.py
. Ce script doit :
predict_api.py
import pandas as pd
import requests
# Fonction pour effectuer la requête à l'API
def make_prediction(api_url: str, description: str):
params = {"description": description, "nb_echoes_max": 2}
response = requests.get(api_url, params=params)
return response.json()
# URL des données
data_path = "https://minio.lab.sspcloud.fr/projet-formation/diffusion/mlops/data/data_to_classify.parquet"
# Charge le fichier Parquet dans un DataFrame pandas
df = pd.read_parquet(data_path)
# URL de l'API
api_url = "https://<your_firstname>-<your_lastname>-api.lab.sspcloud.fr/predict"
# Effectue les requêtes
responses = df["text"].apply(lambda x: make_prediction(api_url, x))
# Affiche le DataFrame avec les résultats des prédictions
print(pd.merge(df, pd.json_normalize(responses),
left_index=True,
right_index=True))
predict_api.py
.Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par "codification-api-..."
. Observez les logs.
Quelles informations détenez-vous ? Est-ce suffisant ?
Important
Nous avons ici réalisé une succession de requêtes GET car nous avons un seul point d’entrée vers notre API. Pour réaliser des requêtes en batch
il est préférable de réaliser des requêtes POST.
MLflow
est polyvalent
MLproject
)➡️ Communication essentielle entre les équipes pour contrôler le modèle en production
⚠️ Le mot surveillance d’une application/modèle a des définitions différentes en fonction de l’équipe où l’on se trouve.
Partie 1 : Logger des métriques métier
app/main.py
.main.py
Faites un commit de vos changements et poussez les sur votre dépôt distant.
Dès lors que vous réalisez un changement sur votre API, il est nécessaire de la redéployer pour que les changements soient effectifs. En théorie, il serait nécessaire de re-construire une nouvelle image pour notre API contenant les derniers ajustements. Pour simplifier, nous avons déjà construit les deux images avec et sans logs dans l’API. Jusqu’à présent vous avez utilisé l’image sans logs, redéployez votre API en utilisant l’image avec les logs dont le tag est logs
.
kubernetes/deployment.yml
, remplacer le tag no-logs
par le tag logs
:deployment.yml
Faites un commit de vos changements et poussez les sur votre dépôt distant.
Patientez 5 minutes qu’ArgoCD
synchronise automatiquement les changements depuis votre dépôt Github ou bien forcez la synchronisation.
predict-api.py
."codification-api-..."
. Observez les logs..parquet
.parquet
Partie 2 : Création d’un tableau de bord de monitoring
Nous allons utiliser Quarto Dashboards
qui fera partie de la version 1.4 de Quarto
. Téléchargez et installez la pre-release.
Ouvrez le fichier dashboard/index.qmd
et inspectez le code. Pour récupérer les données nécessaires à la création du tableau de bord, on utilise un SGBD serverless : DuckDB
. DuckDB
nous permet de faire des requêtes SQL
sur un fichier .parquet
contenant des logs parsés. Ce fichier contient une ligne par prédiction, avec les variables timestamp
, text
, prediction_1
, proba_1
, prediction_2
et proba_2
.
Pour visualiser le tableau de bord, entrez les commandes suivantes dans un Terminal
depuis la racine du projet et cliquez sur le lien généré.
Pour l’instant le pourcentage de prédictions avec une probabilité supérieure à 0.8 ne correspond pas à la réalité. Modifiez la requête SQL permettant d’obtenir la variable pct_predictions
pour afficher la bonne valeur.
daily_stats
pour afficher les bons graphiques.daily_stats = duckdb.sql(
"""
SELECT
CAST(timestamp AS DATE) AS date,
COUNT(*) AS n_liasses,
(
COUNT(
CASE WHEN data.proba_1 > 0.8 THEN 1 END
) * 100.0 / COUNT(*)
) AS pct_high_proba
FROM data
GROUP BY CAST(timestamp AS DATE);
"""
).to_df()
MLflow
est polyvalent
MLproject
)Kubernetes
.
apiVersion: argoproj.io/v1alpha1
kind: Workflow # nouveau type de spécification k8s
metadata:
generateName: hello-world- # nom de la spécification du workflow
spec:
entrypoint: whalesay # invoque le modèle whalesay
templates:
- name: whalesay # nom du modèle
container:
image: docker/whalesay
command: [ cowsay ]
args: [ "bonjour le monde" ]
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: hello-world-parameters-
spec:
entrypoint: whalesay
arguments:
parameters:
- name: message
value: bonjour le monde
templates:
- name: whalesay
inputs:
parameters:
- name: message # déclaration du paramètre
container:
image: docker/whalesay
command: [cowsay]
args: ["{{inputs.parameters.message}}"]
steps
ou dag
)apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: steps-
spec:
entrypoint: hello-hello-hello
# Cette spécification contient deux modèles : hello-hello-hello et whalesay
templates:
- name: hello-hello-hello
# Au lieu d'exécuter uniquement un conteneur
# Ce modèle a une séquence d'étapes
steps:
- - name: hello1 # hello1 est exécuté avant les étapes suivantes
template: whalesay
- - name: hello2a # double tiret => exécuté après l'étape précédente
template: whalesay
- name: hello2b # tiret simple => exécuté en parallèle avec l'étape précédente
template: whalesay
- name: whalesay # nom du modèle
container:
image: docker/whalesay
command: [ cowsay ]
args: [ "bonjour le monde" ]
Partie 1 : introduction à Argo Workflows
Argo Workflows
en cliquant sur cette URL. Ouvrez le service et saisissez le mot de passe du service (soit copié automatiquement, soit disponible dans le fichier README
du service).VSCode
, créez un fichier hello_world.yaml
à la racine du projet avec le contenu suivant :hello_world.yml
apiVersion: argoproj.io/v1alpha1
kind: Workflow
metadata:
generateName: hello-world-
labels:
workflows.argoproj.io/archive-strategy: "false"
annotations:
workflows.argoproj.io/description: |
Ceci est un exemple simple de "Hello World".
Vous pouvez également l'exécuter en Python : https://couler-proj.github.io/couler/examples/#hello-world
spec:
entrypoint: whalesay
templates:
- name: whalesay
container:
image: docker/whalesay:latest
command: [cowsay]
args: ["hello world"]
VSCode
:Argo Workflows
. Trouvez les logs du workflow que vous venez de lancer. Vous devriez voir le logo Docker .Partie 2 : distriubtion de l’optimisation des hyperparamètres
argo_workflows/workflow.yml
. Que pensez-vous qu’il se passera lorsque nous soumettrons ce flux de travail ?workflow.yml
MLflow
pour vérifier ce qui a été fait.Une introduction au MLOps avec MLflow
Comment surveiller un modèle en production ?