Données utilisées
De l’expérimentation à la production
@@ -825,71 +840,42 @@De l’expérimentation à la production
Application 2
-Partie 1 : Des notebooks à un projet de type package
+Partie 1 : Utilisation d’un modèle personnalisé
-
-
Lancez un service
VSCode
en cliquant sur cette URL. Ouvrez le service et saisissez le mot de passe du service.
-Tous les scripts liés à notre modèle personnalisé sont stockés dans le dossier
src
. Consultez-les. Regardez également le fichierMLproject
.
-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
).
-
-Cliquez pour voir la commande -
- --
-
- Dans
MLflow
, comparez les 2 modèles en traçant l’exactitude par rapport à un paramètre que vous avez modifié (par exempledim
) --
-
Sélectionnez les 2 expériences -> Compare -> Scatter Plot -> Select your X and Y axis
-
+ - Tous les scripts liés à notre modèle personnalisé sont stockés dans le dossier
src
. Consultez-les. En particulier, le scripttrain.py
est responsable de l’entraînement du modèle. Quelles sont les principales différences avec l’application 1 ?
+ - Pourquoi pouvons-nous dire que le modèle
MLflow
intègre le preprocessing ?
Application 2
+Partie 1 : Des notebooks à un projet de type package
+Partie 2 : Des notebooks à un projet de type package
-
-
Lancez un service
VSCode
en cliquant sur cette URL. Ouvrez le service et saisissez le mot de passe du service.
-Dans VSCode, ouvrez un terminal (
-> Terminal -> New Terminal
) et réalisez les étapes 6 et 7 de l’application 0 (clone et installation de packages).
-Tous les scripts liés à notre modèle personnalisé sont stockés dans le dossier
src
. Consultez-les. Regardez également le fichierMLproject
.
-Exécutez un entraînement du modèle à l’aide de MLflow. Dans un terminal, exécutez la commande suivante :
-
+Le script
train.py
est également responsable du logging des expérimentations dansMLFlow
. 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 commandemlflow run
. Le fichierMLproject
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_experience>
+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
).
Application 2
mlflow run ~/work/formation-mlops/ --env-manager=local \
- -P remote_server_uri=$MLFLOW_TRACKING_URI \
- -P experiment_name=$MLFLOW_EXPERIMENT_NAME \
- -P dim=25
mlflow run ~/work/formation-mlops/ --env-manager=local \
+ -P remote_server_uri=$MLFLOW_TRACKING_URI \
+ -P experiment_name=$MLFLOW_EXPERIMENT_NAME \
+ -P dim=25
-
-
- Dans
MLflow
, comparez les 2 modèles en traçant l’exactitude par rapport à un paramètre que vous avez modifié (par exempledim
) +-
+
- Dans
MLflow
, comparez les 2 modèles en traçant la métrique accuracy par rapport à un paramètre que vous avez modifié (par exempledim
)Sélectionnez les 2 expériences -> Compare -> Scatter Plot -> Select your X and Y axis
+ - Enregistrez le modèle avec la meilleure accuracy en tant que
fasttext
pour le rendre facilement interrogeable depuisPython
.
- Dans
Application 2
Partie 2 : Distribution et interrogation d’un modèle personnalisé
+Partie 3 : Requêtage du modèle entraîné en local
-
-
- Explorez attentivement le fichier
src/train.py
. Quelles sont les principales différences avec l’application 1 ?
- - Pourquoi pouvons-nous dire que le modèle
MLflow
intègre le preprocessing ?
- - Dans
MLflow
, enregistrez votre dernier modèle en tant quefasttext
pour le rendre facilement interrogeable depuis l’APIPython
. - Créez un script
predict_mlflow.py
dans le dossiersrc
du projet. Ce script doit :- Charger la version 1 du modèle
fasttext
@@ -944,31 +925,31 @@
Application 2
predict_mlflow.py
- Charger la version 1 du modèle
-
+
- Exécutez votre script
predict_mlflow.py
. - Assurez-vous que les deux descriptions suivantes donnent la même prédiction principale :
"COIFFEUR"
et"coiffeur, & 98789"
. - Modifiez la valeur du paramètre
k
et essayez de comprendre comment la structure de la sortie a changé en conséquence.
Cliquez pour voir la commande
- +-
+
Application 2
Bilan
+-
+
MLflow
est polyvalent +-
+
- Utilisation dee frameworks custom (modulo une classe “interface”) +
- Industrialisation de l’entraînement (fichier
MLproject
)
+ - Requêtage simple des modèles entraînés et stockés +
+- Limite : le modèle entraîné n’est pas accessible
+
-
+
- Requêtage simplifié… mais format non-pertinent pour tous les utilisateurs +
- Le modèle n’est pas déployé +
+
3️⃣ Déployer un modèle ML via une API
+3️⃣ Servir un modèle de ML à des utilisateurs
Mise en service du modèle
-
-
- Une fois qu’un modèle de machine learning a été développé, il doit être déployé pour servir ses utilisateurs finaux. +
- Une fois qu’un modèle de machine learning a été développé, il doit servir ses utilisateurs finaux.
-
-
- Quelle est l’infrastructure de production ? -
- Qui sont les utilisateurs finaux ? +
- Quel format pertinent pour rendre accessible aux utilisateurs finaux ?
- Traitement par lots (batch) par rapport au traitement en ligne (online) +
- Quelle infrastructure pour le de déploiement ?
Configuration standard
+Configuration envisagée
-
-
Infrastructure de production : cluster Kubernetes
-Le modèle peut servir diverses applications
+- Le modèle peut servir diverses applications
- Rendre le modèle accessible via une API
- Traitement en ligne (online serving)
+- Traitement en ligne (online serving)
- Les applications client envoient une requête à l’API et reçoivent une réponse rapide
+ - Infrastructure de déploiement : cluster Kubernetes
Exposer un modèle via une API
+Pourquoi exposer un modèle via une API REST ?
+-
+
Simplicité : porte d’entrée unique qui cache la complexité sous-jacente du modèle
+Standardisation : requêtes HTTP, agnostiques 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
+
Exposer un modèle via une API
+Exécuter une API dans un conteneur
Conteneur : environnement autonome et isolé qui encapsule le modèle, ses dépendances et le code de l’API
-Les conteneurs offrent une grande portabilité et scalabilité pour distribuer le modèle de manière efficace.
-Le fichier
Dockerfile
est utilisé pour configurer et construire le conteneur Docker.
+Avantages : portabilité et scalabilité pour distribuer le modèle de manière efficace
Développement avec l’architecture Docker
-Déploiement d’une API sur Kubernetes
-
--
-
- 3 fichiers principaux sont nécessaires pour déployer une API :
-
-
-
deployment.yaml
: définit le fonctionnement de l’API (image du conteneur, ressources et variables d’environnement)
-service.yaml
: établit un point de terminaison réseau interne stable pour l’API.
-ingress.yaml
: fournit un point d’entrée pour les clients externes afin d’accéder à l’API.
-
-
Application 3
Application 3
deployment.yml
- Ouvrez le fichier
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
. - Appliquez les trois contrats
Kubernetes
contenus dans le dossierkubernetes/
dans un terminal pour déployer l’API
- Accédez à votre API en utilisant l’URL définie dans votre fichier
ingress.yml
. - Affichez la documentation de votre API en ajoutant
/docs
à votre URL.
@@ -1097,7 +1087,7 @@ - Ajustez votre variable d’environnement
MLFLOW_MODEL_NAME
ouMLFLOW_MODEL_VERSION
(si vous n’avez pas modifié le nom du modèle) dans le fichierdeployment.yml
. - Appliquez les nouveaux contrats
Kubernetes
pour mettre à jour l’API
Application 3
- 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.
Application 3
Application 3
template-argocd.yml
- Dans ArgoCD, cliquez sur
New App
puisEdit as a YAML
. Copiez-collez le contenu deargocd/template-argocd.yml
et cliquez surCreate
.
@@ -1165,12 +1155,12 @@
Application 3
4️⃣ Décentraliser l’optimisation des hyperparamètres
+4️⃣ Distribuer l’optimisation des hyperparamètres
Entraînement parallèle
+Entraînement distribué
- Avec notre configuration, nous pouvons entraîner des modèles un par un et enregistrer toutes les informations pertinentes sur le serveur MLflow Tracking.
- Et si nous voulions entraîner plusieurs modèles en même temps, par exemple pour optimiser les hyperparamètres ? @@ -1207,18 +1197,18 @@
Argo workflows
Bonjour le monde
-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 # 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" ]
Que se passe-t-il ?
@@ -1252,26 +1242,26 @@Paramètres
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}}"]
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}}"]
Workflows à plusieurs étapes
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" ]
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" ]
Application 4
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"]
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"]
- Soumettez le workflow “Hello World” via un terminal dans
VSCode
:
- Ouvrez l’interface utilisateur d’
Argo Workflows
. Trouvez les logs du workflow que vous venez de lancer. Vous devriez voir le logo Docker .
Application 4
workflow.yml
- Soumettez le flux de travail et observez les tâches s’exécuter en direct dans l’interface utilisateur. @@ -1455,7 +1445,7 @@
- Une fois que toutes les tâches sont terminées, visualisez les logs de l’ensemble du flux de travail. @@ -1485,7 +1475,7 @@
- Lire le fichier parquet disponible à l’adresse suivante :
- Effectuer des requêtes à votre API pour chaque libellé présent dans le fichier parquet.
- Afficher le résultats des prédictions @@ -1499,33 +1489,33 @@
Application 4
Application 5
Application 5
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)
-
-# Votre API URL
-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))
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)
+
+# Votre API URL
+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))
-
@@ -1535,7 +1525,7 @@
Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par
"codification-api-..."
. Observez les logs.
@@ -1653,7 +1643,7 @@
Application 5
Application 5
main.py
- Définissez la configuration de vos logs avant la définition de votre premier point d’entrée : @@ -1662,14 +1652,14 @@
Application 5
main.py
- Ajoutez une le libellé et la réponse de l’API dans vos logs : @@ -1678,8 +1668,8 @@
Application 5
main.py
Faites un commit de vos changements et poussez les sur votre dépôt distant.
@@ -1719,7 +1709,7 @@ - Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par
"codification-api-..."
. Observez les logs.
@@ -1762,27 +1752,27 @@ Nous allons utiliser
-Quarto Dashboards
qui fera partie de la version 1.4 deQuarto
. 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êtesSQL
sur un fichier.parquet
contenant des logs parsés. Ce fichier contient une ligne par prédiction, avec les variablestimestamp
,text
,prediction_1
,proba_1
,prediction_2
etproba_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.- Les deux graphiques situés en bas du tableau de bord ne sont pas corrects non plus. Modifiez la requête SQL permettant d’obtenir la variable
daily_stats
pour afficher les bons graphiques.
@@ -1791,20 +1781,20 @@ - Constatez les changements apportés au tableau de bord.
Application 5
Application 5
wget https://github.com/quarto-dev/quarto-cli/releases/download/v1.4.489/quarto-1.4.489-linux-amd64.deb \
+ -O quarto.deb
+sudo dpkg -i quarto.deb
+quarto check install
+rm quarto.deb
Cliquez pour voir la réponse
- +Application 5
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()
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()