From de334bb809a4ae1135c9630b7ffa93b47ec1d51c Mon Sep 17 00:00:00 2001 From: avouacr Date: Thu, 14 Dec 2023 17:47:47 +0000 Subject: [PATCH] move 5a to 3 --- slides/fr/applications/_application3.qmd | 89 +++++++++++++++++- slides/fr/applications/_application5a.qmd | 95 ++++++++++--------- slides/fr/applications/_application5b.qmd | 108 ++++++++++------------ slides/fr/applications/_application5c.qmd | 73 --------------- slides/fr/index.qmd | 8 +- 5 files changed, 188 insertions(+), 185 deletions(-) delete mode 100644 slides/fr/applications/_application5c.qmd diff --git a/slides/fr/applications/_application3.qmd b/slides/fr/applications/_application3.qmd index 61f4377..89eecfc 100644 --- a/slides/fr/applications/_application3.qmd +++ b/slides/fr/applications/_application3.qmd @@ -1,6 +1,6 @@ ::::{.callout-tip collapse="true" icon=false} -## Exposer localement un modèle de ML en tant qu'API +## Partie 1 : exposer localement un modèle de ML en tant qu'API :::::{.nonincremental} @@ -25,7 +25,7 @@ uvicorn app.main:app ## Application 3 {.scrollable} ::::{.callout-tip collapse="true" icon=false} -## Déploiement manuel d'un modèle de ML en tant qu'API +## Partie 2 : déploiement manuel d'un modèle de ML en tant qu'API :::::{.nonincremental} @@ -85,7 +85,7 @@ kubectl apply -f formation-mlops/kubernetes/ ## Application 3 {.scrollable} ::::{.callout-tip collapse="true" icon=false} -## Déploiement continu d'un modèle de ML en tant qu'API +## Partie 3 : déploiement continu d'un modèle de ML en tant qu'API :::::{.nonincremental} @@ -135,3 +135,86 @@ spec: ::::: :::: + + + + + +## Application 3 {.scrollable} + +::::{.callout-tip collapse="true" icon=false} +## Partie 4 : requêter votre modèle déployé + +:::::{.nonincremental} + +1. Créez un fichier `predict_api.py`. Ce script doit : + - Lire le fichier parquet disponible à l'adresse suivante : + + ```shell + https://minio.lab.sspcloud.fr/projet-formation/diffusion/mlops/data/data_to_classify.parquet + ``` + + - Effectuer des requêtes à votre API pour chaque libellé présent dans le fichier parquet. + - Afficher le résultats des prédictions + +
+ + Cliquez pour voir le contenu du script + + +```{.python filename="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://--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)) + +``` +
+ +2. Exécutez votre script `predict_api.py`. + +
+ + Cliquez pour voir la commande + + +```shell +python formation-mlops/src/predict_api.py +``` +
+ +3. Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par `"codification-api-..."`. Observez les logs. + +4. Quelles informations détenez-vous ? Est-ce suffisant ? + +:::: + +:::: {.callout-important collapse="true"} + +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. + +:::: +::: diff --git a/slides/fr/applications/_application5a.qmd b/slides/fr/applications/_application5a.qmd index aff5b64..6f4db72 100644 --- a/slides/fr/applications/_application5a.qmd +++ b/slides/fr/applications/_application5a.qmd @@ -1,55 +1,73 @@ -::: {.nonincremental} +:::{.nonincremental} :::: {.callout-tip collapse="true" icon=false} -## Partie 1 : Requêter votre modèle déployé +## Partie 1 : Logger des métriques métier -1. Créez un fichier `predict_api.py`. Ce script doit : - - Lire le fichier parquet disponible à l'adresse suivante : +1. Grâce au package [logging](https://docs.python.org/3/library/logging.html), rajoutez des logs à votre API. Pour chaque requête, affichez le libellé à coder ainsi que les réponses renvoyées par votre API. Pour cela, modifiez le fichier `app/main.py`. - ```shell - https://minio.lab.sspcloud.fr/projet-formation/diffusion/mlops/data/data_to_classify.parquet - ``` - - - Effectuer des requêtes à votre API pour chaque libellé présent dans le fichier parquet. - - Afficher le résultats des prédictions
- Cliquez pour voir le contenu du script + Cliquez pour voir les étapes à réaliser -```{.python filename="predict_api.py"} -import pandas as pd -import requests +1. Importez le package logging : +```{.python filename="main.py"} +import logging +``` -# 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() +2. Définissez la configuration de vos logs avant la définition de votre premier point d'entrée : + +```{.python filename="main.py"} +logging.basicConfig( + level=logging.INFO, + format="%(asctime)s - %(levelname)s - %(message)s", + handlers=[ + logging.FileHandler("log_file.log"), + logging.StreamHandler(), + ], +) +``` +3. Ajoutez une le libellé et la réponse de l'API dans vos logs : -# URL des données -data_path = "https://minio.lab.sspcloud.fr/projet-formation/diffusion/mlops/data/data_to_classify.parquet" +```{.python filename="main.py"} +# Logging +logging.info(f"{{'Query': {description}, 'Response': {predictions[0]}}}") +``` -# Charge le fichier Parquet dans un DataFrame pandas -df = pd.read_parquet(data_path) +
-# Votre API URL -api_url = "https://--api.lab.sspcloud.fr/predict" +2. Faites un commit de vos changements et poussez les sur votre dépôt distant. -# Effectue les requêtes -responses = df["text"].apply(lambda x: make_prediction(api_url, x)) +3. 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`. -# Affiche le DataFrame avec les résultats des prédictions -print(pd.merge(df, pd.json_normalize(responses), - left_index=True, - right_index=True)) +
+ + Cliquez pour voir les étapes à réaliser + +1. Dans le fichier `kubernetes/deployment.yml`, remplacer le tag `no-logs` par le tag `logs` : + +```{.yaml code-line-numbers="8" filename="deployment.yml"} +template: + metadata: + labels: + app: codification-api + spec: + containers: + - name: api + image: inseefrlab/formation-mlops:logs + imagePullPolicy: Always ``` + +2. Faites un commit de vos changements et poussez les sur votre dépôt distant. + +3. Patientez 5 minutes qu'`ArgoCD` synchronise automatiquement les changements depuis votre dépôt Github ou bien forcez la synchronisation. +
-2. Exécutez votre script `predict_api.py`. +4. Exécutez votre script `predict-api.py`.
@@ -57,20 +75,11 @@ print(pd.merge(df, pd.json_normalize(responses), ```shell -python formation-mlops/src/predict_api.py +python formation-mlops/src/predict-api.py ```
-3. Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par `"codification-api-..."`. Observez les logs. - -4. Quelles informations détenez-vous ? Est-ce suffisant ? - -:::: - -:::: {.callout-important collapse="true"} - -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. +5. Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par `"codification-api-..."`. Observez les logs. :::: - ::: diff --git a/slides/fr/applications/_application5b.qmd b/slides/fr/applications/_application5b.qmd index c106b97..e6dce4b 100644 --- a/slides/fr/applications/_application5b.qmd +++ b/slides/fr/applications/_application5b.qmd @@ -1,85 +1,73 @@ -:::{.nonincremental} -:::: {.callout-tip collapse="true" icon=false} -## Partie 2 : Logger des métriques métier +:::{.callout-tip collapse="true" icon=false} +## Partie 2 : Création d'un tableau de bord de monitoring -1. Grâce au package [logging](https://docs.python.org/3/library/logging.html), rajoutez des logs à votre API. Pour chaque requête, affichez le libellé à coder ainsi que les réponses renvoyées par votre API. Pour cela, modifiez le fichier `app/main.py`. +:::::{.nonincremental} +1. Nous allons utiliser [`Quarto Dashboards`](https://quarto.org/docs/dashboards/) qui fera partie de la version 1.4 de `Quarto`. Téléchargez et installez la pre-release. + ```sh + 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 les étapes à réaliser - - -1. Importez le package logging : - -```{.python filename="main.py"} -import logging -``` - -2. Définissez la configuration de vos logs avant la définition de votre premier point d'entrée : - -```{.python filename="main.py"} -logging.basicConfig( - level=logging.INFO, - format="%(asctime)s - %(levelname)s - %(message)s", - handlers=[ - logging.FileHandler("log_file.log"), - logging.StreamHandler(), - ], -) -``` - -3. Ajoutez une le libellé et la réponse de l'API dans vos logs : +2. 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`. -```{.python filename="main.py"} -# Logging -logging.info(f"{{'Query': {description}, 'Response': {predictions[0]}}}") -``` - -
+3. 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é. -2. Faites un commit de vos changements et poussez les sur votre dépôt distant. + ```sh + cd dashboard + quarto preview index.qmd + ``` -3. 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`. +4. 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.
- Cliquez pour voir les étapes à réaliser + Cliquez pour voir la réponse -1. Dans le fichier `kubernetes/deployment.yml`, remplacer le tag `no-logs` par le tag `logs` : - -```{.yaml code-line-numbers="8" filename="deployment.yml"} -template: - metadata: - labels: - app: codification-api - spec: - containers: - - name: api - image: inseefrlab/formation-mlops:logs - imagePullPolicy: Always +```python +pct_predictions = duckdb.sql( + """ + SELECT 100 * COUNT(*) / COUNT(*) + FROM data; + """ +).fetchall()[0][0] ``` -2. Faites un commit de vos changements et poussez les sur votre dépôt distant. - -3. Patientez 5 minutes qu'`ArgoCD` synchronise automatiquement les changements depuis votre dépôt Github ou bien forcez la synchronisation. -
-4. Exécutez votre script `predict-api.py`. + +5. 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.
- Cliquez pour voir la commande + Cliquez pour voir la réponse -```shell -python formation-mlops/src/predict-api.py +```python +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() ``` + +6. Constatez les changements apportés au tableau de bord. +
-5. Dans ArgoCD, ouvrez votre application puis cliquez sur votre pod qui doit commencer par `"codification-api-..."`. Observez les logs. +::: -:::: ::: diff --git a/slides/fr/applications/_application5c.qmd b/slides/fr/applications/_application5c.qmd deleted file mode 100644 index 26ea854..0000000 --- a/slides/fr/applications/_application5c.qmd +++ /dev/null @@ -1,73 +0,0 @@ -:::{.callout-tip collapse="true" icon=false} -## Partie 3 : Création d'un tableau de bord de monitoring - -:::::{.nonincremental} -1. Nous allons utiliser [`Quarto Dashboards`](https://quarto.org/docs/dashboards/) qui fera partie de la version 1.4 de `Quarto`. Téléchargez et installez la pre-release. - - ```sh - 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 - ``` - -2. 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`. - -3. 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é. - - ```sh - cd dashboard - quarto preview index.qmd - ``` - -4. 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. - -
- - Cliquez pour voir la réponse - - -```python -pct_predictions = duckdb.sql( - """ - SELECT 100 * COUNT(*) / COUNT(*) - FROM data; - """ -).fetchall()[0][0] -``` - -
- - -5. 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. - -
- - Cliquez pour voir la réponse - - -```python -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() -``` - -6. Constatez les changements apportés au tableau de bord. - -
- -::: - -::: diff --git a/slides/fr/index.qmd b/slides/fr/index.qmd index 1734385..d2d91ed 100644 --- a/slides/fr/index.qmd +++ b/slides/fr/index.qmd @@ -590,10 +590,6 @@ spec: # :five: Machine learning en production -## Application 5 {.scrollable} - -{{< include applications/_application5a.qmd >}} - ## Cycle de vie d'un modèle ML en production ![Source: [martinfowler.com](martinfowler.com)](../img/ML-model-lifecycle.png){fig-align="center"} @@ -654,7 +650,7 @@ spec: ## Application 5 {.scrollable} -{{< include applications/_application5b.qmd >}} +{{< include applications/_application5a.qmd >}} ## Observabilité du modèle grâce à un tableau de bord @@ -680,7 +676,7 @@ spec: ## Application 5 {.scrollable} -{{< include applications/_application5c.qmd >}} +{{< include applications/_application5b.qmd >}} # Conclusion