Added some pictures to blog.md
BIN
docs/GloVe-300d_LSTM_epoch12.png
Normal file
|
After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 64 KiB |
|
Before Width: | Height: | Size: 68 KiB |
BIN
docs/Word2Vec_LSTM_epoch9.png
Normal file
|
After Width: | Height: | Size: 57 KiB |
BIN
docs/bert_confusion_matrix.png
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
docs/bert_roc_curve.png
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
docs/bert_training_curves_epoch1.png
Normal file
|
After Width: | Height: | Size: 46 KiB |
184
docs/blog.md
|
|
@ -1,151 +1,176 @@
|
|||
# ✨ Analyse de sentiments et déploiement MLOps : retour d’expérience complet
|
||||
|
||||
Dans le cadre du projet *Air Paradis*, nous avons mis en œuvre une chaîne complète d’analyse de sentiments à partir de tweets, depuis la modélisation jusqu’au déploiement MLOps. Ce billet de blog revient sur l’ensemble des étapes réalisées, les choix méthodologiques, la comparaison des modèles et la mise en production d’une API. 🧠🔧
|
||||
Dans le cadre du projet *Air Paradis*, nous avons mis en œuvre une chaîne complète d’analyse de sentiments à partir de tweets, depuis la modélisation jusqu’au déploiement MLOps. Ce billet de blog revient sur les étapes clés du projet : choix méthodologiques, comparaison des modèles, mise en production d’une API robuste, et déploiement sur deux environnements (local + cloud). 🧠🔧
|
||||
|
||||
---
|
||||
|
||||
## 🔍 Trois approches de modélisation supervisée
|
||||
|
||||
Nous avons testé trois approches complémentaires pour prédire le sentiment d’un tweet. Chacune s’appuie sur un type de représentation des textes et un algorithme différent :
|
||||
Nous avons testé trois approches complémentaires pour prédire le sentiment d’un tweet. Chacune repose sur une représentation textuelle différente et un algorithme d’apprentissage adapté :
|
||||
|
||||
### 1. 🧱 Approche simple : Bag-of-Words (BoW) + modèles de machine learning
|
||||
|
||||
Cette approche utilise des vecteurs BoW ou BoW + TF-IDF, qui capturent la fréquence des mots dans les tweets. On fait le choix d’éviter des techniques non supervisées comme **LDA**, car elles sont plus adaptées à des tâches de topic modeling et non de classification de sentiments (binaire qui plus est).
|
||||
On vectorise les tweets via BoW ou BoW + TF-IDF, qui comptent la fréquence des mots.
|
||||
Contrairement à d'autres projets NLP, nous avons évité LDA (non supervisé, orienté topic modeling).
|
||||
|
||||
➡️ **Modèles testés :**
|
||||
➡️ **Modèles testés** :
|
||||
- Régression Logistique
|
||||
- Naive Bayes
|
||||
- SVM
|
||||
- Random Forest
|
||||
|
||||
Ces modèles ont été entraînés avec **GridSearchCV**, en optimisant la **précision (`precision` et non `accuracy`)**, notre KPI principal.
|
||||
Ces modèles sont entraînés avec **GridSearchCV**, en optimisant la **précision (`precision`)**, notre KPI métier. Différents KPI ont été calculés sur l'ensemble de test.
|
||||
|
||||
📸 *[Insérer ici une capture d’écran MLFlow avec les scores des modèles simples]*
|
||||

