Dans ce projet, je suis dans le rôle d´un freelance en ML en mission pour Futurisys. Mon but est de déployer un modèle de ML de prédiction de départ d´employer.
Pour cela je pars de mon projet précédent (4) où je dispose de mon notebook contenant mon modèle entrainé.
L´objectif est de rendre le modèle utilisable en production tout en respectant les meilleurs pratiques de l´ingénierie logicielle.
Pour cela j´ai donc développé une API REST de pédiction du démission avec FastAPI. Cette API expose un modèle de régression logisitque entrainé sur 1468 employés. Elle stocke les données ainsi que les prédiction dans une base PostgrSQL.
Structure du dépôt GIT
Structure de base:
ocr_p5/
|
├── scripts # Scripts utilitaires
│ ├── create_db.py # Script pour la création de la base de données et des tables
│ └── import_data.py # Script pour l´import des CSV dans la base de données
|
├── src # Code source de l´API
│ ├── data # Data d´entrée pour peupler la base de données
│ │ ├── extrait_eval.csv
│ │ ├── extrait_sirh.csv
│ │ └── extrait_sondage.csv
│ ├── models
│ │ ├── evaluation_pipeline.joblib # Pipeline d´evaluation (contient le modèle de regression)
│ ├── database.py # Connexion PostgreSQL
│ ├── __init__.py
│ ├── logging.py # middleware de logging des intéractions
│ ├── main.py # Point d´entrée FastAPI
│ ├── models.py # Modèles SQLAlchemy
│ ├── pipeline_loader.py # Chargement de la pipeline de prédiction
│ └── schemas.py # Definition des schemas Pydantic
|
├── tests # Tests unitaires et d'intégration
│ ├── conftest.py
│ ├── test_api.py
│ └── test_model.py
|
├── gitlab-ci.yml # Pipeline CI/CD
├── docker-compose.yml
├── Dockerfile
├── pyproject.toml
├── README.md # README
├── requirements.txt
└── uv.lock
Branches:
main : code stable, prêt pour la production.
dev : Intégration des fonctinnalités testées.
features/* : une branche par fonctionnalité.
Installation
Prérequis
Python 3.13+
Docker (pour avoir la base de donnée en local avec docker compose)
tests/conftest.py Fixtures pour les différents tests
tests/test_api.py Test des endpoint HTTP
tests/test_model.py Test de fonctionnement du modèle de prédiction
Déploiement
Le déploiement se fait automatiquement sur le space hugging face si push sur la branche dev ou sur la branche main.
Pour que cela fonctionne, la variable HF_TOKEN doit être déclaré dans gitlab et elle doit contenir le token huggingface avec les droits d´écriture sur les spaces de production et de dev.
2 - Préparation du modèle pour déploiement
J´ai extrait modèle de mon ancien notebook avec la commande suivante:
J´ai ensuite placer le ficheir "model.joblib" dans /src.
Mais ce model ne contient pas les deux étapes nécessaires à sont foncitonnement à savoir l´encodage des variables catégorielles et la standardisation des variables numériques. J´ai donc aussi extrait la pipeline complète de mon notebook et l´ai stocker dans /src. (evaluation_pipeline.joblib).
Avoir la pipeline complète va m´éviter de devoir recode l´encodage et la standardisation.
Je crée ensuite un script python qui charge ma pipeline (pipeline_loader.py). Dans ce script, je crée aussi une fonction qui permet de prédire avec le modèle. Dans cette fonction je dois ajouter le code pour vérifier que les données d´entrée sont au bon format (celui attendu par la pipeline).
[ ] Ajouter le code pour vérifier le bon format des données d´entrée dans la fonction predict de pipeline_loarder.py
3 - Développer l´API avec FastAPI et CI
Je commencer par créer ma branche dev.
Ajout de "fastapi" dans les dépendances avec uv add fastapi.
Création de l´app fastAPI dans main.py.
Ajout de "uvicorn" pour implementer le web server.
Pour lancer l´app, uvicorn main:app. Cela lancer le serveur sur http://127.0.0.1/8000.
Pour tester le fonctionnement de mon API, j´ai créé 2 endpoints:
get("/") qui renvoie un simple Hello World
get("/predict") qui renvoie la prédiction du premier élément lorsque j´envoie la totalité des data nettoyées (Dataframe extrait de mon projet précédent).
Cela me permet de valider le fonctionnement de mon serveur et celui de ma pipeline(OneHot + standardisation + modèle).
La base fonctionne. Maintenant je dois définir quelles sont les fonctionnalité que je souhaite avoir pour mon API.
Avant de commencer le développement de l´API, je dois mettre en place ma board pour la planification.
Dans le dépôt gitlab, j´ai créé mes labels, ma board. Je commence très simple avec une seule board: 'Development', contenant 2 colonnes 'To Do' et 'Doing', et seulement un 'type' de carte 'user story'. Cela me permet de commencer rapidement et facilement. Ceci étant la première fois que j´utilise cette méthodes et ce projet étant solo, je ne veux pas trop alourdir la méthodes de projet.
Cela ne m´empèche pas de la faire évoluer au fur et à mesure du projet en ajoutant des labels comme 'Epic' ou 'Evil User Story'.
Maintenant que j´ai créé la structure pour accueillir les User Stories, je peux commencer à en créer.
CREATION DE USER STORIES
Avec quelques User Stories de créées, je peux commencer le développement.
Les fonctionnalités de mon API dépendent de ma base de données. Je dois donc définir sa structure.
- Base de données
Les données d´entrée sont sous forme de 3 fichiers CSV fourni par les RH.
Afin de respecter la structure des CSV, je vais créer 3 tables avec les champs des CSV. J´ajouter les clés étrangères pour relier les tables.
Je crée aussi une table prediction pour stocker les prédictions.
Je rédige donc un script init_db.sql qui crée les tables.
Je créer une branche pour le développement de ma première feature: l´API FastAPI
Sur ma branche feature, je commence donc le développement en partant de mes User Story.
Ajout de ruff dans la pipeline CI et en pre-commit
Le but est ici d´ajouter le linter et formater ruff dans la pipeline CI mais aussi dans le pre-commit.
Je commence donc par ajouter ruff avec la commande:
uv add --dev ruff--dev car ruff ne sert pas en production.
Lancer les tests en local:
uv run uvicorn src.main:app --reload
export PYTHONPATH="${PYTHONPATH}:$(pwd)"
uv run pytest tests/ --cov=src --cov-report=term-missing
Se connecter à la base de donnée en local:
sudo -u postgres psql
Ajouter les droits à user1:
GRANT ALL PRIVILEGES ON DATABASE futurisys TO user1;
\c futurisys
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO user1;
Lancer l´app en local:
uv run uvicorn src.main:app --reload
AAAAAAA
CREATE USER user1 WITH PASSWORD 'password1' CREATEDB;
Changer le mode d´authentification ident => md5 dans pg_hba.conf (pour tourver le chemin: sudo find / -name pg_hba.conf 2>/dev/null
)
Puis sudo find / -name pg_hba.conf 2>/dev/null
Ensuite je peux lancer le script de création de la base et des tables:
uv run scripts/create_db.py
Ensutie je peux lancer le script d´import des CSV pour peupler la DB:
uv run scripts/import_data.py