Ce projet implémente un système de reconnaissance d'oiseaux basé sur des images, avec une infrastructure MLOps complète pour la gestion des données, l'entraînement, le déploiement et le monitoring du modèle.
- Application Modules principaux de l'application
- Data Données relatives au dataset d'entraînement du modèle
- Docker Répertoire contenant les données relatives aux différents conteneurs Docker
- Admin API Conteneur de l'API administrative
- Production Conteneur du modèle en production
- MLflow Conteneur de l'interface MLflow
- Monitoring Conteneur de surveillance de l'état de santé du système et du modèle en production
- Data processing Conteneur de traitement des données
- Streamlit Conteneur de l'interface Streamlit
- Training Conteneur d'entraînement
- User API Conteneur de l'API client
- Documentation Documentation détaillée du projet
- Logs Historique des logs générés pendant l'exécution des différents scripts
- MLRuns Historique des runs MLflow
- Models Historique des modèles
- Monitoring Scripts pour le monitoring et la détection de drift
- Preprocessing Scripts de traitement des données
- Temp images Stockage temporairement des images dans le cadre du fonctionnement de l'API et du modèle
- Scripts Scripts dédiés à la pipeline
- Tests Tests unitaires et d'intégration
- Tests d'intégration Tests d'intégration
- Tests unitaires Tests unitaires
- Training Scripts pour l'entraînement du modèle
- Upload de l'image :
- L'image est d'abord envoyée par l'utilisateur sur le serveur, où elle est conservée dans un fichier temporaire.
- Inférence :
- La prédiction de classe est effectuée en quelques centaines de millisecondes.
- Le résultat comprend les 3 classes les plus probables ainsi que leurs scores.
- Sont aussi affichées les images des classes en question pour aider l'utilisateur.
- Feedback :
- Si l'utilisateur indique que la prédiction est correcte, on ajoute son image au dataset.
- Si il indique que la prédiction est fausse mais connaît l'espèce, il l'indique et on ajoute son image au dataset.
- Si il ne connaît pas l'image, on ajoute son image dans un dossier qui sera traité plus tard.
Cette architecture supporte efficacement le flux de travail participatif, permettant une amélioration continue du modèle grâce aux contributions des utilisateurs.
- Gestion des données :
- Entièrement autonome.
- Responsable de l'acquisition, du nettoyage et de l'augmentation des données, y compris les nouvelles images soumises par les utilisateurs.
- Gère la création de nouvelles classes pour les espèces non répertoriées.
- Entraînement :
- Orchestre l'entraînement du modèle EfficientNetB0, s'adaptant aux nouvelles classes et données.
- Utilise MLflow pour le suivi des expériences et la gestion des versions, crucial avec l'évolution constante du dataset.
- Production :
- Héberge le modèle optimisé pour des prédictions en temps réel sur les nouvelles images soumises.
- Se met à jour régulièrement pour intégrer les améliorations basées sur les contributions des utilisateurs.
- API client :
- Fournit des endpoints pour la soumission d'images, la récupération des prédictions, et la gestion des contributions utilisateurs.
- Gère l'authentification et les autorisations pour sécuriser les contributions.
- API administrative :
- Fournit des endpoints pour la gestion des données, des utilisateurs et des entraînements, pour la comparaison des métriques et le choix du modèle en production.
- Interface :
- Interface Streamlit intuitive permettant aux utilisateurs de soumettre des images, voir les prédictions, et contribuer au dataset.
- Offre des visualisations des performances du modèle et de l'évolution du dataset.
- Monitoring :
- Surveille en temps réel les performances du modèle, particulièrement important avec l'ajout constant de nouvelles données.
- Détecte les drifts potentiels causés par l'évolution du dataset.
- MLflow :
- Centralise la gestion des expériences, des modèles et des métriques.
- Crucial pour suivre l'évolution du modèle avec l'intégration continue de nouvelles données et classes.
Cette architecture supporte efficacement le flux de travail participatif, permettant une amélioration continue du modèle grâce aux contributions des utilisateurs.
Notre pipeline permet une actualisation des données constantes ainsi qu'un modèle toujours performant et évolutif.
-
Arrivée de nouvelles données : Les données sont téléchargées et corrigées dans un dossier dataset_raw (données brutes) puis déplacées dans un dossier dataset_clean une fois ayant passé l'étape du traitement des données (preprocessing). Tout nouvelle image arrive d'abord dans dataset_raw et se retrouve plus tard dans dataset_clean lors du preprocessing, qu'elle soit ajoutée par l'utilisateur ou qu'elle provienne de Kaggle. Un processus automatique chaque jour vérifie la disponibilité d'un nouveau dataset sur Kaggle. Si une version plus récente est disponible, elle est téléchargée. Dès qu'un nouveau dataset est téléchargé, le preprocessing des données se lance directement.
-
Traitement des données : Lors du lancement d'un preproccessing, les labels du dataset Kaggle sont corrigés avec les noms corrects et qui correspondent à la liste qui permet d'ajouter une nouvelle espèce. Aussi, les dossiers train/test/valid sont répartis avec un équilibre de 70%/15%/15%. Le script s'assure de suivre les nouvelles images et classes :
- Lorsqu'un certain nombre de nouvelles images (au moins l'équivalent de 1% de la totalité du dataset) est ajouté par les utilisateurs, un preprocessing est lancé.
- Lorsqu'une nouvelle classe apparaît, elle ne passe jamais à travers le script de preprocessing, même si déclenché par les événements ci-dessus, tant qu'elle n'a pas suffisamment d'images. On considère qu'une classe est complète lorsqu'elle dispose au moins du même nombre d'images que la classe la plus petite de notre dataset. Lorsque la condition est remplie, un preprocessing se lance et cette classe se voit intégrée. Dès qu'un preprocessing est lancé, cela signifie que les données ont changé de manière suffisante pour déclencher une alerte aux administrateurs et les encourager à réentraîner le modèle.
-
Entraînement du modèle : Un entraînement du modèle peut-être déclenché manuellement par un administrateur, par exemple car il a reçu une alerte indiquant une dérive du modèle ou l'arrivée de nombreuses nouvelles données. Lorsqu'un entraînement est terminé, l'administrateur est notifié et les informations relatives au nouveau modèle sont enregistrées dans MLflow. Aussi, une matrice de confusion couplée avec un rapport de classification est sauvegardée pour faire état de la performance du modèle à sa création.
-
MLflow : Durant et après un entraînement, MLflow s'assure du suivi des métriques et de l'enregistrement des modèles ainsi que de la matrice évoquée plus haut. Il dispose d'une interface permettant d'afficher toutes les informations relatives aux entraînements et de faire les comparaisons nécessaires entre les modèles. Son intérêt est également de servir de moyen d'archive des modèles générés.
-
Évaluation du modèle : Une fois un entraînement terminé, l'administrateur peut afficher une comparaison entre le modèle en production et celui qui vient d'être entraîné. Pour cela, il dispose des deux métriques les plus importantes, à savoir la validation_accuracy et la validation_loss, mais également d'une liste des noms et scores des 10 classes sur lesquelles le modèle est le moins performant, permettant de faciliter la prise de décision pour changer de modèle.
-
Déploiement : Pour déployer le modèle, l'administrateur peut choisir parmi tous les modèles dans MLflow et simplement indiquer lequel passer en production. Le script chargé de l'inférence pour les utilisateurs charge en quelques secondes le nouveau modèle, sans interruption de service (seulement une attente si prédiction demandée en même temps que le changement de modèle).
-
Monitoring des performances : Grâce à la matrice de confusion enregistrée avec chaque modèle, tous les jours, une nouvelle matrice est générée et comparée avec l'originale du modèle. Grâce à cela, il est possible de détecter un drift du modèle,soit une perte de performance sur certaines classes qu'il connaît à cause de nouvelles images qui peuvent être trop différentes de son entraînement. Un rapport est envoyé tous les jours avec les 10 meilleures et pires classes ainsi que les classes qui dérivent (positivement ou négativement, s'il y en a).
-
Gestion des conflits Pour éviter des conflits entre les scripts de monitoring, de preprocessing et de training, chacun indique en permanence son état aux autres. Cela permet à l'un d'attendre que l'autre est fini pour se lancer et évite des erreurs ou corruption de données.
IMPORTANT : seule la version docker est à jour avec toutes les dernières améliorations. Le code le plus récent se situe donc uniquement dans le dossier "docker". Le reste du code est considéré comme ancien et ne doit être exécuté qu'à des fins d'expérimentation.
Version docker (recommandé) :
- Installez Docker Desktop et lancez le.
- Clonez le repository et aller dans le dossier "docker".
- Complétez le fichier .env situé dans le dossier "docker" (et non celui à la racine) avec vos identifiants Gmail (il ne faut pas utiliser le mot de passe du compte, mais générez un "App password" via l'interface de gestion du compte Google). 3.1. Si les identifiants sont déjà présents, indiquez simplement le mail qui recevra les alertes.
- Ajoutez ensuite dans le même .env vos identifiants Kaggle (connectez-vous à votre compte kaggle.com puis "Settings > API > Create New Token").
Version sans docker (non recommandé) :
- Clonez ce repository.
- Installez les dépendances :
pip install -r requirements.txt
- Complétez le fichier .env situé à la racine du projet avec vos identifiants Gmail (il ne faut pas utiliser le mot de passe du compte, mais générez un "App password" via l'interface de Gestion du compte Google).
- Ajoutez ensuite dans le même .env vos identifiants Kaggle (connectez-vous à votre compte kaggle.com puis "Settings > API > Create New Token").
Version docker (recommandé) :
- Entrez dans le répertoire "docker" du projet avec le terminal
- Exécutez
./clean.ps1
sur Windows ou./clean.sh
sur Linux (il faut exécuter cette commande avant tout docker compose, à chaque fois) 2.1 Il est possible de commenter ou non la ligne supprimant le volume :docker volume rm docker_main_volume
. Il est préférable de la commenter si l'on ne souhaite pas tout télécharger à nouveau. - Si vous avez une carte graphique Nvidia :
docker-compose -f docker-compose-nvidia.yml up
- Si vous n'avez pas de carte graphique Nvidia ou vous n'êtes pas sur :
docker-compose -f docker-compose.yml up
- IMPORTANT : lors de la création du volume, le dataset sera téléchargé et le preprocessing lancé. Les routes des API indiqueront qu'il faut attendre mais l'interface Streamlit peut indiquer des erreurs. Il suffit de patienter jusqu'à recevoir le mail de confirmation à la fin de l'opération.
Version sans docker (non recommandé) :
- Pour exécuter la pipeline complète :
python scripts/pipeline.py
- Pour télécharger le dataset :
python scripts/downloadDataset.py
- Pour effectuer le traitement obligatoire des données :
python preprocessing/preprocess_dataset.py
- Pour entraîner le modèle :
python training/train_model.py
- Pour télécharger le dataset :
- Pour lancer l'interface Streamlit :
streamlit run streamlit_app.py
Les pull requests sont les bienvenues. Pour des changements majeurs, veuillez d'abord ouvrir une issue pour discuter de ce que vous aimeriez changer.