|
||||
|
||||
---
|
||||
|
||||
### 2. 🔥 Approche avancée : Word Embeddings (Word2Vec & GloVe 300d) + LSTM
|
||||
### 2. 🔥 Approche avancée : Word Embeddings + LSTM
|
||||
|
||||
On représente les mots non plus comme des fréquences mais comme des vecteurs denses, porteurs de signification.
|
||||
Nous avons utilisé :
|
||||
- **Word2Vec**, entraîné sur un grand corpus (skip-gram),
|
||||
- **GloVe 300d**, embeddings précalculés par Stanford.
|
||||
Nous utilisons des vecteurs denses Word2Vec (entraînés) et GloVe 300d (préentraînés par Stanford), qui capturent les similarités sémantiques entre mots. Ces représentations ne prennent toutefois **pas en compte le contexte** exact (ex : "annulé" est probablement un mot très négatif pour un vol mais positif pour un procès contenant des charges contre vous).
|
||||
|
||||
Ces représentations sont **statistiquement proches** entre mots au sens sémantique.
|
||||
Elles **ne tiennent cependant pas compte du contexte exact dans la phrase** :
|
||||
> « banque » aura le même vecteur que ce soit pour une banque d'argent ou une banque de données.
|
||||
La classification est réalisée par un **LSTM**, capable d'exploiter la séquentialité des mots.
|
||||
Le **modèle déployé est automatiquement sélectionné** entre Word2Vec + LSTM et GloVe + LSTM, selon la **précision maximale enregistrée dans MLFlow**.
|
||||
|
||||
La classification se fait via un **LSTM** (Long Short-Term Memory), une architecture de **deep learning supervisée** adaptée aux séquences de mots.
|
||||
Modèle `Word2Vec + LSTM` (`test_precision : 0.797 , val_precision : 0.795`):
|
||||

|
||||
Modèle `GloVe 300d + LSTM` (`test_precision : 0.792 , val_precision : 0.798`):
|
||||

