documentation available both in english and french
This commit is contained in:
parent
20f4f1652b
commit
f074ebb4f4
13 changed files with 672 additions and 170 deletions
62
README.fr.md
Normal file
62
README.fr.md
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
# Projet Air Paradis – Analyse de sentiments
|
||||||
|
|
||||||
|
📘 Ce projet est également disponible en [anglais 🇬🇧](./README.md)
|
||||||
|
|
||||||
|
Ce dépôt contient les notebooks et le code source du projet d’analyse de sentiments sur des tweets, réalisé dans le cadre du programme OpenClassrooms **"Air Paradis"**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contexte métier
|
||||||
|
|
||||||
|
L’objectif est de prédire si un tweet (ou une courte expression écrite) est perçu comme **positif ou négatif**, dans le contexte d’une compagnie aérienne.
|
||||||
|
Le projet repose sur le jeu de données public **Sentiment140**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Description du projet
|
||||||
|
|
||||||
|
Le projet vise à développer un système complet d’analyse de sentiments, comprenant :
|
||||||
|
|
||||||
|
- Une analyse exploratoire des données textuelles,
|
||||||
|
- Une comparaison de plusieurs modèles de classification (classiques, avancés et à l’état de l’art),
|
||||||
|
- Le déploiement d’une API REST exposant un modèle avancé (embeddings + LSTM),
|
||||||
|
- La mise en place d’un pipeline CI/CD pour automatiser les tests et le déploiement,
|
||||||
|
- Un hébergement local sur un serveur NAS pour garantir la souveraineté des données.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Structure du dépôt
|
||||||
|
|
||||||
|
- `notebooks/` : notebooks d’analyse et de modélisation,
|
||||||
|
- `deployment/` : code de l’API, tests, Dockerfile et fichiers liés au déploiement,
|
||||||
|
- `docs/` : documentation et ressources associées,
|
||||||
|
- `../.github/workflows/` : pipelines CI/CD.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Entraînement des modèles
|
||||||
|
|
||||||
|
Les phases d’entraînement ont principalement été réalisées sur **Google Colab**, afin de bénéficier de ressources GPU nécessaires aux modèles de deep learning.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Utilisation
|
||||||
|
|
||||||
|
Les notebooks détaillent les étapes d’analyse et d’entraînement.
|
||||||
|
L’API est disponible dans le dossier `deployment/api`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Remarques
|
||||||
|
|
||||||
|
- Les fichiers `requirements.txt` dans `notebooks/` proviennent des environnements Google Colab et peuvent contenir des dépendances peu optimisées pour un usage local.
|
||||||
|
- Le fichier `.env`, exclu du dépôt, contient les variables d’environnement nécessaires.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Ce README sera mis à jour progressivement au fur et à mesure de l’avancement du projet.
|
||||||
|
Certains commentaires de code peuvent rester en français (ainsi que les cellules Markdown des notebooks). Tout sera traduit en anglais ultérieurement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Projet réalisé dans le cadre du parcours "Data Scientist – Projet 7" d’OpenClassrooms**
|
||||||
13
README.md
13
README.md
|
|
@ -1,4 +1,6 @@
|
||||||
# Air Paradis Project - Sentiment Analysis
|
# Air Paradis Project – Sentiment Analysis
|
||||||
|
|
||||||
|
📘 This project is also available in [French 🇫🇷](./README.fr.md)
|
||||||
|
|
||||||
This repository contains the notebooks and source code for the sentiment analysis project on tweets, carried out as part of the OpenClassrooms "Air Paradis" program.
|
This repository contains the notebooks and source code for the sentiment analysis project on tweets, carried out as part of the OpenClassrooms "Air Paradis" program.
|
||||||
|
|
||||||
|
|
@ -6,7 +8,8 @@ This repository contains the notebooks and source code for the sentiment analysi
|
||||||
|
|
||||||
## Business Context
|
## Business Context
|
||||||
|
|
||||||
The goal is to predict whether a tweet, or a short written expression, is perceived as positive or negative, in the context of an airline company. The project is based on the public **Sentiment140** dataset.
|
The goal is to predict whether a tweet, or a short written expression, is perceived as **positive or negative**, in the context of an airline company.
|
||||||
|
The project is based on the public **Sentiment140** dataset.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -50,9 +53,9 @@ The notebooks detail the analysis and training steps. The API is available in `d
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
This README will be updated progressively as the project advances.
|
This README will be updated progressively as the project advances.
|
||||||
Some code comments can remain in french language (as well as the notebooks markdowns etc.). All will be changed into english in the future.
|
Some code comments can remain in French (as well as notebook markdowns). All will be translated into English later.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**Project completed as part of the OpenClassrooms "Data Scientist - Project 7" program**
|
**Project completed as part of the OpenClassrooms "Data Scientist – Project 7" program**
|
||||||
|
|
|
||||||
128
deployment/README.fr.md
Normal file
128
deployment/README.fr.md
Normal file
|
|
@ -0,0 +1,128 @@
|
||||||
|
# Déploiement de l’API – Projet Air Paradis
|
||||||
|
|
||||||
|
📘 Cette documentation est aussi disponible en [anglais 🇬🇧](./README.md)
|
||||||
|
|
||||||
|
Ce dossier contient le code et la configuration nécessaires au déploiement de l’API de prédiction de sentiment.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Objectif
|
||||||
|
|
||||||
|
Déployer une API REST permettant de :
|
||||||
|
|
||||||
|
- Prédire le **sentiment d’un tweet** (positif ou négatif) à partir d’un modèle LSTM entraîné sur des embeddings (Word2Vec ou GloVe),
|
||||||
|
- Signaler les erreurs de prédiction.
|
||||||
|
|
||||||
|
L’API utilise le **meilleur modèle enregistré** dans MLflow et le sert via **FastAPI**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📦 Architecture globale
|
||||||
|
|
||||||
|
Schéma :
|
||||||
|
|
||||||
|
```
|
||||||
|
┌──────────────────────────────┐
|
||||||
|
│ Utilisateur final (UI) │
|
||||||
|
│ (interface Streamlit) │
|
||||||
|
└────────────┬─────────────────┘
|
||||||
|
│
|
||||||
|
[Appel HTTP vers /predict]
|
||||||
|
│
|
||||||
|
┌────────────▼─────────────┐
|
||||||
|
│ API FastAPI │
|
||||||
|
│ (serveur lancé via │
|
||||||
|
│ Uvicorn) │
|
||||||
|
└────────────┬─────────────┘
|
||||||
|
│
|
||||||
|
Chargement du modèle (MLflow)
|
||||||
|
│
|
||||||
|
Prétraitement du tweet
|
||||||
|
│
|
||||||
|
Prédiction (inférence)
|
||||||
|
│
|
||||||
|
Réponse JSON avec le sentiment
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 Fonctionnement de l’API
|
||||||
|
|
||||||
|
1. **Chargement du modèle**
|
||||||
|
- Le meilleur modèle est enregistré dans MLflow sous le nom `SentimentAnalysisLSTM`, avec le stage `Production`.
|
||||||
|
- L’API le charge au démarrage via l’URI :
|
||||||
|
|
||||||
|
```
|
||||||
|
models:/SentimentAnalysisLSTM/Production
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Prétraitement du texte**
|
||||||
|
- Nettoyage, tokenisation, lemmatisation, puis conversion en vecteurs d’embedding.
|
||||||
|
|
||||||
|
3. **Prédiction**
|
||||||
|
- Le modèle LSTM prédit le sentiment.
|
||||||
|
- Le résultat (`positive` ou `negative`) est retourné en JSON.
|
||||||
|
|
||||||
|
4. **Interface utilisateur (optionnelle)**
|
||||||
|
- Une interface Streamlit permet une interaction visuelle avec l’API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐳 Déploiement via Docker
|
||||||
|
|
||||||
|
Un `Dockerfile` est fourni pour simplifier le déploiement sur tout hôte compatible Docker (NAS, cloud, etc.).
|
||||||
|
|
||||||
|
L’image Docker est poussée sur DockerHub à chaque version validée (voir CI/CD plus bas).
|
||||||
|
|
||||||
|
Par souci de **souveraineté des données**, le déploiement est préféré sur un **NAS équipé d’un processeur Intel N100** (peu énergivore et suffisant pour l’inférence LSTM).
|
||||||
|
|
||||||
|
Le redéploiement peut être automatisé via :
|
||||||
|
- une tâche `cron` simple, ou
|
||||||
|
- un conteneur **Watchtower** (dans docker-compose ou kubernetes).
|
||||||
|
|
||||||
|
**Commande pour test local :**
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker build -t sentiment-api .
|
||||||
|
docker run --rm --env-file ../../.env -p 8000:8000 -p 8080:8080 sentiment-api
|
||||||
|
```
|
||||||
|
|
||||||
|
En production, les variables d’environnement doivent être définies dans le `docker-compose.yml` ou via un gestionnaire de secrets.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🛠 Problèmes AVX2 / Déploiement cloud
|
||||||
|
|
||||||
|
**Mise à jour :** au départ, le NAS ne supportait pas les instructions AVX2 nécessaires à TensorFlow.
|
||||||
|
En réalité, les CPU N100 les prennent en charge, mais certains fabricants désactivent cette option dans le BIOS.
|
||||||
|
|
||||||
|
En attendant un accès physique au NAS, nous avons opté pour un déploiement sur **Google Cloud**.
|
||||||
|
Problème : un seul port peut être exposé publiquement sur ces services.
|
||||||
|
|
||||||
|
Deux solutions possibles :
|
||||||
|
- Séparer le backend (FastAPI) et le frontend (Streamlit) en deux conteneurs,
|
||||||
|
- Utiliser un **reverse proxy** (ex. : nginx) pour rediriger les ports.
|
||||||
|
|
||||||
|
➡️ Nous avons choisi la **deuxième solution**, pour garder une **seule image Docker**.
|
||||||
|
|
||||||
|
**Mise à jour 2 :** AVX2 a été activé via le BIOS. Le déploiement est donc opérationnel **à la fois en local (NAS)** et **sur le cloud**, avec déploiement automatique pour le NAS (voir section suivante).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔁 CI/CD – GitHub Actions
|
||||||
|
|
||||||
|
Un pipeline est défini dans `.github/workflows/` pour :
|
||||||
|
|
||||||
|
- Lancer les tests unitaires à chaque `push`,
|
||||||
|
- Vérifier la stabilité de l’API avant déploiement (NAS ou cloud),
|
||||||
|
- Construire et pousser l’image Docker sur DockerHub.
|
||||||
|
|
||||||
|
Les tests sont situés dans :
|
||||||
|
|
||||||
|
```
|
||||||
|
deployment/api/tests/
|
||||||
|
```
|
||||||
|
|
||||||
|
Le redéploiement automatique sur le NAS est géré via **Watchtower**, qui surveille les mises à jour de l’image Docker (fonctionne comme un `cron`, avec logs).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
@ -1,14 +1,19 @@
|
||||||
# API Deployment - Air Paradis Project
|
# API Deployment – Air Paradis Project
|
||||||
|
|
||||||
|
📘 This documentation is also available in [French 🇫🇷](./README.fr.md)
|
||||||
|
|
||||||
This folder contains the code and configuration necessary to deploy the sentiment prediction API.
|
This folder contains the code and configuration necessary to deploy the sentiment prediction API.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## 🎯 Objective
|
## 🎯 Objective
|
||||||
|
|
||||||
Deploy a REST API that allows to:
|
Deploy a REST API that allows to:
|
||||||
- predict the sentiment of a tweet (positive or negative) based on an LSTM model trained on embeddings (Word2Vec or GloVe).
|
|
||||||
- report prediction errors
|
|
||||||
|
|
||||||
The API uses the best-performing model, registered on MLflow, and serves it via FastAPI.
|
- Predict the sentiment of a tweet (positive or negative) using an LSTM model trained on embeddings (Word2Vec or GloVe),
|
||||||
|
- Report prediction errors.
|
||||||
|
|
||||||
|
The API uses the best-performing model registered on MLflow and serves it via FastAPI.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -16,6 +21,7 @@ The API uses the best-performing model, registered on MLflow, and serves it via
|
||||||
|
|
||||||
Diagram:
|
Diagram:
|
||||||
|
|
||||||
|
```
|
||||||
┌──────────────────────────────┐
|
┌──────────────────────────────┐
|
||||||
│ End user (UI) │
|
│ End user (UI) │
|
||||||
│ (Streamlit interface) │
|
│ (Streamlit interface) │
|
||||||
|
|
@ -36,72 +42,85 @@ Diagram:
|
||||||
Prediction (inference)
|
Prediction (inference)
|
||||||
│
|
│
|
||||||
Sentiment response (JSON)
|
Sentiment response (JSON)
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧪 API Workflow
|
## 🧪 API Workflow
|
||||||
|
|
||||||
1. Model loading
|
1. **Model loading**
|
||||||
- The best performing model is registered in MLflow under a fixed name (`SentimentAnalysisLSTM`) and a stage `Production`.
|
- The best performing model is registered in MLflow under a fixed name (`SentimentAnalysisLSTM`) and a `Production` stage.
|
||||||
- The API loads this model at startup using a stable URI:
|
- The API loads this model at startup using the URI:
|
||||||
|
|
||||||
|
```
|
||||||
models:/SentimentAnalysisLSTM/Production
|
models:/SentimentAnalysisLSTM/Production
|
||||||
|
```
|
||||||
|
|
||||||
2. Text preprocessing
|
2. **Text preprocessing**
|
||||||
- The text sent by the user is cleaned, tokenized, lemmatized, and transformed into vectors (embeddings).
|
- Text is cleaned, tokenized, lemmatized, and converted into vectors (embeddings).
|
||||||
|
|
||||||
3. Prediction
|
3. **Prediction**
|
||||||
- The LSTM model (loaded from MLflow) performs inference.
|
- The LSTM model (loaded from MLflow) makes a prediction.
|
||||||
- The result (`positive` or `negative`) is returned as a JSON response.
|
- The result (`positive` or `negative`) is returned as JSON.
|
||||||
|
|
||||||
4. User interface (optional)
|
4. **User interface (optional)**
|
||||||
- A Streamlit interface allows visual interaction with the API.
|
- A Streamlit interface allows visual interaction with the API.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🐳 Deployment with Docker
|
## 🐳 Deployment with Docker
|
||||||
|
|
||||||
A Dockerfile is provided to facilitate deploying the API on any Docker-compatible host (NAS, cloud, etc.).
|
A `Dockerfile` is provided for easy deployment on any Docker-compatible host (NAS, cloud, etc.).
|
||||||
|
|
||||||
This Docker image should be pushed to DockerHub at each validated versioning (see the CI/CD section below).
|
This Docker image should be pushed to DockerHub with every validated version (see CI/CD below).
|
||||||
|
|
||||||
For data sovereignty reasons, deployment will preferably be done on a NAS equipped with an Intel N100 processor (energy efficient but probably sufficient for LSTM inference).
|
For data sovereignty, deployment is preferably done on a **NAS with Intel N100** CPU (energy-efficient, sufficient for inference).
|
||||||
Docker can be redeployed each time the docker image on DockerHub is updated. Man can use `cron` instruction (simple) or `Watchtower` docker (docker-compose / kubernetes context).
|
Docker can be automatically redeployed using:
|
||||||
|
- `cron` (simple), or
|
||||||
|
- `Watchtower` in docker-compose/kubernetes setups.
|
||||||
|
|
||||||
For running the Docker image locally (development), it is important to provide the `.env` file containing environment variables and to open the FastAPI and Streamlit ports for testing the application.
|
**Development command (local test):**
|
||||||
|
|
||||||
Example commands to build and run:
|
```bash
|
||||||
|
docker build -t sentiment-api .
|
||||||
|
docker run --rm --env-file ../../.env -p 8000:8000 -p 8080:8080 sentiment-api
|
||||||
|
```
|
||||||
|
|
||||||
docker build -t sentiment-api .
|
In production (e.g. via docker-compose or cloud services), environment variables must be defined in the compose file or secret manager.
|
||||||
docker run --env-file ../../.env -p 8000:8000 -p 8080:8080 sentiment-api
|
|
||||||
|
|
||||||
For deployment on a personal or public cloud (with docker-compose, Kubernetes), it is preferable to specify the necessary environment variables in `docker-compose.yml` or in secrets.
|
|
||||||
|
|
||||||
Add the `--rm` argument so that the container is removed after stopping.
|
|
||||||
|
|
||||||
**UPDATE** : in our case, we encountered some issues with the NAS which CPU is not able to run AVX2 instructions so we are obliged to deploy it on a "standard" public cloud service. To be precise, N100 CPU is normally able to run AXV2 instructions but some NAS/home server motherboard manufacturers sometimes disable this feature. Maybe is it possible to renable it on the BIOS, but I am away from my NAS so it will have to wait.
|
|
||||||
|
|
||||||
So, we decided to use Google Cloud. A common issue arises here: we cannot expose multiple ports (contrary to the instruction above) on a cloud service.
|
|
||||||
|
|
||||||
Two options are possible:
|
|
||||||
|
|
||||||
- Separate the service into two dockers (one for FastAPI backend and one for Streamlit frontend)
|
|
||||||
- Configure a reverse proxy like nginx to redirect requests to different internal ports
|
|
||||||
|
|
||||||
We decided to keep the second solution to install the API from a single Docker container.
|
|
||||||
|
|
||||||
**UPDATE 2** : AVX2 instructions have been enabled by accessing the home server motherboard BIOS. So the deployment is also done here and complete continuous deployment will be done as well.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔁 Continuous Integration / Continuous Deployment
|
## 🛠 Notes on AVX2 / Cloud Deployment
|
||||||
|
|
||||||
A GitHub Actions pipeline (CI/CD) is planned at the very root of the repo to:
|
**Update:** the NAS initially failed due to lack of AVX2 support. Some N100-based NAS motherboards disable AVX2 in BIOS.
|
||||||
|
|
||||||
- Automatically run unit tests at every push on the GitHub repository.
|
When not accessible, fallback deployment is done on **Google Cloud**.
|
||||||
- Ensure API stability before any deployment (NAS or cloud).
|
Issue: public cloud services do **not allow multiple ports** to be exposed easily.
|
||||||
- Update the Dockerfile and push it to DockerHub.
|
|
||||||
|
|
||||||
Unit tests will be defined in `./deployment/api/tests/`
|
Two solutions:
|
||||||
|
- Split into two containers: FastAPI + Streamlit,
|
||||||
|
- Use a **reverse proxy** (e.g., Nginx) to map ports.
|
||||||
|
|
||||||
- API docker is automatically updated on home server docker using watchtower docker (= cron with logging options)
|
➡️ We chose the second option to keep a **single Docker image**.
|
||||||
|
|
||||||
|
**Update 2:** AVX2 was enabled via BIOS. Deployment is now active **both locally (NAS)** and **on cloud**, with continuous deployment on NAS (see section below).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🔁 CI/CD – GitHub Actions
|
||||||
|
|
||||||
|
A pipeline is defined in `.github/workflows/` to:
|
||||||
|
|
||||||
|
- Run unit tests on every push,
|
||||||
|
- Check API health before deployment (local/cloud),
|
||||||
|
- Build and push Docker image to DockerHub.
|
||||||
|
|
||||||
|
Tests are defined in:
|
||||||
|
|
||||||
|
```
|
||||||
|
deployment/api/tests/
|
||||||
|
```
|
||||||
|
|
||||||
|
Docker image auto-redeployment on NAS is handled by **Watchtower**, which checks DockerHub updates (like a cron job, with logs).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
|
||||||
235
docs/blog.fr.md
Normal file
235
docs/blog.fr.md
Normal file
|
|
@ -0,0 +1,235 @@
|
||||||
|
# ✨ 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 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 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
|
||||||
|
|
||||||
|
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** :
|
||||||
|
- Régression Logistique
|
||||||
|
- Naive Bayes
|
||||||
|
- SVM
|
||||||
|
- Random Forest
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 2. 🔥 Approche avancée : Word Embeddings + LSTM
|
||||||
|
|
||||||
|
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).
|
||||||
|
|
||||||
|
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**.
|
||||||
|
|
||||||
|
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`):
|
||||||
|