|
||||
|
||||
🧠 **Le modèle retenu pour le déploiement est sélectionné automatiquement dans MLflow parmi les deux (Word2Vec ou GloVe), en fonction de celui qui obtient la précision maximale.**
|
||||
Cela permet d’avoir un compromis optimal entre légèreté (CPU-friendly) et performance.
|
||||
|
||||
📸 *[Insérer ici une capture d’écran du graphe de précision sur validation pour GloVe+LSTM]*
|
||||
Bien que GloVe 300d + LSTM présente un score de précision légèrement supérieur à Word2Vec + LSTM sur l'ensemble de validation, il reste inférieur pour l'ensemble de test (relativement négligeable dans l'absolu).
|
||||
|
||||
---
|
||||
|
||||
### 3. 🤖 BERT : Bidirectional Encoder Representations from Transformers
|
||||
### 3. 🤖 Approche transformer : DistilBERT, embeddings contextuels allégés
|
||||
|
||||
BERT est un modèle de langage avancé, préentraîné par Google, capable de **comprendre le contexte bidirectionnel** d’un mot dans une phrase. Contrairement aux word embeddings classiques, BERT :
|
||||
- **encode dynamiquement les mots** selon leur contexte d’usage (ex. « banque » n’aura pas le même vecteur selon la phrase),
|
||||
- est entraîné par **masked language modeling** et **next sentence prediction**, puis fine-tuné pour la classification supervisée.
|
||||
Nous avons utilisé **DistilBERT**, une version plus légère et plus rapide de BERT (créée par Hugging Face).
|
||||
Il conserve **95 % de la performance de BERT** tout en étant **40 % plus petit** et **60 % plus rapide**, ce qui le rend particulièrement adapté à un **entraînement sur GPU limité** (Google Colab) et à une **inférence plus rapide**.
|
||||
|
||||
Cependant, il a ses **limites** :
|
||||
> ⚠️ BERT **ne comprend pas l’ironie, le sarcasme ou les références culturelles implicites**.
|
||||
> Il reste un modèle basé sur des cooccurrences statistiques, sans connaissance du monde ou intentionnalité.
|
||||
> Or, **Twitter est un terrain propice au second degré**, aux détournements ou aux trolls : ce type de contenu reste un **véritable défi pour les modèles classiques de NLP.**
|
||||
Comme BERT, DistilBERT produit des **embeddings contextuels**, c’est-à-dire que le sens des mots varie selon leur contexte. Par exemple, *"banque"* dans *"je vais à la banque"* et *"banque de données"* n’aura pas le même vecteur.
|
||||
|
||||
📸 *[Insérer ici un graphique montrant la précision de BERT sur le jeu de validation]*
|
||||
Il a été **fine-tuné** ici pour une classification binaire (positif/négatif), avec un tokenizer et un encodage spécifiques à son architecture.
|
||||
|
||||
> **Modèle `DistilBERT`** (`test_precision : 0.861 , val_precision : 0.858`)
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
⚠️ **Limites** : comme tous les modèles préentraînés, DistilBERT **n’est pas sensible à l’ironie, aux jeux de mots, ni aux références culturelles implicites**.
|
||||
Or, Twitter est un terrain de jeu idéal pour ce genre de contenus détournés. Ces limites s’appliquent aussi à Word2Vec, GloVe et aux modèles classiques.
|
||||
|
||||
---
|
||||
|
||||
## 📐 Choix du KPI : pourquoi la précision (precision) ?
|
||||
## 🎯 Pourquoi optimiser la précision (et non l'accuracy) ?
|
||||
|
||||
Nous avons fait le choix de nous focaliser sur la **précision** plutôt que l’**accuracy** :
|
||||
**Accuracy** = proportion de bonnes prédictions globales.
|
||||
**Precision** = proportion de tweets *prévus positifs* qui sont *vraiment positifs*.
|
||||
|
||||
> 🎯 **Objectif métier :** éviter de **classer un tweet comme positif alors qu’il est négatif**, car cela pourrait induire une mauvaise communication ou une mauvaise interprétation dans un contexte sensible.
|
||||
> Exemple : sur 100 tweets, si le modèle prédit 30 positifs, mais 15 sont des erreurs, la précision est de 50 %.
|
||||
|
||||
### Pour chaque type de modèle :
|
||||
- Modèles classiques → optimisation via **GridSearchCV sur la précision**
|
||||
- Modèles DL → **EarlyStopping sur val_loss**, mais sélection du **meilleur modèle selon la précision** sur l’ensemble de validation.
|
||||
Nous avons préféré **minimiser les faux positifs**, car dans un contexte sensible, **annoncer un tweet positif alors qu’il est négatif peut être problématique**.
|
||||
|
||||
- Modèles classiques : **GridSearchCV optimisé sur la précision**
|
||||
- Modèles DL : **EarlyStopping sur val_loss**, mais **sélection finale sur la précision**
|
||||
|
||||
---
|
||||
|
||||
## ⚙️ Mise en place de l’environnement MLOps maison
|
||||
## ⚙️ Environnement MLOps souverain
|
||||
|
||||
Nous avons choisi une **infrastructure MLOps souveraine et autonome** pour orchestrer les expérimentations.
|
||||
### 🖥️ Serveur personnel NAS + OpenMediaVault
|
||||
|
||||
### 🏠 Serveur personnel (NAS) + OpenMediaVault
|
||||
Nous avons déployé MLFlow sur un NAS personnel tournant sous **OpenMediaVault** (basé sur Debian).
|
||||
MLFlow est installé sur un **NAS personnel (Intel N100)**, sous **OpenMediaVault (Debian)**.
|
||||
Nous utilisons **MinIO** pour stocker artefacts et modèles, garantissant une gestion locale, souveraine et compatible S3.
|
||||
|
||||
### 📦 Artefacts dans MinIO
|
||||
Les modèles, métriques, visualisations et paramètres sont stockés dans **MinIO**, un système compatible S3.
|
||||
➡️ MinIO est open-source, léger, et permet une **gestion souveraine des artefacts**, contrairement à AWS S3.
|
||||
> Les notebooks, exécutés sur Google Colab pour bénéficier de GPU, loggent dans MLFlow et envoient les modèles vers MinIO via des **variables d’environnement**.
|
||||
|
||||
> Les notebooks (en particulier ceux entraînés sur Google Colab, pour bénéficier de GPU) envoient automatiquement leurs logs vers MLFlow et leurs artefacts vers MinIO, via des **variables d’environnement** pour sécuriser les identifiants.
|
||||
Dashboard Expériences MLFlow :
|
||||

|
||||
|
||||
📸 *[Insérer ici une capture du dashboard MLFlow]*
|
||||
Modèles en production (registre de modèles):
|
||||

|
||||
|
||||
Meilleur modèle non BERT retenu :
|
||||

|
||||

|
||||
---
|
||||
|
||||
## 🧪 Intégration continue, tests, versioning
|
||||
## 🧪 CI, tests et versioning
|
||||
|
||||
Une fois les modèles validés, nous avons implémenté toute la chaîne MLOps pour le déploiement API :
|
||||
### ✅ Tests unitaires
|
||||
|
||||
### ✅ Tests automatisés
|
||||
- **Tests unitaires** pour valider le prétraitement des tweets, les prédictions et la gestion des erreurs.
|
||||
- Ces tests sont intégrés dans **GitHub Actions**, et **empêchent tout déploiement Docker si les tests échouent**.
|
||||
- Vérifient le bon fonctionnement du prétraitement, des prédictions et de la gestion d’erreurs.
|
||||
- Intégrés à **GitHub Actions**, **ils bloquent le déploiement si les tests échouent.**
|
||||
|
||||
### 🐳 Conteneurisation & CI/CD
|
||||
- L’API est packagée via **Docker**, puis poussée automatiquement sur **DockerHub** en cas de succès.
|
||||
- Cela permet un déploiement cohérent et rapide sur n’importe quelle plateforme.
|
||||
|
||||
L’API FastAPI est packagée via Docker, puis poussée sur DockerHub.
|
||||
Un pipeline CI/CD complet garantit **un déploiement reproductible**.
|
||||
|
||||

|
||||
---
|
||||
|
||||
## 🚀 Déploiement de l’API FastAPI (double)
|
||||
|
||||
### 🔧 Backend : FastAPI
|
||||
|
||||
- Expose un endpoint `/predict`
|
||||
- Charge dynamiquement le **meilleur modèle Word Embedding + LSTM** via le *Model Registry* MLFlow
|
||||
- Applique les bons embeddings selon le tag `embedding_type`
|
||||
|
||||
### 💻 Interface Streamlit
|
||||
|
||||
Interface locale pour tester les requêtes, debug, démonstrations.
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## 🚀 Déploiement de l’API FastAPI
|
||||
### 🌐 Double déploiement (NAS + Google Cloud)
|
||||
|
||||
### 🛠️ Backend : FastAPI
|
||||
- Fournit un endpoint `/predict`, avec chargement dynamique du modèle via MLFlow et récupération des embeddings (BoW, GloVe ou Word2Vec) selon le tag `embedding_type`.
|
||||
#### 🔧 Problème AVX2
|
||||
|
||||
🧠 Le modèle de type Word Embeddings + LSTM avec la **meilleure précision** est automatiquement récupéré depuis le *Model Registry* MLFlow.
|
||||
Initialement, l’API ne fonctionnait pas sur le NAS (Intel N100), faute d’instruction **AVX2**, requise par TensorFlow.
|
||||
|
||||
### 💻 Frontend local : Streamlit
|
||||
- Sert d’**interface utilisateur** pour tester les prédictions en local, simuler des requêtes API et visualiser les résultats.
|
||||
- C’est aussi un outil utile pour les démonstrations ou le debug.
|
||||
> 🛠️ **Solution : activer AVX2 dans le BIOS** (désactivée par défaut sur certaines cartes mères, souvent optimisées pour NAS).
|
||||
|
||||
📸 *[Insérer capture Streamlit en action]*
|
||||
Depuis, l’API tourne sur :
|
||||
- 🏠 NAS local (accès via [sentiment-api.greg-madman-nas.duckdns.org](https://sentiment-api.greg-madman-nas.duckdns.org))
|
||||
Interface Docker Compose de NAS:
|
||||

|
||||
|
||||
- ☁️ Google Cloud Run : [sentiment-api-service-7772256003.europe-west1.run.app](https://sentiment-api-service-7772256003.europe-west1.run.app)
|
||||
Interface Déploiement Google Cloud:
|
||||

|
||||
|
||||
---
|
||||
|
||||
### 🌐 Problème matériel sur le NAS
|
||||
Le NAS utilise un processeur **Intel N100**, théoriquement compatible AVX2.
|
||||
> ❗ Malheureusement, **certaines cartes mères désactivent cette instruction** au niveau BIOS, ce qui empêche l’exécution de TensorFlow, nécessaire pour le LSTM et BERT.
|
||||
## 📊 Monitoring maison
|
||||
|
||||
🛠️ Solution : **déploiement sur Google Cloud Run**, à l’adresse suivante :
|
||||
🔗 [https://sentiment-api-service-7772256003.europe-west1.run.app/](https://sentiment-api-service-7772256003.europe-west1.run.app/)
|
||||
Une logique d’alerte légère embarquée dans l’API :
|
||||
|
||||
📸 *[Insérer capture console Google Cloud / endpoint]*
|
||||

|
||||
|
||||
---
|
||||

|
||||
|
||||
## 📊 Monitoring maison en production
|
||||

|
||||
|
||||
L'API embarque une **logique d’alerte interne** en cas de dérive.
|
||||
|
||||
🎯 **Comportement :**
|
||||
- Si plus de **3 prédictions incorrectes** sont identifiées dans une **fenêtre de 5 minutes**, un **rapport d’erreur** est généré automatiquement.
|
||||
- Ces erreurs peuvent être loggées ou transmises via webhook selon la configuration future.
|
||||
Si **3 erreurs de prédiction** consécutives sont détectées sur une **fenêtre de 5 min**, un rapport est généré automatiquement.
|
||||
|
||||

|
||||
|
||||
|
||||
Cela permet de garder un **œil léger mais réactif** sur les dérives en production, sans surcharger l’infrastructure.
|
||||
|
||||
---
|
||||
|
||||
## 🧠 Schéma global du pipeline MLOps
|
||||
|
||||
```
|
||||
┌────────────┐
|
||||
│ Données │
|
||||
│ (tweets) │
|
||||
└────┬───────┘
|
||||
└─────┬──────┘
|
||||
│
|
||||
Prétraitement (regex, tokenisation, lemmatisation, stopwords)
|
||||
│
|
||||
|
|
@ -162,26 +187,25 @@ Cela permet de garder un **œil léger mais réactif** sur les dérives en produ
|
|||
│ + Streamlit │
|
||||
└─────────┬──────────┘
|
||||
│
|
||||
Déploiement sur Google Cloud Run
|
||||
Déploiement sur NAS + Google Cloud Run
|
||||
│
|
||||
┌──────────▼─────────────┐
|
||||
│ Monitoring léger maison│
|
||||
│ (alertes sur mauvaises │
|
||||
│ prédictions) │
|
||||
└────────────────────────┘
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## ✨ Conclusion
|
||||
|
||||
Ce projet a permis d’explorer en profondeur les enjeux de classification de sentiments et les **limites des approches standards face à la richesse du langage naturel**, en particulier sur Twitter.
|
||||
Il a aussi démontré l’intérêt d’un **pipeline MLOps souverain** (le plus possible), reproductible et automatisé.
|
||||
|
||||
> ✅ En alliant des modèles puissants, des outils robustes comme MLFlow et FastAPI, et un déploiement maîtrisé, on pose les bases d’un produit de NLP industrialisable.
|
||||
Ce projet démontre comment construire une chaîne MLOps complète, autonome et reproductible pour du NLP appliqué à Twitter.
|
||||
Il souligne les **forces et limites des modèles** (y compris BERT), la nécessité d’une métrique adaptée au contexte (précision vs accuracy), et l’importance d’un **déploiement maîtrisé**, même sur une infrastructure personnelle.
|
||||
|
||||
---
|
||||
|
||||
💬 Merci pour votre lecture !
|
||||
Pour tester l’API : [https://sentiment-api-service-7772256003.europe-west1.run.app/](https://sentiment-api-service-7772256003.europe-west1.run.app/)
|
||||
|
||||
Testez l’API :
|
||||
- En local (NAS) : [https://sentiment-api.greg-madman-nas.duckdns.org/](https://sentiment-api.greg-madman-nas.duckdns.org/)
|
||||
- Sur Google Cloud : [https://sentiment-api-service-7772256003.europe-west1.run.app/](https://sentiment-api-service-7772256003.europe-west1.run.app/)
|
||||
BIN
docs/github_ci-cd-1.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/github_ci-cd.png
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
docs/google_cloud_interface-1.png
Normal file
|
After Width: | Height: | Size: 834 KiB |
BIN
docs/mlflolw_experiments_dashboard_best_LSTM_model-1.png
Normal file
|
After Width: | Height: | Size: 256 KiB |
BIN
docs/mlflow_models_registry_2-1.png
Normal file
|
After Width: | Height: | Size: 235 KiB |
BIN
docs/mlflow_models_registry_best_LSTM_model-1.png
Normal file
|
After Width: | Height: | Size: 167 KiB |
BIN
docs/openmediavault_docker-compose_settings-1.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
BIN
docs/openmediavault_docker-compose_settings.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
|
Before Width: | Height: | Size: 87 KiB After Width: | Height: | Size: 87 KiB |
BIN
docs/streamlit_interface_local.png
Normal file
|
After Width: | Height: | Size: 34 KiB |
BIN
docs/streamlit_interface_nas.png
Normal file
|
After Width: | Height: | Size: 37 KiB |