|
||||||
|
|
||||||
|
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. 🤖 Approche transformer : DistilBERT, embeddings contextuels allégés
|
||||||
|
|
||||||
|
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**.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Pourquoi optimiser la précision (et non l'accuracy) ?
|
||||||
|
|
||||||
|
**Accuracy** = proportion de bonnes prédictions globales.
|
||||||
|
**Precision** = proportion de tweets *prévus positifs* qui sont *vraiment positifs*.
|
||||||
|
|
||||||
|
> Exemple : sur 100 tweets, si le modèle prédit 30 positifs, mais 15 sont des erreurs, la précision est de 50 %.
|
||||||
|
|
||||||
|
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**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚙️ Environnement MLOps souverain
|
||||||
|
|
||||||
|
### 🖥️ Serveur personnel NAS + OpenMediaVault
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
> 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**.
|
||||||
|
|
||||||
|
Dashboard Expériences MLFlow :
|
||||||
|

|
||||||
|
|
||||||
|
Modèles en production (registre de modèles):
|
||||||
|

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

|
||||||
|

|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧪 CI, tests et versioning
|
||||||
|
|
||||||
|
### ✅ Tests unitaires
|
||||||
|
|
||||||
|
- 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 FastAPI est packagée via Docker, puis poussée sur DockerHub.
|
||||||
|
Un [pipeline CI/CD](https://github.com/GrgMdmn/OpenClassrooms_AI_Projects/blob/main/.github/workflows/p7_ci-cd.yml) complet garantit **un déploiement reproductible**. Il assure:
|
||||||
|
- La validation de tests unitaires
|
||||||
|
- La construction et le push de l'api conteneurisée sur dockerhub
|
||||||
|
|
||||||
|

|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### 🌐 Double déploiement (NAS + Google Cloud)
|
||||||
|
|
||||||
|
#### 🔧 Problème AVX2
|
||||||
|
|
||||||
|
Initialement, l’API ne fonctionnait pas sur le NAS (processeur Intel N100), car celui-ci ne prenait pas en charge les instructions **AVX2**, requises par TensorFlow.
|
||||||
|
|
||||||
|
> 🛠️ **Solution** : activation manuelle du support AVX2 dans le BIOS. Cette option est souvent désactivée par défaut sur les cartes mères orientées NAS pour des raisons de consommation énergétique ou de stabilité.
|
||||||
|
|
||||||
|
Depuis cette modification, le NAS peut exécuter l’API sans erreurs.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 🚀 API déployées
|
||||||
|
|
||||||
|
Le projet propose un **double déploiement** de l’API, en local et dans le cloud :
|
||||||
|
|
||||||
|
- 🏠 **NAS local** : [sentiment-api.greg-madman-nas.duckdns.org](https://sentiment-api.greg-madman-nas.duckdns.org)\
|
||||||
|
Interface Docker Compose sur le NAS :
|
||||||
|

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

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
#### 🔄 Déploiement continu automatisé (NAS uniquement)
|
||||||
|
|
||||||
|
Pour assurer un **déploiement continu** sur le NAS, il a été choisi d'installer [**Watchtower**](https://containrrr.dev/watchtower/arguments/) pour rester dans un logique d'environnement 100% `docker`. Cet outil surveille toutes les **10 minutes** l’image Docker de l’API (`sentiment_api`) et, en cas de nouvelle version disponible sur DockerHub, redémarre automatiquement le conteneur avec la dernière image.
|
||||||
|

|
||||||
|
|
||||||
|
> Un **système d’alerte mail** notifie automatiquement toute mise à jour effectuée.
|
||||||
|

|
||||||
|
|
||||||
|
Ce mécanisme garantit que la version déployée sur le NAS reste toujours synchronisée avec la dernière version validée par les tests sur GitHub Actions, **sans intervention manuelle**.
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Monitoring maison
|
||||||
|
|
||||||
|
Une logique d’alerte légère embarquée dans l’API :
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🧠 Schéma global du pipeline MLOps
|
||||||
|
|
||||||
|
### Schéma synthétique
|
||||||
|
```
|
||||||
|
┌────────────┐
|
||||||
|
│ Données │
|
||||||
|
│ (tweets) │
|
||||||
|
└─────┬──────┘
|
||||||
|
│
|
||||||
|
Prétraitement (regex, tokenisation, lemmatisation, stopwords)
|
||||||
|
│
|
||||||
|
┌─────────▼──────────┐
|
||||||
|
│ Entraînement ML │
|
||||||
|
└─────────┬──────────┘
|
||||||
|
│
|
||||||
|
Log via MLFlow + artefacts MinIO
|
||||||
|
│
|
||||||
|
Sélection du meilleur modèle "avancé" (hors BERT) selon précision
|
||||||
|
│
|
||||||
|
┌─────────▼──────────┐
|
||||||
|
│ API FastAPI │
|
||||||
|
│ + Streamlit │
|
||||||
|
└─────────┬──────────┘
|
||||||
|
│
|
||||||
|
Déploiement :
|
||||||
|
├─ Google Cloud Run (manuel)
|
||||||
|
└─ NAS local (automatisé via Watchtower)
|
||||||
|
│
|
||||||
|
┌──────────▼─────────────┐
|
||||||
|
│ Monitoring léger maison│
|
||||||
|
│ (alertes sur mauvaises │
|
||||||
|
│ prédictions) │
|
||||||
|
└────────────────────────┘
|
||||||
|
```
|
||||||
|
### Schéma détaillé
|
||||||
|

|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✨ Conclusion
|
||||||
|
|
||||||
|
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 !
|
||||||
245
docs/blog.md
245
docs/blog.md
|
|
@ -1,235 +1,244 @@
|
||||||
# ✨ Analyse de sentiments et déploiement MLOps : retour d’expérience complet
|
# ✨ Sentiment Analysis and MLOps Deployment: A Complete Experience Report
|
||||||
|
|
||||||
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). 🧠🔧
|
As part of the *Air Paradis* project, we implemented a full sentiment analysis pipeline from tweets, covering everything from modeling to MLOps deployment. This blog post reviews the key project stages: methodological choices, model comparison, deployment of a robust API, and deployment on two environments (local + cloud). 🧠🔧
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔍 Trois approches de modélisation supervisée
|
## 🔍 Three Supervised Modeling Approaches
|
||||||
|
|
||||||
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é :
|
We tested three complementary approaches to predict the sentiment of a tweet. Each relies on a different text representation and a suitable learning algorithm:
|
||||||
|
|
||||||
### 1. 🧱 Approche simple : Bag-of-Words (BoW) + modèles de machine learning
|
### 1. 🧱 Simple Approach: Bag-of-Words (BoW) + Machine Learning Models
|
||||||
|
|
||||||
On vectorise les tweets via BoW ou BoW + TF-IDF, qui comptent la fréquence des mots.
|
Tweets are vectorized using BoW or BoW + TF-IDF, which count word frequencies.
|
||||||
Contrairement à d'autres projets NLP, nous avons évité LDA (non supervisé, orienté topic modeling).
|
Unlike other NLP projects, we avoided LDA (unsupervised, topic modeling oriented).
|
||||||
|
|
||||||
➡️ **Modèles testés** :
|
➡️ **Tested models**:
|
||||||
- Régression Logistique
|
- Logistic Regression
|
||||||
- Naive Bayes
|
- Naive Bayes
|
||||||
- SVM
|
- SVM
|
||||||
- Random Forest
|
- Random Forest
|
||||||
|
|
||||||
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.
|
These models are trained with **GridSearchCV**, optimizing **precision (`precision`)**, our key business KPI. Various KPIs were computed on the test set.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 2. 🔥 Approche avancée : Word Embeddings + LSTM
|
### 2. 🔥 Advanced Approach: Word Embeddings + LSTM
|
||||||
|
|
||||||
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).
|
We use dense Word2Vec vectors (trained) and GloVe 300d (pretrained by Stanford), which capture semantic similarities between words. However, these representations **do not take into account the exact context** (e.g., "cancelled" is probably very negative for a flight but positive in a legal case with charges against you).
|
||||||
|
|
||||||
La classification est réalisée par un **LSTM**, capable d'exploiter la séquentialité des mots.
|
Classification is done by an **LSTM**, capable of exploiting word sequentiality.
|
||||||
Le **modèle déployé est automatiquement sélectionné** entre Word2Vec + LSTM et GloVe + LSTM, selon la **précision maximale enregistrée dans MLFlow**.
|
The **deployed model is automatically selected** between Word2Vec + LSTM and GloVe + LSTM, according to the **highest precision recorded in MLFlow**.
|
||||||
|
|
||||||
Modèle `Word2Vec + LSTM` (`test_precision : 0.797 , val_precision : 0.795`):
|
Model `Word2Vec + LSTM` (`test_precision: 0.797, val_precision: 0.795`):
|
||||||

|

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

|

|
||||||
|
|
||||||
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).
|
Although GloVe 300d + LSTM shows a slightly better precision score on the validation set than Word2Vec + LSTM, it remains lower on the test set (relatively negligible overall).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 3. 🤖 Approche transformer : DistilBERT, embeddings contextuels allégés
|
### 3. 🤖 Transformer Approach: DistilBERT, Lightweight Contextual Embeddings
|
||||||
|
|
||||||
Nous avons utilisé **DistilBERT**, une version plus légère et plus rapide de BERT (créée par Hugging Face).
|
We used **DistilBERT**, a lighter and faster version of BERT (created by 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**.
|
It retains **95% of BERT's performance** while being **40% smaller** and **60% faster**, making it especially suited for **training on limited GPUs** (Google Colab) and **faster inference**.
|
||||||
|
|
||||||
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.
|
Like BERT, DistilBERT produces **contextual embeddings**, meaning word meanings vary depending on context. For example, *"bank"* in *"I go to the bank"* and *"database bank"* will not have the same vector.
|
||||||
|
|
||||||
Il a été **fine-tuné** ici pour une classification binaire (positif/négatif), avec un tokenizer et un encodage spécifiques à son architecture.
|
It was **fine-tuned** here for binary classification (positive/negative), with a tokenizer and encoding specific to its architecture.
|
||||||
|
|
||||||
> **Modèle `DistilBERT`** (`test_precision : 0.861 , val_precision : 0.858`)
|
> **Model `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**.
|
⚠️ **Limits**: Like all pretrained models, DistilBERT **is not sensitive to irony, puns, or implicit cultural references**.
|
||||||
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.
|
Twitter is an ideal playground for this kind of nuanced content. These limits also apply to Word2Vec, GloVe, and classical models.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🎯 Pourquoi optimiser la précision (et non l'accuracy) ?
|
## 🎯 Why Optimize Precision (Not Accuracy)?
|
||||||
|
|
||||||
**Accuracy** = proportion de bonnes prédictions globales.
|
**Accuracy** = overall proportion of correct predictions.
|
||||||
**Precision** = proportion de tweets *prévus positifs* qui sont *vraiment positifs*.
|
**Precision** = proportion of *predicted positive* tweets that are *actually positive*.
|
||||||
|
|
||||||
> Exemple : sur 100 tweets, si le modèle prédit 30 positifs, mais 15 sont des erreurs, la précision est de 50 %.
|
> Example: out of 100 tweets, if the model predicts 30 positives but 15 are wrong, precision is 50%.
|
||||||
|
|
||||||
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**.
|
We preferred to **minimize false positives**, because in a sensitive context, **announcing a tweet as positive when it is negative can be problematic**.
|
||||||
|
|
||||||
- Modèles classiques : **GridSearchCV optimisé sur la précision**
|
- Classical models: **GridSearchCV optimized for precision**
|
||||||
- Modèles DL : **EarlyStopping sur val_loss**, mais **sélection finale sur la précision**
|
- Deep Learning models: **EarlyStopping on val_loss**, but **final selection based on precision**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ⚙️ Environnement MLOps souverain
|
## ⚙️ Sovereign MLOps Environment
|
||||||
|
|
||||||
### 🖥️ Serveur personnel NAS + OpenMediaVault
|
### 🖥️ Personal NAS Server + OpenMediaVault
|
||||||
|
|
||||||
MLFlow est installé sur un **NAS personnel (Intel N100)**, sous **OpenMediaVault (Debian)**.
|
MLFlow is installed on a **personal NAS (Intel N100)** running **OpenMediaVault (Debian)**.
|
||||||
Nous utilisons **MinIO** pour stocker artefacts et modèles, garantissant une gestion locale, souveraine et compatible S3.
|
We use **MinIO** to store artifacts and models, ensuring local, sovereign, and S3-compatible management.
|
||||||
|
|
||||||
> 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**.
|
> Notebooks, run on Google Colab to leverage GPUs, log in MLFlow and send models to MinIO via **environment variables**.
|
||||||
|
|
||||||
Dashboard Expériences MLFlow :
|
MLFlow Experiments Dashboard:
|
||||||

|

|
||||||
|
|
||||||
Modèles en production (registre de modèles):
|
Production Models (model registry):
|
||||||

|

|
||||||
|
|
||||||
Meilleur modèle non BERT retenu :
|
Best non-BERT selected model:
|
||||||

|

|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧪 CI, tests et versioning
|
## 🧪 CI, Testing and Versioning
|
||||||
|
|
||||||
### ✅ Tests unitaires
|
### ✅ Unit Tests
|
||||||
|
|
||||||
- Vérifient le bon fonctionnement du prétraitement, des prédictions et de la gestion d’erreurs.
|
- Check correct preprocessing, predictions, and error handling.
|
||||||
- Intégrés à **GitHub Actions**, **ils bloquent le déploiement si les tests échouent.**
|
- Integrated into **GitHub Actions**, **blocking deployment if tests fail.**
|
||||||
|
|
||||||
### 🐳 Conteneurisation & CI/CD
|
### 🐳 Containerization & CI/CD
|
||||||
|
|
||||||
L’API FastAPI est packagée via Docker, puis poussée sur DockerHub.
|
The FastAPI API is packaged with Docker, then pushed to DockerHub.
|
||||||
Un [pipeline CI/CD](https://github.com/GrgMdmn/OpenClassrooms_AI_Projects/blob/main/.github/workflows/p7_ci-cd.yml) complet garantit **un déploiement reproductible**. Il assure:
|
A full [CI/CD pipeline](https://github.com/GrgMdmn/OpenClassrooms_AI_Projects/blob/main/.github/workflows/p7_ci-cd.yml) guarantees **reproducible deployment**, ensuring:
|
||||||
- La validation de tests unitaires
|
- Validation of unit tests
|
||||||
- La construction et le push de l'api conteneurisée sur dockerhub
|
- Build and push of the containerized API to DockerHub
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||

|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🚀 Déploiement de l’API FastAPI (double)
|
## 🚀 FastAPI API Deployment (Dual)
|
||||||
|
|
||||||
### 🔧 Backend : FastAPI
|
### 🔧 Backend: FastAPI
|
||||||
|
|
||||||
- Expose un endpoint `/predict`
|
- Exposes a `/predict` endpoint
|
||||||
- Charge dynamiquement le **meilleur modèle Word Embedding + LSTM** via le *Model Registry* MLFlow
|
- Dynamically loads the **best Word Embedding + LSTM model** via MLFlow Model Registry
|
||||||
- Applique les bons embeddings selon le tag `embedding_type`
|
- Applies appropriate embeddings according to the `embedding_type` tag
|
||||||
|
|
||||||
### 💻 Interface Streamlit
|
### 💻 Streamlit Interface
|
||||||
|
|
||||||
Interface locale pour tester les requêtes, debug, démonstrations.
|
Local interface for request testing, debugging, demonstrations.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
### 🌐 Double déploiement (NAS + Google Cloud)
|
### 🌐 Dual Deployment (NAS + Google Cloud)
|
||||||
|
|
||||||
#### 🔧 Problème AVX2
|
#### 🔧 AVX2 Issue
|
||||||
|
|
||||||
Initialement, l’API ne fonctionnait pas sur le NAS (processeur Intel N100), car celui-ci ne prenait pas en charge les instructions **AVX2**, requises par TensorFlow.
|
Initially, the API did not run on the NAS (Intel N100 CPU) because it did not support **AVX2 instructions**, required by TensorFlow.
|
||||||
|
|
||||||
> 🛠️ **Solution** : activation manuelle du support AVX2 dans le BIOS. Cette option est souvent désactivée par défaut sur les cartes mères orientées NAS pour des raisons de consommation énergétique ou de stabilité.
|
> 🛠️ **Solution**: manual activation of AVX2 support in BIOS. This option is often disabled by default on NAS motherboards for power consumption or stability reasons.
|
||||||
|
|
||||||
Depuis cette modification, le NAS peut exécuter l’API sans erreurs.
|
Since this change, the NAS can run the API without errors.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 🚀 API déployées
|
#### 🚀 Deployed APIs
|
||||||
|
|
||||||
Le projet propose un **double déploiement** de l’API, en local et dans le cloud :
|
The project offers a **dual API deployment**, locally and in the cloud:
|
||||||
|
|
||||||
- 🏠 **NAS local** : [sentiment-api.greg-madman-nas.duckdns.org](https://sentiment-api.greg-madman-nas.duckdns.org)\
|
- 🏠 **Local NAS**: [sentiment-api.greg-madman-nas.duckdns.org](https://sentiment-api.greg-madman-nas.duckdns.org)
|
||||||
Interface Docker Compose sur le NAS :
|
Docker Compose interface on the NAS:
|
||||||

|

|
||||||
|
|
||||||
- ☁️ **Google Cloud Run** : [sentiment-api-service-7772256003.europe-west1.run.app](https://sentiment-api-service-7772256003.europe-west1.run.app)\
|
- ☁️ **Google Cloud Run**: [sentiment-api-service-7772256003.europe-west1.run.app](https://sentiment-api-service-7772256003.europe-west1.run.app)
|
||||||
Interface de déploiement Google Cloud :
|
Google Cloud deployment interface:
|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
#### 🔄 Déploiement continu automatisé (NAS uniquement)
|
#### 🔄 Automated Continuous Deployment (NAS only)
|
||||||
|
|
||||||
Pour assurer un **déploiement continu** sur le NAS, il a été choisi d'installer [**Watchtower**](https://containrrr.dev/watchtower/arguments/) pour rester dans un logique d'environnement 100% `docker`. Cet outil surveille toutes les **10 minutes** l’image Docker de l’API (`sentiment_api`) et, en cas de nouvelle version disponible sur DockerHub, redémarre automatiquement le conteneur avec la dernière image.
|
To ensure **continuous deployment** on the NAS, we chose to install [**Watchtower**](https://containrrr.dev/watchtower/arguments/) to maintain a 100% `docker` environment. This tool checks every **10 minutes** the Docker image of the API (`sentiment_api`) and, if a new version is available on DockerHub, automatically restarts the container with the latest image.
|
||||||

|

|
||||||
|
|
||||||
> Un **système d’alerte mail** notifie automatiquement toute mise à jour effectuée.
|
> An **email alert system** automatically notifies any update performed.
|
||||||

|

|
||||||
|
|
||||||
Ce mécanisme garantit que la version déployée sur le NAS reste toujours synchronisée avec la dernière version validée par les tests sur GitHub Actions, **sans intervention manuelle**.
|
This mechanism ensures that the version deployed on the NAS always stays synchronized with the latest version validated by GitHub Actions tests, **without manual intervention**.
|
||||||

|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 📊 Monitoring maison
|
## 📊 Home-made Monitoring
|
||||||
|
|
||||||
Une logique d’alerte légère embarquée dans l’API :
|
A lightweight alert logic embedded in the API:
|
||||||
|
|
||||||

|

|
||||||
|

|
||||||

|

|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
|
If **3 consecutive prediction errors** are detected within a **5-minute window**, a report is automatically generated.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🧠 Schéma global du pipeline MLOps
|
## 🧠 Overall MLOps Pipeline Diagram
|
||||||
|
|
||||||
|
### Summary Diagram
|
||||||
|
|
||||||
### Schéma synthétique
|
|
||||||
```
|
```
|
||||||
┌────────────┐
|
┌────────────┐
|
||||||
│ Données │
|
│ Data │
|
||||||
│ (tweets) │
|
│ (tweets) │
|
||||||
└─────┬──────┘
|
└─────┬──────┘
|
||||||
│
|
│
|
||||||
Prétraitement (regex, tokenisation, lemmatisation, stopwords)
|
Preprocessing (regex, tokenization, lemmatization, stopwords)
|
||||||
│
|
│
|
||||||
┌─────────▼──────────┐
|
┌─────────▼──────────┐
|
||||||
│ Entraînement ML │
|
│ ML Training │
|
||||||
└─────────┬──────────┘
|
└─────────┬──────────┘
|
||||||
│
|
│
|
||||||
Log via MLFlow + artefacts MinIO
|
Logging via MLFlow + artifacts MinIO
|
||||||
│
|
│
|
||||||
Sélection du meilleur modèle "avancé" (hors BERT) selon précision
|
Select best "advanced" model (excluding BERT) by precision
|
||||||
│
|
│
|
||||||
┌─────────▼──────────┐
|
┌─────────▼──────────┐
|
||||||
│ API FastAPI │
|
│ FastAPI │
|
||||||
│ + Streamlit │
|
│ + Streamlit │
|
||||||
└─────────┬──────────┘
|
└─────────┬──────────┘
|
||||||
│
|
│
|
||||||
Déploiement :
|
Deployment:
|
||||||
├─ Google Cloud Run (manuel)
|
├─ Google Cloud Run (manual)
|
||||||
└─ NAS local (automatisé via Watchtower)
|
└─ Local NAS (automated via Watchtower)
|
||||||
│
|
│
|
||||||
┌──────────▼─────────────┐
|
┌──────────▼─────────────┐
|
||||||
│ Monitoring léger maison│
|
│ Lightweight in-house │
|
||||||
│ (alertes sur mauvaises │
|
│ Monitoring │
|
||||||
│ prédictions) │
|
│ (alerts on bad │
|
||||||
|
│ predictions) │
|
||||||
└────────────────────────┘
|
└────────────────────────┘
|
||||||
|
|
||||||
```
|
```
|
||||||
### Schéma détaillé
|
|
||||||

|
### Detailed Diagram
|
||||||
|

|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## ✨ Conclusion
|
## ✨ Conclusion
|
||||||
|
|
||||||
Ce projet démontre comment construire une chaîne MLOps complète, autonome et reproductible pour du NLP appliqué à Twitter.
|
This project demonstrates how to build a complete, autonomous, and reproducible MLOps pipeline for NLP applied to 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.
|
It highlights the **strengths and limitations of the models** (including BERT), the need for a **metric adapted to the context** (precision vs accuracy), and the importance of **controlled deployment**, even on personal infrastructure.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
💬 Merci pour votre lecture !
|
💬 Thank you for reading!
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Demander à ChatGPT
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
<mxPoint x="-14" y="-1" as="offset" />
|
<mxPoint x="-14" y="-1" as="offset" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
</mxCell>
|
</mxCell>
|
||||||
<mxCell id="vVvrGs-YRXqjEHhurR4v-106" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=oval;endFill=1;fillColor=#60a917;strokeColor=#2D7600;" parent="1" source="vVvrGs-YRXqjEHhurR4v-47" edge="1">
|
<mxCell id="vVvrGs-YRXqjEHhurR4v-106" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;endArrow=oval;endFill=1;fillColor=#60a917;strokeColor=#2D7600;strokeWidth=2;" parent="1" source="vVvrGs-YRXqjEHhurR4v-47" edge="1">
|
||||||
<mxGeometry relative="1" as="geometry">
|
<mxGeometry relative="1" as="geometry">
|
||||||
<mxPoint x="1140" y="712" as="targetPoint" />
|
<mxPoint x="1140" y="712" as="targetPoint" />
|
||||||
</mxGeometry>
|
</mxGeometry>
|
||||||
|
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 135 KiB After Width: | Height: | Size: 135 KiB |
46
notebooks/README.fr.md
Normal file
46
notebooks/README.fr.md
Normal file
|
|
@ -0,0 +1,46 @@
|
||||||
|
# Notebooks
|
||||||
|
|
||||||
|
Ce dossier contient les notebooks Jupyter utilisés pour le développement des modèles et les analyses du projet.
|
||||||
|
|
||||||
|
## Contenu
|
||||||
|
|
||||||
|
- Analyse exploratoire des données
|
||||||
|
- Modèles classiques (régression logistique, SVM, etc.)
|
||||||
|
- Modèles avancés (LSTM avec embeddings GloVe)
|
||||||
|
- Modèle BERT
|
||||||
|
|
||||||
|
## Note concernant les fichiers requirements
|
||||||
|
|
||||||
|
Les fichiers `*requirements.txt` ont été générés depuis un environnement Google Colab. Cet environnement inclut de nombreuses librairies préinstallées, dont toutes ne sont pas nécessaires au projet.
|
||||||
|
|
||||||
|
Un nettoyage manuel ou une génération spécifique des fichiers requirements sera nécessaire pour alléger ces fichiers avant un usage en production ou un déploiement.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Résumé des performances des modèles
|
||||||
|
|
||||||
|
### Modèles classiques (entraînés sur 200 000 tweets)
|
||||||
|
|
||||||
|
| Modèle | Précision | Temps d'entraînement|
|
||||||
|
|--------------------------------|-----------|---------------------|
|
||||||
|
| Random Forest + BoW | 0,7798 | ~5 heures |
|
||||||
|
| Régression logistique + TF-IDF | 0,7796 | <2 minutes |
|
||||||
|
|
||||||
|
### Modèles avancés basés sur des embeddings (entraînés sur 200 000 tweets, accélérés GPU sur Google Colab)
|
||||||
|
|
||||||
|
| Modèle | Précision | Temps d'entraînement|
|
||||||
|
|------------------------|-----------|---------------------|
|
||||||
|
| Word2Vec + LSTM | 0,797 | 57 secondes |
|
||||||
|
| GloVe (300d) + LSTM | 0,792 | 47 secondes |
|
||||||
|
|
||||||
|
### Modèle de pointe (entraîné sur 100 000 tweets en raison des limites RAM)
|
||||||
|
|
||||||
|
| Modèle | Précision | Temps d'entraînement|
|
||||||
|
|---------|-----------|---------------------|
|
||||||
|
| BERT | 0,882 | 1,3 minutes |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Ce résumé met en lumière les compromis entre précision des modèles et temps d’entraînement. Si les modèles classiques sont plus rapides à entraîner, les modèles avancés utilisant des embeddings et LSTM offrent une meilleure précision, avec BERT qui atteint la meilleure précision malgré un jeu de données plus restreint.
|
||||||
|
|
||||||
|
L’écart de précision entre BERT et les modèles à embeddings peut s’expliquer principalement par la capacité bidirectionnelle de BERT à comprendre le contexte.
|
||||||
|
|
@ -22,7 +22,7 @@ Manual cleanup or specific generation of requirements files will be needed to sl
|
||||||
### Classical Models (trained on 200,000 tweets)
|
### Classical Models (trained on 200,000 tweets)
|
||||||
|
|
||||||
| Model | Precision | Training Time |
|
| Model | Precision | Training Time |
|
||||||
|-----------------------------|-----------|-----------------|
|
|------------------------------|-----------|-----------------|
|
||||||
| Random Forest + BoW | 0.7798 | ~5 hours |
|
| Random Forest + BoW | 0.7798 | ~5 hours |
|
||||||
| Logistic Regression + TF-IDF | 0.7796 | <2 minutes |
|
| Logistic Regression + TF-IDF | 0.7796 | <2 minutes |
|
||||||
|
|
||||||
|
|
|
||||||
BIN
presentation/git_cd_docker.png
Normal file
BIN
presentation/git_cd_docker.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 187 KiB |
BIN
presentation/git_ci_tests.png
Normal file
BIN
presentation/git_ci_tests.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 184 KiB |
BIN
presentation/git_commands.png
Normal file
BIN
presentation/git_commands.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
Loading…
Add table
Reference in a new issue