JeanProjets commited on
Commit
1a8e402
·
verified ·
1 Parent(s): d9c804c

Upload folder using huggingface_hub

Browse files
.gcloudignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ .git
2
+ .github
3
+ .venv
4
+ __pycache__
5
+ notebooks/
.gitattributes CHANGED
@@ -33,3 +33,6 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ app/Screenshot_streamlit_app.png filter=lfs diff=lfs merge=lfs -text
37
+ mlflow.db filter=lfs diff=lfs merge=lfs -text
38
+ models/best_unet_model.keras filter=lfs diff=lfs merge=lfs -text
Livrables.md ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Livrables
2
+
3
+
4
+ Les scripts développés sur un notebook permettant l’exécution du pipeline complet :
5
+ Ce livrable vous servira à présenter le caractère “industrialisable” de votre travail en particulier le générateur de données.
6
+ Une API (Flask ou FastAPI) déployée sur le Cloud (Azure, Heroku, PythonAnywhere ou toute autre solution), pour exposer votre modèle entraîné et qui recevra en entrée une image et retournera le mask prédit (les segments identifiés par votre modèle) :
7
+ Ce livrable permettra à Laura d’utiliser facilement votre modèle.
8
+ Une application (Flask, Streamlit) de présentation des résultats qui consomme l’API de prédiction, déployée sur le Cloud (Azure, Heroku, PythonAnywhere ou toute autre solution). Cette application sera l’interface pour tester l’API et intégrera les fonctionnalités suivantes : affichage de la liste des id des images disponibles, lancement de la prédiction du mask pour l’id sélectionné par appel à l’API, et affichage de l’image réelle, du mask réel et du mask prédit :
9
+ Ce livrable permettra d’illustrer votre travail auprès de vos collègues
10
+ Une note technique de 10 pages environ contenant une présentation des différentes approches et une synthèse de l’état de l’art, la présentation plus détaillée du modèle et de l’architecture retenue, une synthèse des résultats obtenus (incluant les gains obtenus avec les approches d’augmentation des données) et une conclusion avec des pistes d’amélioration envisageables :
11
+ Ce livrable vous servira à présenter votre démarche technique à vos collègues.
12
+ Un support de présentation (type Power Point) de votre démarche méthodologique (30 slides maximum) :
13
+ Ce livrable vous permettra de présenter vos résultats à Laura.
14
+ Déposez sur la plateforme, dans un dossier zip nommé “Titre_du_projet_nom_prénom”, votre livrable nommé comme suit : Nom_Prénom_n° du livrable_nom du livrable_date de démarrage du projet. Cela donnera :
15
+
16
+ Nom_Prénom_1_scripts_mmaaaa
17
+ Nom_Prénom_2_API_mmaaaa
18
+ Nom_Prénom_3_application_Flask_mmaaaa
19
+ Nom_Prénom_4_note_technique_mmaaaa
20
+ Nom_Prénom_5_presentation_mmaaaa
21
+ Par exemple, votre premier livrable peut être nommé comme suit : Dupont_Jean_1_scripts_012024.
22
+
23
+
24
+
25
+ # Soutenance:
26
+
27
+
28
+ Pendant la soutenance, l’évaluateur ne jouera aucun rôle en particulier. Vous lui présenterez l’ensemble de votre travail.
29
+
30
+ Présentation (20 minutes)
31
+ Présentation du contexte, des objectifs, des principes de segmentation et des mesures de performance qui seront utilisées pour comparer les modèles (5 minutes)
32
+ Présentation des différents modèles, simulations et comparaisons des modèles (10 minutes).
33
+ Mise en production d’un modèle (5 minutes) :
34
+ Architecture API et application Web et démarche de mise en production sur le Cloud choisi par l’étudiant
35
+ démonstration de fonctionnement de l’application et de la prédiction de segmentation d’une image (mask).
36
+ Discussion (5 minutes)
37
+ L’évaluateur vous challengera sur vos choix.
38
+ Débriefing (5 minutes)
39
+ À la fin de la soutenance, vous pourrez débriefer ensemble.
40
+ Votre présentation devrait durer 20 minutes (+/- 5 minutes). Puisque le respect des durées des présentations est important en milieu professionnel, les présentations en dessous de 15 minutes ou au-dessus de 25 minutes peuvent être refusées.
41
+
42
+ Concernant la mise en production de l’API, plusieurs solutions s’offrent à vous, en particulier Azure webapp, AWS et Heroku. À vous de choisir la solution qui vous convient le mieux.
43
+
44
+ Dans le cadre de l’utilisation de Heroku, étant devenu payant depuis fin novembre 2022, les coûts liés à votre projet seront à votre charge. Vous êtes donc libre de vous investir financièrement si vous le souhaitez, mais vous n’avez aucune obligation de le faire pour réaliser ce projet.
45
+
46
+ Quelque soit la solution Cloud choisie, l'étudiant et l'évaluateur veilleront à enregistrer pendant la soutenance la démo de l'application en production, ce qui permettra au jury de visionner cette démo, sans que l'étudiant n'ait à maintenir son application sur le Cloud. Maintenir l’application dans le Cloud pourrait en effet engendrer des coûts.
Project_description.md ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Projet_8
2
+
3
+ Future Vision Transport est une entreprise qui conçoit des systèmes embarqués de vision par ordinateur pour les véhicules autonomes.
4
+
5
+ Vous êtes l’un des ingénieurs IA au sein de l’équipe R&D de cette entreprise. Votre équipe est composée d’ingénieurs aux profils variés. Chacun des membres de l’équipe est spécialisé sur une des parties du système embarqué de vision par ordinateur.
6
+
7
+ Voici les différentes parties du système :
8
+
9
+ acquisition des images en temps réel
10
+ traitement des images
11
+ segmentation des images (c’est vous !)
12
+ système de décision
13
+ Vous travaillez sur la partie de segmentation des images (3) qui est alimentée par le bloc de traitement des images (2) et qui alimente le système de décision (4).
14
+
15
+ Votre rôle est de concevoir un premier modèle de segmentation d’images qui devra s’intégrer facilement dans la chaîne complète du système embarqué.
16
+
17
+ Lors d’une première phase de cadrage, vous avez récolté les avis de Franck et Laura, qui travaillent sur les parties avant et après votre intervention :
18
+
19
+ Franck, en charge du traitement des images (2) :
20
+
21
+ Le jeu de données que Franck utilise est disponible à ce lien, ou en téléchargement direct à ces liens : 1 ou 2, (images segmentées et annotées de caméras embarquées). On a uniquement besoin des 8 catégories principales (et non pas des 32 sous-catégories)
22
+ Laura, en charge du système de décision (4)
23
+
24
+ Souhaite une API simple à utiliser.
25
+ L’API prend en entrée une image et renvoie la segmentation de l’image de l’algo.
26
+
27
+ Pour récapituler, vous avez dressé un plan d’action, avec les points suivants :
28
+
29
+ entraîner un modèle de segmentation des images sur les 8 catégories principales. Keras est le framework de travail commun à toute l’équipe. Attention aux contraintes de Franck !
30
+ concevoir une API de prédiction (Flask ou FastAPI) qui sera utilisée par Laura et la déployer sur le Cloud (Azure, Heroku, PythonAnywhere ou toute autre solution). Cette API prend en entrée une image et renvoie le mask prédit (segments prédits de l’image).
31
+ concevoir une application web (Flask, Streamlit) de présentation des résultats et la déployer sur le Cloud (Azure, Heroku, PythonAnywhere ou toute autre solution). Cette application sera l’interface pour tester l’API et afficher les images et masks.
README.md CHANGED
@@ -1,11 +1,10 @@
1
  ---
2
- title: Projet 8 Api
3
- emoji: 🏃
4
- colorFrom: yellow
5
- colorTo: yellow
6
  sdk: docker
7
  pinned: false
8
- short_description: Partie API de mon projet 8 contenant le modèle keras
 
9
  ---
10
-
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: Projet 8 API
3
+ emoji: 🚀
4
+ colorFrom: blue
5
+ colorTo: indigo
6
  sdk: docker
7
  pinned: false
8
+ app_port: 7860
9
+ dockerfile: api/Dockerfile
10
  ---
 
 
README_API.md ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Ce dossier, P7, est le projet 7 avant que je ne fasse le docker init. J'ai cloné le projet qui s'appelle maintenant Projet_7 dans lequel je fais le docker init.
2
+
3
+
4
+ Build l'image Docker:
5
+
6
+ docker build \
7
+ -t predictionsentiments \
8
+ -f Projet_7_API/Dockerfile Projet_7_API
9
+
10
+ Runner l'image Docker:
11
+ docker run -p 8000:8000 --name predictionsentiments_container predictionsentiments
12
+
13
+ POur accéder à la documentation:
14
+ http://0.0.0.0:8000/docs
15
+
16
+ # AZURE PORTAL : Pour vérifier où mes images docker sont:
17
+ container registries dans la barre de recherche Azure
18
+ Services < dépôts
19
+ predictionsentimentsregistry est mon registry situé dans mes Dépôts Azure
20
+ L'application est déployée via le 'app service'
21
+
22
+ # MLflow
23
+ Pour lancer MLFlow il faut taper 'mlflow server'
24
+ Ensuite, aller à http://127.0.0.1:5000/
25
+
26
+
27
+ # Lancer l'application
28
+ cd Projet_8_API
29
+ uvicorn main:app --host 0.0.0.0 --port 8000
30
+ uvicorn main:app --host 0.0.0.0 --port 8000 --reload
31
+
32
+
33
+
34
+ # Feeling classifier
35
+
36
+ Pour lancer l'API
37
+
38
+ fastapi dev main.py
39
+
40
+ Ouvir http://127.0.0.1:8000/docs
41
+
42
+ A faire:
43
+
44
+ - Installer Docker Desktop
45
+ - Faire un Dockerfile avec l'api dedans et qui marche
46
+ - Creer un Github
47
+ - Creer un Github workflow pour build l'image
48
+ - Creer un compte Azure, creer une azure app
49
+ - Deployer l'image de Github sur Azure app,
50
+ - Avoir l'API qui fonctionne sur Azure APP
51
+
52
+ # Fonctionnement de main.py
53
+
54
+ main.py :
55
+ Le modèle est chargé dynamiquement au lancement de l'API via lifespan pour une meilleure gestion de la mémoire.
56
+ Le point de terminaison /segmentation a été mis à jour : il convertit désormais l'image entrante, la redimensionne en 256x512, la normalise, fait la prédiction via notre modèle Keras, et génère un masque coloré basé sur les couleurs Cityscapes.
57
+ L'image du masque est finalement renvoyée via StreamingResponse au format PNG, ce qui est le standard le plus optimisé pour les API d'images avec FastAPI.
58
+ Un point de terminaison /health a été ajouté pour vérifier si l'API est saine et le modèle bien chargé.
59
+ Attention : Comme mentionné dans le Walkthrough, bien que notre modèle soit léger, TensorFlow reste une librairie très lourde en RAM. S'il s'avère que l'API crashe par manque de mémoire sur Render (limite de 512 Mo), il faudra envisager de convertir notre modèle en format TFLite ou ONNX.
60
+
61
+ Si un jour j'ai un serveur plus puissant et je souhaite changer de modèle il suffira de changer la variable MODEL_PATH = 'best_mobilenet_unet_model.keras' dans le main.py
api/Dockerfile ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ ENV PYTHONDONTWRITEBYTECODE=1
4
+ ENV PYTHONUNBUFFERED=1
5
+
6
+ WORKDIR /app
7
+
8
+ RUN apt-get update && apt-get install -y --no-install-recommends \
9
+ build-essential \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ COPY api/requirements.txt .
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ COPY api/ api/
16
+ COPY models/ models/
17
+
18
+ WORKDIR /app/api
19
+
20
+ # --- Configuration du port (Décommenter selon le Cloud choisi) ---
21
+
22
+ # Pour Google Cloud Run (ou local standard) :
23
+ # EXPOSE 8000
24
+ # CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
25
+
26
+ # Pour Hugging Face Spaces (Port 7860 par défaut) :
27
+ EXPOSE 7860
28
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "7860"]
api/main.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import io
3
+ import logging
4
+ from contextlib import asynccontextmanager
5
+
6
+ from fastapi import FastAPI, UploadFile, File
7
+ from fastapi.responses import StreamingResponse
8
+ from PIL import Image
9
+ import numpy as np
10
+
11
+ # Setup logger
12
+ logging.basicConfig(
13
+ level=logging.INFO,
14
+ format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
15
+ )
16
+ logger = logging.getLogger(__name__)
17
+
18
+ # Note : Le code pour Azure Log Analytics peut être configuré ici
19
+ # en utilisant azure-monitor-opentelemetry (si la clé de connexion est fournie via env)
20
+ # try:
21
+ # from azure.monitor.opentelemetry import configure_azure_monitor
22
+ # if "APPLICATIONINSIGHTS_CONNECTION_STRING" in os.environ:
23
+ # configure_azure_monitor()
24
+ # except ImportError:
25
+ # pass
26
+
27
+ CLASSES = ['void', 'flat', 'construction', 'object', 'nature', 'sky', 'human', 'vehicle']
28
+ COLORS = [
29
+ [0, 0, 0], [128, 64, 128], [70, 70, 70], [153, 153, 153],
30
+ [107, 142, 35], [70, 130, 180], [220, 20, 60], [0, 0, 142]
31
+ ]
32
+
33
+ # Variables globales pour l'état de l'application
34
+ model = None
35
+ MODEL_PATH = os.path.join(os.path.dirname(__file__), '../models/best_unet_model.keras')
36
+
37
+ @asynccontextmanager
38
+ async def lifespan(app: FastAPI):
39
+ global model
40
+ if os.path.exists(MODEL_PATH):
41
+ try:
42
+ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
43
+ import tensorflow as tf
44
+ logger.info("⏳ Chargement du modèle Keras...")
45
+ model = tf.keras.models.load_model(MODEL_PATH, compile=False)
46
+ logger.info("✅ Modèle chargé avec succès !")
47
+ except Exception as e:
48
+ model = None
49
+ logger.error(f"❌ Erreur critique de TensorFlow : {e}")
50
+ else:
51
+ logger.warning(f"⚠️ Modèle introuvable ({MODEL_PATH}). L'API tourne en 'MOCK MODE'.")
52
+ yield
53
+ # Nettoyage si nécessaire
54
+ model = None
55
+
56
+ app = FastAPI(
57
+ title="Cityscapes Segmentation API",
58
+ description="API de segmentation sémantique pour Future Vision Transport",
59
+ version="1.0",
60
+ lifespan=lifespan
61
+ )
62
+
63
+ @app.get("/")
64
+ async def root():
65
+ return {"message": "Service back-end de prédiction Actif."}
66
+
67
+ @app.get("/health")
68
+ def health_check():
69
+ return {"status": "ok", "model_active": model is not None}
70
+
71
+ @app.post("/segmentation")
72
+ async def segmentation(file: UploadFile = File(...)):
73
+ # Lire l'image envoyée
74
+ image_bytes = await file.read()
75
+ image = Image.open(io.BytesIO(image_bytes)).convert('RGB')
76
+
77
+ IMG_HEIGHT, IMG_WIDTH = 256, 512
78
+ img_resized = image.resize((IMG_WIDTH, IMG_HEIGHT))
79
+
80
+ if model is not None:
81
+ # Prétraitement de l'image
82
+ img_array = np.array(img_resized) / 255.0
83
+ img_batch = np.expand_dims(img_array, axis=0)
84
+
85
+ # Prédiction
86
+ prediction = model.predict(img_batch, verbose=0)[0]
87
+ mask_classes = np.argmax(prediction, axis=-1).astype(np.uint8)
88
+ else:
89
+ # Mock Mode : générer un masque vide si aucun modèle n'est chargé
90
+ mask_classes = np.zeros((IMG_HEIGHT, IMG_WIDTH), dtype=np.uint8)
91
+
92
+ # Colorisation du masque
93
+ mask_colored = np.zeros((IMG_HEIGHT, IMG_WIDTH, 3), dtype=np.uint8)
94
+ for class_id, color in enumerate(COLORS):
95
+ mask_colored[mask_classes == class_id] = color
96
+
97
+ mask_img = Image.fromarray(mask_colored)
98
+
99
+ # Convertir l'image en bytes pour la réponse
100
+ img_io = io.BytesIO()
101
+ mask_img.save(img_io, format="PNG")
102
+ img_io.seek(0)
103
+
104
+ return StreamingResponse(img_io, media_type="image/png")
api/requirements.txt ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ fastapi==0.128.8
2
+ uvicorn==0.39.0
3
+ python-multipart==0.0.20
4
+ tensorflow-cpu==2.14.0
5
+ numpy
6
+ pillow
7
+ azure-monitor-opentelemetry
app/Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ # On installe les requirements de l'application
6
+ COPY app/requirements.txt .
7
+ RUN pip install --no-cache-dir -r requirements.txt
8
+
9
+ # On copie le code de l'application et la donnée (images de test)
10
+ COPY app/ app/
11
+ COPY data/ data/
12
+
13
+ # --- Configuration du port (Décommenter selon le Cloud choisi) ---
14
+
15
+ # Pour Google Cloud Run (ou local standard) :
16
+ # EXPOSE 8501
17
+ # CMD ["streamlit", "run", "app/app.py", "--server.port", "8501", "--server.address", "0.0.0.0"]
18
+
19
+ # Pour Hugging Face Spaces (Port 7860 par défaut) :
20
+ EXPOSE 7860
21
+ CMD ["streamlit", "run", "app/app.py", "--server.port", "7860", "--server.address", "0.0.0.0"]
app/Screenshot_streamlit_app.png ADDED

Git LFS Details

  • SHA256: f50825e181c837a098415cf927920c8865599766df29adf5e93906427a672674
  • Pointer size: 131 Bytes
  • Size of remote file: 871 kB
app/app.py ADDED
@@ -0,0 +1,104 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import requests
3
+ import glob
4
+ import os
5
+ from PIL import Image
6
+ import base64
7
+ import io
8
+
9
+ # --- 1. Configuration UI ---
10
+ st.set_page_config(page_title="Future Vision Transport - Démos", layout="wide", page_icon="🚗")
11
+
12
+ st.title("🚗 Segmentation Sémantique Embarquée")
13
+ st.markdown("Interface d'Inférence interagissant en direct avec l'API FastAPI construite lors de la Phase 5.")
14
+
15
+ # Cible du Microservice API
16
+ # --- Configuration du port local (Décommenter selon le Cloud choisi) ---
17
+ # Si tu testes pour GCP (Port 8000) :
18
+ # API_URL = os.getenv("API_URL", "http://localhost:8000")
19
+ # Si tu testes pour Hugging Face (Port 7860) :
20
+ API_URL = os.getenv("API_URL", "http://localhost:7860")
21
+
22
+ # --- 2. Fonctions Méthodologiques ---
23
+ @st.cache_data
24
+ def load_available_images():
25
+ """
26
+ Scanne intelligemment le dossier de Test pour remonter toute la flotte d'images réelles (Phase 6.1).
27
+ Utilise le cache de Streamlit pour ne pas faire mouliner le disque dur à chaque clic !
28
+ """
29
+ img_dir = "data/P8_Cityscapes_leftImg8bit_trainvaltest/leftImg8bit/test/"
30
+ if not os.path.exists(img_dir):
31
+ return []
32
+
33
+ image_paths = sorted(glob.glob(os.path.join(img_dir, "**/*_leftImg8bit.png"), recursive=True))
34
+ return image_paths
35
+
36
+ images_list = load_available_images()
37
+
38
+ if not images_list:
39
+ st.error("⚠️ **Stop !** Dossier des images introuvable. J'ai cherché dans `data/P8_Cityscapes_leftImg8bit_trainvaltest`. Êtes-vous sûr d'avoir lancé `streamlit run app/app.py` depuis la racine de `Projet_8` ?")
40
+ st.stop()
41
+
42
+ # --- 3. Barre de Menu (Sidebar) ---
43
+ st.sidebar.header("🕹 Tableau de Bord")
44
+ st.sidebar.markdown("Sélectionnez l'image issue des caméras embarquées pour la transmettre au réseau de neurones.")
45
+
46
+ # On allège visuellement la liste déroulante en n'affichant que le nom du fichier
47
+ images_names = [os.path.basename(p) for p in images_list]
48
+ selected_filename = st.sidebar.selectbox("Fichier à analyser :", images_names)
49
+ selected_path = images_list[images_names.index(selected_filename)]
50
+
51
+ # Algorithme pour reconstruire le chemin du "Ground Truth Color" (Masque Parfait) de Cityscapes
52
+ city_name = selected_filename.split('_')[0]
53
+ gt_color_filename = selected_filename.replace('_leftImg8bit.png', '_gtFine_color.png')
54
+ gt_color_path = os.path.join("data/P8_Cityscapes_gtFine_trainvaltest/gtFine/test/", city_name, gt_color_filename)
55
+
56
+ # --- 4. Le Client REST ---
57
+ if st.sidebar.button("🤖 Lancer l'Inférence de l'API"):
58
+ st.markdown("---")
59
+
60
+ with st.spinner("⏳ Transmission sécurisée à l'API FastAPI en cours..."):
61
+ try:
62
+ # Sérialisation : On capture l'image en données binaires pour le flux HTTP sortant
63
+ with open(selected_path, "rb") as image_file:
64
+ # payload 'multipart/form-data'
65
+ files = {"file": (selected_filename, image_file, "image/png")}
66
+ response = requests.post(f"{API_URL}/segmentation", files=files)
67
+
68
+ # Si le serveur nous envoie un Code HTTP 200 (Succès Total)
69
+ if response.status_code == 200:
70
+ # L'API nous renvoie désormais directement l'image au format PNG ! (StreamingResponse)
71
+ predicted_mask = Image.open(io.BytesIO(response.content))
72
+
73
+ st.success("✅ Triangulation serveur réussie ! Prédiction récupérée depuis l'API.")
74
+
75
+ # --- VISUALISATION DES 3 COMPOSANTES (Phase 6.1 Guideline) ---
76
+ col1, col2, col3 = st.columns(3)
77
+
78
+ # A. La Réalité Capturée
79
+ col1.subheader("📸 Caméra (leftImg8bit)")
80
+ col1.image(Image.open(selected_path), use_container_width=True)
81
+
82
+ # B. Le Masque Parfait fourni par Cityscapes
83
+ col2.subheader("🎯 Masque Vérité (Attendu)")
84
+ if os.path.exists(gt_color_path):
85
+ col2.image(Image.open(gt_color_path), use_container_width=True)
86
+ else:
87
+ col2.warning("Non fourni (Normal pour le Test-Set de compétition).")
88
+
89
+ # C. L'Intelligence Artificielle en Action
90
+ col3.subheader("🧠 Prédiction FastAPI (Notre IA)")
91
+ col3.image(predicted_mask, use_container_width=True)
92
+
93
+ # Affichage des classes (Codées en dur ici car l'API renvoie directement une image pour optimiser)
94
+ CLASSES = ['void', 'flat', 'construction', 'object', 'nature', 'sky', 'human', 'vehicle']
95
+ with st.expander("Consulter la palette de couleurs sémantiques 🎨"):
96
+ st.write(", ".join(CLASSES))
97
+
98
+ else:
99
+ st.error(f"❌ Erreur Serveur (HTTP {response.status_code}) : Vous devez vérifier ce que l'API imprime dans son propre terminal.")
100
+
101
+ except requests.exceptions.ConnectionError:
102
+ st.error(f"💥 ERREUR CRITIQUE : L'API est injoignable sur l'URL ciblée (`{API_URL}`).")
103
+ # st.info("👉 Si vous testez en local pour GCP, lancez le serveur FastAPI via : `cd api && uvicorn main:app --port 8000` et vérifiez l'API_URL.")
104
+ st.info("👉 Si vous testez en local pour Hugging Face, lancez le serveur FastAPI via : `cd api && uvicorn main:app --port 7860` et vérifiez l'API_URL.")
app/requirements.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ streamlit==1.50.0
2
+ requests==2.32.5
3
+ pillow==11.3.0
guide_projet_8.md ADDED
@@ -0,0 +1,523 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 🚗 Guide Complet — Projet 8 : Déploiement d'un Modèle de Segmentation d'Images
2
+
3
+ > **Contexte** : Tu es ingénieur IA chez *Future Vision Transport*. Tu conçois le module de **segmentation d'images** dans une chaîne de vision embarquée pour véhicules autonomes. Le dataset est **Cityscapes**, le framework imposé est **Keras**, et tu dois livrer un modèle + API + application web déployés sur le Cloud.
4
+
5
+ ---
6
+
7
+ ## Phase 0 — Mise en place de l'environnement
8
+
9
+ ### 0.1 Créer un environnement virtuel Python dédié
10
+ ```bash
11
+ python -m venv venv_projet8
12
+ source venv_projet8/bin/activate
13
+ pip install tensorflow keras numpy pandas matplotlib opencv-python albumentations flask fastapi uvicorn streamlit
14
+ ```
15
+ - **Why** : Isoler les dépendances évite les conflits entre projets. C'est une pratique professionnelle standard.
16
+ - **Notions** : *virtual environments*, gestion de dépendances avec `pip`, `requirements.txt`.
17
+
18
+ ### 0.2 Structurer le répertoire de travail
19
+ ```
20
+ Projet_8/
21
+ ├── data/ # Données Cityscapes (déjà présent)
22
+ ├── notebooks/ # Notebooks d'exploration et d'entraînement
23
+ ├── src/ # Code source réutilisable (data generator, model, utils)
24
+ ├── api/ # Code de l'API Flask/FastAPI
25
+ ├── app/ # Code de l'application web Streamlit/Flask
26
+ ├── models/ # Modèles sauvegardés (.h5, .keras)
27
+ ├── docs/ # Note technique + supports de présentation
28
+ └── requirements.txt
29
+ ```
30
+ - **Why** : Une structure claire rend le projet "industrialisable" (critère évalué dans les livrables) et facilite la collaboration.
31
+ - **Notions** : *project scaffolding*, bonnes pratiques d'organisation de projets ML.
32
+
33
+ ### 0.3 Initialiser un dépôt Git
34
+ ```bash
35
+ git init
36
+ echo "venv_projet8/\ndata/\nmodels/*.h5\n__pycache__/" > .gitignore
37
+ ```
38
+ - **Why** : Le versionnement est indispensable pour tracer l'évolution du code, revenir en arrière, et montrer ta démarche.
39
+ - **Notions** : *Git*, versionnement, `.gitignore`.
40
+
41
+ ---
42
+
43
+ ## Phase 1 — Comprendre les données Cityscapes
44
+
45
+ ### 1.1 Télécharger le jeu de données complet
46
+ > ⚠️ **Observation** : Ton dossier [data/](file:///Users/j/Documents/OC_Inge_IA/Projet_8/data) contient actuellement uniquement les **annotations gtFine** (masks de segmentation), pas les images brutes. Tu dois télécharger les images `leftImg8bit` depuis [cityscapes-dataset.com](https://www.cityscapes-dataset.com/).
47
+
48
+ - **Why** : Ton modèle prend en entrée les **images caméra** (leftImg8bit) et doit prédire les **masks de segmentation** (gtFine). Sans les images, tu ne peux pas entraîner.
49
+ - **Notions** : *supervised learning*, notion d'images d'entrée vs. ground truth / labels.
50
+
51
+ ### 1.2 Comprendre la structure des fichiers
52
+ Pour chaque image, Cityscapes fournit :
53
+
54
+ | Fichier | Description |
55
+ |---------|-------------|
56
+ | `*_leftImg8bit.png` | Image caméra brute (1024×2048) |
57
+ | `*_gtFine_labelIds.png` | Mask avec label ID par pixel (0-33) |
58
+ | `*_gtFine_color.png` | Mask coloré (visualisation) |
59
+ | `*_gtFine_instanceIds.png` | Mask d'instances |
60
+ | `*_gtFine_polygons.json` | Annotations polygonales |
61
+
62
+ - **Why** : Comprendre ce que chaque fichier représente est crucial avant de construire ton pipeline de données. Tu utiliseras principalement `leftImg8bit` + `labelIds`.
63
+ - **Notions** : *semantic segmentation*, *instance segmentation*, label maps, correspondance pixel-classe.
64
+
65
+ ### 1.3 Comprendre les 8 catégories principales vs les 32 sous-catégories
66
+
67
+ Le projet demande de travailler avec les **8 catégories principales** :
68
+
69
+ | ID Cat. | Catégorie | Sous-catégories incluses |
70
+ |---------|-----------|-------------------------|
71
+ | 0 | **void** | unlabeled, ego vehicle, rectification border, out of roi, static, dynamic |
72
+ | 1 | **flat** | road, sidewalk, parking, rail track |
73
+ | 2 | **construction** | building, wall, fence, guard rail, bridge, tunnel |
74
+ | 3 | **object** | pole, polegroup, traffic light, traffic sign |
75
+ | 4 | **nature** | vegetation, terrain |
76
+ | 5 | **sky** | sky |
77
+ | 6 | **human** | person, rider |
78
+ | 7 | **vehicle** | car, truck, bus, caravan, trailer, train, motorcycle, bicycle |
79
+
80
+ - **Why** : C'est une contrainte explicite du projet (Franck). Tu dois mapper les 32 sous-catégories vers ces 8. Cela simplifie le problème et rend le modèle plus robuste.
81
+ - **Notions** : *label remapping*, *category grouping*, dictionnaire de correspondance Cityscapes.
82
+
83
+ ### 1.4 Explorer visuellement les données (EDA)
84
+ Dans un notebook, afficher côte à côte :
85
+ - L'image brute
86
+ - Le mask coloré (`gtFine_color`)
87
+ - Le mask labelIds remappé vers les 8 catégories
88
+ - Distribution des classes par image (histogrammes)
89
+
90
+ - **Why** : L'EDA permet de détecter le *class imbalance* (par exemple, "road" et "building" dominent, "rider" est rare). Cela guidera tes choix d'augmentation de données et de loss function.
91
+ - **Notions** : *Exploratory Data Analysis*, *class imbalance*, visualisation de masks de segmentation, `matplotlib.imshow()`.
92
+
93
+ ---
94
+
95
+ ## Phase 2 — État de l'Art et Recherche Bibliographique
96
+
97
+ ### 2.1 Étudier les architectures de segmentation sémantique
98
+
99
+ Architectures incontournables à comprendre et comparer :
100
+
101
+ | Architecture | Principe clé | Avantage |
102
+ |-------------|--------------|----------|
103
+ | **FCN** (Fully Convolutional Network) | Remplace les couches FC par des convolutions | Premier modèle end-to-end pour la segmentation |
104
+ | **U-Net** | Encoder-decoder avec skip connections | Excellent pour les détails fins, idéal pour les données limitées |
105
+ | **SegNet** | Encoder-decoder avec pooling indices | Plus léger en mémoire que U-Net |
106
+ | **DeepLab v3+** | Atrous convolutions + ASPP + encoder-decoder | State-of-the-art, capture multi-échelle |
107
+ | **PSPNet** | Pyramid Pooling Module | Capture le contexte global |
108
+
109
+ - **Why** : La note technique demande une "présentation des différentes approches et une synthèse de l'état de l'art". Tu dois comprendre les forces/faiblesses de chaque architecture pour justifier ton choix.
110
+ - **Notions** : *encoder-decoder architecture*, *skip connections*, *atrous/dilated convolutions*, *feature pyramid*, *receptive field*.
111
+
112
+ ### 2.2 Étudier les métriques de segmentation
113
+
114
+ | Métrique | Formule/Description |
115
+ |----------|-------------------|
116
+ | **Pixel Accuracy** | % de pixels correctement classifiés |
117
+ | **Mean IoU (mIoU)** | Intersection over Union moyenné sur toutes les classes |
118
+ | **Dice Coefficient** | 2×TP / (2×TP + FP + FN) |
119
+ | **Per-class IoU** | IoU calculé pour chaque classe individuellement |
120
+
121
+ - **Why** : Le pixel accuracy est trompeur sur des données déséquilibrées. Le mIoU est la métrique standard en segmentation sémantique et sera celle que l'évaluateur attend.
122
+ - **Notions** : *IoU (Intersection over Union)*, *Dice score*, *confusion matrix* pixel-level, *mean IoU*.
123
+
124
+ ### 2.3 Étudier les loss functions adaptées
125
+
126
+ - **Categorical Cross-Entropy** : Standard, mais sensible au class imbalance
127
+ - **Weighted Cross-Entropy** : Pondération inversement proportionnelle à la fréquence de la classe
128
+ - **Dice Loss** : Optimise directement le Dice Coefficient
129
+ - **Focal Loss** : Réduit la contribution des exemples bien classifiés
130
+ - **Combinaison** : Dice Loss + Cross-Entropy souvent utilisée en pratique
131
+
132
+ - **Why** : Le choix de la loss function a un impact direct sur les performances, surtout avec des classes déséquilibrées (road vs rider).
133
+ - **Notions** : *loss functions*, *class weighting*, *focal loss*, *dice loss*.
134
+
135
+ ---
136
+
137
+ ## Phase 3 — Pipeline de Données
138
+
139
+ ### 3.1 Créer un Data Generator Keras
140
+
141
+ ```python
142
+ class CityscapesGenerator(tf.keras.utils.Sequence):
143
+ def __init__(self, image_paths, mask_paths, batch_size, img_size, augment=False):
144
+ ...
145
+ def __getitem__(self, idx):
146
+ # Charge batch d'images + masks
147
+ # Remapping 32 → 8 catégories
148
+ # Resize
149
+ # Augmentation (si train)
150
+ # One-hot encoding du mask
151
+ ...
152
+ ```
153
+
154
+ - **Why** : Les images Cityscapes (1024×2048) sont trop volumineuses pour tout charger en RAM. Un generator charge les données par batch à la volée. C'est un critère du livrable ("caractère industrialisable").
155
+ - **Notions** : `tf.keras.utils.Sequence`, *batch loading*, *lazy loading*, *one-hot encoding* de masks, *yield* vs *return*.
156
+
157
+ ### 3.2 Implémenter le label remapping (32 → 8 catégories)
158
+
159
+ ```python
160
+ # Dictionnaire de mapping utilisant la documentation Cityscapes
161
+ LABEL_TO_CATEGORY = {
162
+ 0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, # void
163
+ 7: 1, 8: 1, 9: 1, 10: 1, # flat
164
+ 11: 2, 12: 2, 13: 2, 14: 2, 15: 2, 16: 2, # construction
165
+ 17: 3, 18: 3, 19: 3, 20: 3, # object
166
+ 21: 4, 22: 4, # nature
167
+ 23: 5, # sky
168
+ 24: 6, 25: 6, # human
169
+ 26: 7, 27: 7, 28: 7, 29: 7, 30: 7, 31: 7, 32: 7, 33: 7 # vehicle
170
+ }
171
+ ```
172
+
173
+ - **Why** : Franck (le collègue en charge du traitement d'images) a spécifié que seules les 8 catégories principales sont nécessaires. Ce remapping doit être fait dans le pipeline de données, pas manuellement.
174
+ - **Notions** : *label encoding*, *numpy vectorized mapping* (`np.vectorize` ou table de lookup), correspondance Cityscapes.
175
+
176
+ ### 3.3 Implémenter l'augmentation de données
177
+
178
+ Techniques à appliquer :
179
+ - **Flip horizontal** (le plus commun pour la conduite)
180
+ - **Rotation légère** (±10°)
181
+ - **Variations de luminosité/contraste**
182
+ - **Random crop + resize**
183
+ - **Ajout de bruit gaussien**
184
+
185
+ > ⚠️ L'augmentation doit être appliquée **identiquement** à l'image ET au mask !
186
+
187
+ - **Why** : Le livrable demande explicitement des "gains obtenus avec les approches d'augmentation des données". L'augmentation permet de régulariser le modèle et d'augmenter virtuellement la taille du dataset.
188
+ - **Notions** : *data augmentation*, bibliothèque `albumentations` (applique les mêmes transformations géométriques à l'image et au mask), *overfitting prevention*.
189
+
190
+ ### 3.4 Gérer le redimensionnement des images
191
+
192
+ Réduire les images de 1024×2048 à une taille gérable :
193
+ - **256×512** : bon compromis vitesse/qualité pour les premiers tests
194
+ - **512×1024** : meilleure résolution si ressources GPU suffisantes
195
+
196
+ - **Why** : Les images originales sont très grandes. Entraîner en pleine résolution nécessite un GPU puissant (32+ Go VRAM). Le redimensionnement est un compromis nécessaire.
197
+ - **Notions** : *image resizing*, interpolation bilinéaire vs nearest-neighbor (pour les masks !), *aspect ratio preservation*.
198
+
199
+ ---
200
+
201
+ ## Phase 4 — Entraînement du Modèle
202
+
203
+ ### 4.1 Commencer avec un modèle simple (baseline)
204
+
205
+ Entraîner un U-Net simple depuis zéro comme baseline :
206
+ - Encoder : blocs Conv2D + BatchNorm + ReLU + MaxPool
207
+ - Decoder : UpSampling2D + Concatenate (skip connections) + Conv2D
208
+ - Sortie : Conv2D(8, (1,1), activation='softmax')
209
+
210
+ - **Why** : Un modèle simple permet de valider que tout le pipeline fonctionne (data loading, training loop, évaluation) avant d'investir du temps dans des architectures plus complexes.
211
+ - **Notions** : *U-Net architecture*, *encoder-decoder*, *skip connections*, *softmax pour classification multi-classe pixel-level*.
212
+
213
+ ### 4.2 Utiliser le Transfer Learning
214
+
215
+ Utiliser un backbone pré-entraîné sur ImageNet :
216
+ - **MobileNetV2** : léger, idéal pour l'embarqué
217
+ - **ResNet50** : bon compromis performance/poids
218
+ - **EfficientNet** : état de l'art en efficacité
219
+
220
+ ```python
221
+ base_model = tf.keras.applications.MobileNetV2(input_shape=(256, 512, 3), include_top=False, weights='imagenet')
222
+ ```
223
+
224
+ - **Why** : Le transfer learning permet d'obtenir de bien meilleures performances avec moins de données et moins de temps d'entraînement. Les features bas-niveau (contours, textures) apprises sur ImageNet sont transférables.
225
+ - **Notions** : *transfer learning*, *feature extraction vs fine-tuning*, *backbone freezing/unfreezing*, `keras.applications`.
226
+
227
+ ### 4.3 Implémenter un modèle avancé (DeepLab v3+ ou similaire)
228
+
229
+ Options :
230
+ - Utiliser `segmentation_models` library : `pip install segmentation-models`
231
+ - Implémenter DeepLab v3+ manuellement avec Keras
232
+ - Utiliser TensorFlow Hub pour charger un modèle pré-entraîné
233
+
234
+ - **Why** : La comparaison entre un modèle simple (baseline) et un modèle avancé est attendue dans la note technique. DeepLab v3+ est souvent le meilleur choix pour Cityscapes.
235
+ - **Notions** : *ASPP (Atrous Spatial Pyramid Pooling)*, *dilated convolutions*, *multi-scale feature extraction*.
236
+
237
+ ### 4.4 Configurer l'entraînement
238
+
239
+ ```python
240
+ model.compile(
241
+ optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),
242
+ loss='categorical_crossentropy', # ou dice_loss + CE combinée
243
+ metrics=['accuracy', MeanIoU(num_classes=8)]
244
+ )
245
+
246
+ callbacks = [
247
+ tf.keras.callbacks.ModelCheckpoint('best_model.keras', save_best_only=True, monitor='val_mean_iou', mode='max'),
248
+ tf.keras.callbacks.EarlyStopping(patience=10, monitor='val_mean_iou', mode='max'),
249
+ tf.keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=5),
250
+ tf.keras.callbacks.TensorBoard(log_dir='./logs')
251
+ ]
252
+ ```
253
+
254
+ - **Why** : Les callbacks automatisent la sauvegarde du meilleur modèle, l'arrêt précoce (évite l'overfitting), et l'ajustement du learning rate. C'est une démarche professionnelle.
255
+ - **Notions** : *callbacks Keras*, *early stopping*, *learning rate scheduling*, *model checkpointing*, *TensorBoard*.
256
+
257
+ ### 4.5 Entraîner et comparer les modèles
258
+
259
+ Pour chaque modèle, documenter :
260
+ - Architecture utilisée
261
+ - Hyperparamètres (lr, batch size, epochs, augmentation)
262
+ - Courbes train/val loss et mIoU
263
+ - Per-class IoU sur le validation set
264
+ - Prédictions visuelles (image / ground truth / prédiction)
265
+
266
+ - **Why** : La soutenance demande la "comparaison des modèles" (10 min dédiées). Tu dois montrer une démarche itérative et justifier le modèle final retenu.
267
+ - **Notions** : *hyperparameter tuning*, *learning curves analysis*, *overfitting vs underfitting diagnosis*, *model selection*.
268
+
269
+ ### 4.6 Évaluer sur le jeu de test
270
+
271
+ Calculer les métriques finales sur le test set (Berlin, Bielefeld, Bonn, Leverkusen, Mainz, Munich) :
272
+ - mIoU global
273
+ - IoU par classe
274
+ - Matrice de confusion pixel-level
275
+ - Visualisations qualitatives
276
+
277
+ - **Why** : L'évaluation sur le test set (jamais vu pendant l'entraînement) donne une estimation non biaisée des performances. C'est la norme en ML.
278
+ - **Notions** : *train/val/test split*, *generalization*, *qualitative vs quantitative evaluation*.
279
+
280
+ ---
281
+
282
+ ## Phase 5 — Développement de l'API de Prédiction
283
+
284
+ ### 5.1 Choisir entre Flask et FastAPI
285
+
286
+ | Critère | Flask | FastAPI |
287
+ |---------|-------|---------|
288
+ | Facilité | ✅ Plus simple | ⚠️ Async concepts |
289
+ | Performance | ⚠️ Synchrone | ✅ Asynchrone natif |
290
+ | Documentation auto | ❌ | ✅ Swagger/OpenAPI inclus |
291
+ | Typing | ❌ | ✅ Pydantic intégré |
292
+
293
+ > **Recommandation** : FastAPI — la doc auto est un vrai plus pour Laura et la soutenance.
294
+
295
+ - **Why** : Laura veut une "API simple à utiliser". FastAPI génère automatiquement une documentation interactive (Swagger UI) qui permet de tester l'API sans code client.
296
+ - **Notions** : *REST API*, *endpoints*, *HTTP methods* (POST), *content types* (multipart/form-data, JSON).
297
+
298
+ ### 5.2 Concevoir l'endpoint de prédiction
299
+
300
+ ```python
301
+ from fastapi import FastAPI, File, UploadFile
302
+ import numpy as np
303
+ from PIL import Image
304
+ import io
305
+
306
+ app = FastAPI(title="Cityscapes Segmentation API")
307
+
308
+ # Charger le modèle au démarrage
309
+ model = tf.keras.models.load_model('best_model.keras')
310
+
311
+ @app.post("/predict")
312
+ async def predict(file: UploadFile = File(...)):
313
+ # 1. Lire l'image uploadée
314
+ image = Image.open(io.BytesIO(await file.read()))
315
+ # 2. Prétraiter (resize, normalisation)
316
+ # 3. Prédire le mask
317
+ # 4. Post-traiter (argmax, resize au format original)
318
+ # 5. Retourner le mask (encodé en base64 ou en JSON)
319
+ return {"mask": mask_as_list, "classes": class_names}
320
+ ```
321
+
322
+ - **Why** : Cet endpoint est le cœur du livrable 2. Il prend une image et retourne le mask prédit. Il sera consommé par l'application web (livrable 3).
323
+ - **Notions** : *API endpoint design*, *image I/O* (bytes → PIL → numpy), *model inference pipeline*, *base64 encoding*.
324
+
325
+ ### 5.3 Ajouter des endpoints utilitaires
326
+
327
+ - `GET /` : Infos sur l'API (version, modèle utilisé, classes)
328
+ - `GET /health` : Health check
329
+ - `GET /classes` : Liste des 8 catégories et leurs couleurs
330
+
331
+ - **Why** : Des endpoints d'information facilitent l'intégration et le monitoring. C'est une bonne pratique d'architecture API.
332
+ - **Notions** : *API design patterns*, *health checks*, *API versioning*.
333
+
334
+ ### 5.4 Tester l'API en local
335
+
336
+ ```bash
337
+ uvicorn api.main:app --reload --host 0.0.0.0 --port 8000
338
+ # Tester sur http://localhost:8000/docs (Swagger UI)
339
+ ```
340
+
341
+ - **Why** : Toujours tester en local avant de déployer. La Swagger UI permet de tester visuellement l'upload d'image et la réponse.
342
+ - **Notions** : *local development server*, *API testing*, *Swagger/OpenAPI*.
343
+
344
+ ---
345
+
346
+ ## Phase 6 — Développement de l'Application Web
347
+
348
+ ### 6.1 Concevoir l'application Streamlit (ou Flask)
349
+
350
+ L'application doit permettre :
351
+ 1. **Afficher la liste des IDs** des images disponibles (test set)
352
+ 2. **Sélectionner un ID** → lancer la prédiction via l'API
353
+ 3. **Afficher 3 images côte à côte** : image réelle | mask réel | mask prédit
354
+
355
+ ```python
356
+ import streamlit as st
357
+ import requests
358
+
359
+ st.title("🚗 Segmentation d'Images - Future Vision Transport")
360
+
361
+ # Liste des images disponibles
362
+ image_ids = get_available_image_ids()
363
+ selected_id = st.selectbox("Sélectionner une image :", image_ids)
364
+
365
+ if st.button("Lancer la prédiction"):
366
+ # Appel à l'API
367
+ response = requests.post(API_URL + "/predict", files={"file": image_bytes})
368
+ predicted_mask = decode_response(response.json())
369
+
370
+ col1, col2, col3 = st.columns(3)
371
+ col1.image(original_image, caption="Image réelle")
372
+ col2.image(ground_truth_mask, caption="Mask réel")
373
+ col3.image(predicted_mask, caption="Mask prédit")
374
+ ```
375
+
376
+ - **Why** : Cette application est l'interface de démonstration (livrable 3). Elle doit consommer l'API, pas faire la prédiction directement — cela prouve que l'architecture est bien découplée.
377
+ - **Notions** : *Streamlit*, *API consumption* (`requests`), *image display*, *UI/UX pour une démo*, *client-server architecture*.
378
+
379
+ ### 6.2 Ajouter des fonctionnalités bonus
380
+
381
+ - Palette de couleurs pour les classes (légende)
382
+ - Overlay du mask sur l'image originale (transparence)
383
+ - Métriques affichées (IoU par classe vs ground truth)
384
+ - Upload d'une image personnelle (pas du dataset)
385
+
386
+ - **Why** : Ces fonctionnalités impressionnent l'évaluateur et montrent une maîtrise au-delà du minimum requis.
387
+ - **Notions** : *image compositing*, *alpha blending*, *color mapping*.
388
+
389
+ ---
390
+
391
+ ## Phase 7 — Déploiement sur le Cloud
392
+
393
+ ### 7.1 Choisir une plateforme Cloud
394
+
395
+ | Plateforme | Coût | Difficulté | GPU |
396
+ |-----------|------|-----------|-----|
397
+ | **Render** | Gratuit (limité) | ⭐⭐ | ❌ |
398
+ | **Railway** | Gratuit ($5 crédit) | ⭐⭐ | ❌ |
399
+ | **Azure Web App** | Free tier disponible | ⭐⭐⭐ | Option payante |
400
+ | **Google Cloud Run** | Free tier généreux | ⭐⭐⭐ | ❌ |
401
+ | **PythonAnywhere** | Gratuit (très limité) | ⭐ | ❌ |
402
+ | **AWS (EC2/Lambda)** | Free tier 12 mois | ⭐⭐⭐⭐ | Option payante |
403
+
404
+ - **Why** : Le déploiement Cloud est obligatoire pour la soutenance. Tu dois faire une démo en live et l'enregistrer. Choisis en fonction de ton budget et de ta familiarité.
405
+ - **Notions** : *cloud deployment*, *PaaS vs IaaS*, *containerization concepts*.
406
+
407
+ ### 7.2 Containeriser avec Docker
408
+
409
+ ```dockerfile
410
+ # API
411
+ FROM python:3.10-slim
412
+ WORKDIR /app
413
+ COPY requirements.txt .
414
+ RUN pip install --no-cache-dir -r requirements.txt
415
+ COPY . .
416
+ EXPOSE 8000
417
+ CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
418
+ ```
419
+
420
+ - **Why** : Docker garantit que l'environnement est identique en local et en production. La plupart des plateformes Cloud supportent Docker nativement.
421
+ - **Notions** : *Docker*, *Dockerfile*, *containers vs VMs*, *image build*, *port mapping*.
422
+
423
+ ### 7.3 Déployer l'API et l'application
424
+
425
+ Deux déploiements séparés :
426
+ 1. **API** : déploiement du service de prédiction
427
+ 2. **App web** : déploiement de l'interface Streamlit (pointe vers l'URL de l'API)
428
+
429
+ - **Why** : Séparer l'API de l'application web est une architecture microservices. Cela prouve la modularité de ton système.
430
+ - **Notions** : *microservices architecture*, *environment variables* pour l'URL de l'API, *CORS configuration*.
431
+
432
+ ### 7.4 Enregistrer la démo pendant la soutenance
433
+
434
+ > ⚠️ **Important** : Le sujet précise que l'évaluateur et l'étudiant doivent **enregistrer la démo** pendant la soutenance pour que le jury puisse la visionner. Tu pourras ensuite couper le service Cloud pour éviter les coûts.
435
+
436
+ - **Why** : C'est une exigence explicite du sujet. Prépare un outil d'enregistrement d'écran (OBS, QuickTime, etc.).
437
+ - **Notions** : *screen recording*, préparation de démo.
438
+
439
+ ---
440
+
441
+ ## Phase 8 — Rédaction de la Note Technique (~10 pages)
442
+
443
+ ### 8.1 Structure recommandée
444
+
445
+ | Section | Contenu | ~Pages |
446
+ |---------|---------|--------|
447
+ | **1. Introduction** | Contexte (Future Vision Transport), objectifs, contraintes | 1 |
448
+ | **2. État de l'Art** | Revue des architectures (FCN, U-Net, SegNet, DeepLab), métriques | 2 |
449
+ | **3. Dataset et Préparation** | Cityscapes, 8 catégories, EDA, augmentation | 1.5 |
450
+ | **4. Modèle Retenu** | Architecture détaillée, hyperparamètres, justification du choix | 2 |
451
+ | **5. Résultats** | Comparaison des modèles, mIoU, courbes, gains de l'augmentation | 2 |
452
+ | **6. Mise en Production** | Architecture API + App, déploiement Cloud | 1 |
453
+ | **7. Conclusion** | Bilan, limites, pistes d'amélioration | 0.5 |
454
+
455
+ - **Why** : La note technique est un livrable clé (livrable 4). Elle doit démontrer ta rigueur scientifique et ta capacité à synthétiser.
456
+ - **Notions** : *technical writing*, *scientific methodology*, *results presentation*.
457
+
458
+ ### 8.2 Points clés à inclure
459
+
460
+ - **Comparaison explicite** des modèles (tableau mIoU)
461
+ - **Gains de l'augmentation** : comparer modèle sans augmentation vs avec
462
+ - **Visualisations** : courbes de loss, exemples de prédictions, matrice de confusion
463
+ - **Pistes d'amélioration** : Real-time inference, quantization, pruning, TensorRT
464
+
465
+ - **Why** : Ces éléments sont explicitement demandés dans le descriptif des livrables.
466
+ - **Notions** : *ablation study*, *model comparison*, *scientific rigor*.
467
+
468
+ ---
469
+
470
+ ## Phase 9 — Support de Présentation (max 30 slides)
471
+
472
+ ### 9.1 Structure calquée sur le timing de soutenance
473
+
474
+ | Bloc | Durée | Slides | Contenu |
475
+ |------|-------|--------|---------|
476
+ | **Contexte & Objectifs** | 5 min | 5-7 | Entreprise, chaîne de vision, ton rôle, métriques |
477
+ | **Modèles & Résultats** | 10 min | 12-15 | Architectures, comparaisons, visualisations, augmentation |
478
+ | **Mise en Production** | 5 min | 5-8 | Architecture API/App, déploiement, démo live |
479
+
480
+ - **Why** : La soutenance est strictement chronométrée (20 min ±5). Une présentation trop courte (<15 min) ou trop longue (>25 min) peut être refusée.
481
+ - **Notions** : *presentation skills*, *storytelling technique*, *demo preparation*.
482
+
483
+ ### 9.2 Préparer la démo live
484
+
485
+ Préparer un script de démo :
486
+ 1. Ouvrir l'application web déployée
487
+ 2. Sélectionner une image du test set
488
+ 3. Lancer la prédiction
489
+ 4. Montrer image / mask réel / mask prédit côte à côte
490
+ 5. Éventuellement tester avec une image uploadée
491
+
492
+ > Tester la démo **plusieurs fois avant** la soutenance !
493
+
494
+ - **Why** : La démo est le moment fort de la soutenance. Un bug en live est très pénalisant. Prépare aussi des screenshots de backup au cas où le Cloud tombe.
495
+ - **Notions** : *demo rehearsal*, *fallback plan*.
496
+
497
+ ---
498
+
499
+ ## ✅ Checklist des Livrables
500
+
501
+ | # | Livrable | Format | Nommage |
502
+ |---|----------|--------|---------|
503
+ | 1 | **Scripts/Notebooks** (pipeline complet) | `.ipynb` / `.py` | `Nom_Prénom_1_scripts_mmaaaa` |
504
+ | 2 | **API de prédiction** (déployée sur le Cloud) | Flask/FastAPI | `Nom_Prénom_2_API_mmaaaa` |
505
+ | 3 | **Application web** (déployée sur le Cloud) | Streamlit/Flask | `Nom_Prénom_3_application_Flask_mmaaaa` |
506
+ | 4 | **Note technique** (~10 pages) | PDF | `Nom_Prénom_4_note_technique_mmaaaa` |
507
+ | 5 | **Présentation** (max 30 slides) | PPTX/PDF | `Nom_Prénom_5_presentation_mmaaaa` |
508
+
509
+ > ⚠️ Tout doit être dans un **zip** nommé `Titre_du_projet_nom_prénom`.
510
+
511
+ ---
512
+
513
+ ## 🎯 Notions Clés à Maîtriser (Résumé)
514
+
515
+ | Domaine | Notions |
516
+ |---------|---------|
517
+ | **Computer Vision** | Semantic segmentation, encoder-decoder, skip connections, dilated convolutions |
518
+ | **Deep Learning** | Transfer learning, data augmentation, loss functions (Dice, Focal, CE), callbacks |
519
+ | **Keras/TensorFlow** | `tf.keras.utils.Sequence`, `keras.applications`, custom training loops, `MeanIoU` |
520
+ | **MLOps** | Docker, API REST, déploiement Cloud, CI/CD basique |
521
+ | **Data Engineering** | Data generators, label remapping, preprocessing pipelines |
522
+ | **Évaluation** | mIoU, Dice, pixel accuracy, confusion matrix, per-class metrics |
523
+ | **Communication** | Note technique, présentation de résultats, démo live |
mlflow.db ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5880996b1fff46c501244aad7a321f7fbaa951c11ea0a62eba1561b8e5d77cfc
3
+ size 626688
models/best_unet_model.keras ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ec48de7f43bdb66bc5106f78b7c1de12561593e4d56ae3487c49956d622d17cf
3
+ size 23481417
mon_avancement.md ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Avancement au 20/03/2026
2
+
3
+ ## Objectif actuel
4
+
5
+
6
+ ## Avancement
7
+
8
+
9
+ ## Prochaines étapes
10
+
11
+ Remapper les 32 sous catégories de Cityscapes en 8 catégories
12
+
13
+ Faire une EDA:
14
+ Dans un notebook, afficher côte à côte :
15
+ - L'image brute
16
+ - Le mask coloré (gtFine_color)
17
+ - Le mask labelIds remappé vers les 8 catégories
18
+ - Distribution des classes par image (histogrammes)
19
+
20
+ Faire tourner le google colab https://colab.research.google.com/drive/1jZ2tdEyJ2xaERUCwyQ5juwPJrEyIAtBN?usp=sharing#scrollTo=O9oKKrUPQD9s
21
+ L'objectif est juste d'obtenir un modèle où la segmentation est correcte.
22
+ Mettre le modèle dans l'api et le déployer.
23
+
24
+ Faire des tests unitaires dans le projet 7
25
+ Mettre de l'argent pour upgrade le projet 7 et faire tourner l'app, ou essayer dans render
26
+
27
+ Entrainement du modèle
28
+ Affichage des résultats
29
+ Il faut que j'ai la segmentation et que mon modèle puisse renvoyer les images.
30
+
31
+
32
+ Parler de l'augmentation des données. Quand j'ai mes images de voiture, je les pivote, etc pour augementer mes images pour l'entrainement.
33
+ Parler du modèle. Expliquer ce qu'est le U-net. Qu'estce que qui se passe et comment ça se passe.
34
+ Comment j'ai pu faire avec le transfer-learning
35
+ Parler des différents modèles et comparer leurs résultats.
36
+ Insister sur le github. Comment j'ai fait mon github, comment je le link avec render. Comment je le link avec streamlit et vérifier les résultats visuellement.
37
+ Parler du CI/CD
38
+ Parler de la FASTAPPi
notebooks/notebook_entrainement.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
notebooks/notebook_exploratoire.ipynb ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ fastapi
2
+ uvicorn
3
+ python-multipart
4
+ tensorflow
5
+ pandas
6
+ numpy
7
+ pillow
8
+ streamlit
9
+ albumentations
10
+ matplotlib
11
+ scipy
12
+ azure-monitor-opentelemetry
resume_execution_notebook.md ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Synthèse de l'Exécution du Notebook (MobileNetV2-UNet)
2
+
3
+ Ce document résume les actions effectuées par Gemini CLI pour adapter et exécuter localement le notebook Colab trouvé sur internet (`Copie_de_p08_david_scanu_notebook_MobileNetV2_UNet.ipynb`), ainsi que les résultats produits par cette exécution.
4
+
5
+ ## 1. Contexte et Objectif
6
+
7
+ Le but était de prendre un notebook Google Colab conçu pour l'entraînement d'un modèle de segmentation sémantique (architecture MobileNetV2-UNet sur le jeu de données Cityscapes) et de l'exécuter de bout en bout sur l'environnement local.
8
+
9
+ ## 2. Fichiers de configuration et d'adaptation créés
10
+
11
+ Pour rendre le notebook exécutable localement (hors de l'environnement Google Colab) et de manière automatisée, Gemini CLI a généré plusieurs scripts Python "patch" pour modifier le code du notebook à la volée :
12
+
13
+ * **`fix_colab.py`** : A commenté toutes les lignes spécifiques à Google Colab (comme `import google.colab` ou `drive.mount`), qui auraient provoqué des erreurs en local.
14
+ * **`patch_notebook.py`** : A remplacé le long processus de téléchargement du véritable jeu de données Cityscapes par une fonction générant un **jeu de données fictif (mock)**. Cela a permis de tester l'intégralité du pipeline (de l'entraînement à l'évaluation) très rapidement sans devoir télécharger des gigaoctets de données.
15
+ * **`fix_epochs.py`** : A probablement réduit le nombre d'époques d'entraînement (epochs) pour accélérer l'exécution du test de bout en bout.
16
+ * **`fix_paths.py` / `patch_train.py` / `patch_image.py`** : Ont servi à corriger les chemins de fichiers et d'autres petits détails d'implémentation pour s'assurer que le notebook puisse tourner correctement sur votre machine.
17
+ * **`notebook_script.py`** : Le code Python final, extrait du notebook, prêt à être exécuté.
18
+
19
+ ## 3. Résultats et Fichiers Générés (Outputs)
20
+
21
+ L'exécution du notebook a généré une arborescence complète de résultats, principalement documentée dans le fichier `outputs_summary.md` :
22
+
23
+ * **Modèles Entraînés (`content/experiments/.../models/`) :**
24
+ * `cityscapes_segmentation_model.keras` : Le modèle complet de fin d'entraînement.
25
+ * `checkpoints/best_model.keras` : Le meilleur modèle sauvegardé en cours de route (celui à utiliser pour les prédictions).
26
+ * `class_mapping.json` : Le dictionnaire qui associe les classes prédites (IDs) à leurs couleurs et noms (ex: "route", "voiture").
27
+ * **Métriques et Évaluation (`content/experiments/.../results/`) :**
28
+ * Des fichiers CSV et JSON contenant l'IoU par classe, la matrice de confusion, le rapport de classification et l'historique d'entraînement.
29
+ * **Visualisations (`content/experiments/.../visualizations/`) :**
30
+ * Des graphiques de l'historique d'entraînement (Loss/Accuracy), la matrice de confusion visuelle, et surtout des images comparant l'image originale, le vrai masque, et la prédiction du modèle.
31
+ * **Suivi MLflow (`mlruns/`) :**
32
+ * Une base de données locale MLflow stockant les hyperparamètres de l'expérience et ses métriques.
33
+
34
+ ## 4. Prochaines Étapes : Déploiement
35
+
36
+ Gemini a également généré un fichier `Next_step.md` qui explique comment exploiter ces résultats dans la suite de votre projet :
37
+
38
+ * **Intégration Streamlit :** Il fournit le code (boilerplate) nécessaire pour charger le `best_model.keras` et le `class_mapping.json` dans votre application `app.py`. Le modèle est capable de prendre une image uploadée et de renvoyer un masque segmenté coloré.
39
+ * **Déploiement sur Render :** Des mises en garde importantes y sont précisées :
40
+ * Gérer la taille du modèle (76 MB), qui passe sur Git classique mais qui, s'il était plus gros, nécessiterait Git LFS.
41
+ * Faire attention à la limite de RAM (512 MB) du niveau gratuit de Render, TensorFlow étant très gourmand. Il est conseillé d'utiliser `tensorflow-cpu` dans le `requirements.txt` pour éviter les crashs "Out of Memory" (OOM).
tests/test_api.py ADDED
@@ -0,0 +1,79 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import urllib.parse
3
+ import pandas as pd
4
+
5
+ # 1. Define your base API URL
6
+ base_url = "https://predictionsentiments-azepf7eme8dvftaa.francecentral-01.azurewebsites.net/feeling_predictions/"
7
+ # URL locale pour MLFlow
8
+ #base_url = "http://127.0.0.1:8000/feeling_predictions/"
9
+
10
+ # 2. Define a list of 10 different sentences (mixing happy and sad to test your model)
11
+ sentences = [
12
+ "I just got a promotion at work and I am thrilled!",
13
+ "My dog passed away yesterday and my heart is broken.",
14
+ "The weather is absolutely beautiful today, I love it.",
15
+ "I failed my math exam despite studying all night.",
16
+ "We had a wonderful family dinner with lots of laughs.",
17
+ "I feel so lonely and isolated in this new city.",
18
+ "Winning the championship was the best moment of my life.",
19
+ "My flight got canceled and I missed my best friend's wedding.",
20
+ "I am enjoying a nice, relaxing cup of coffee by the window.",
21
+ "Everything is going wrong today and I just want to cry."
22
+ ]
23
+
24
+ # 3. Initialize an empty list to store all the results
25
+ all_results = []
26
+
27
+ headers = {"accept": "application/json"}
28
+
29
+ print("Starting predictions...\n")
30
+
31
+ # 4. Loop through each sentence in the list
32
+ for text in sentences:
33
+ # URL-encode the sentence safely
34
+ encoded_text = urllib.parse.quote(text)
35
+ full_url = f"{base_url}{encoded_text}"
36
+
37
+ try:
38
+ # Call the API
39
+ response = requests.get(full_url, headers=headers)
40
+ response.raise_for_status() # Check for HTTP errors like 500 or 404
41
+
42
+ # Parse the JSON response {"text": "...", "feeling_result": "..."}
43
+ api_data = response.json()
44
+
45
+ # Extract the prediction
46
+ prediction = api_data.get("feeling_result")
47
+
48
+ # Store the success result in our list as a dictionary
49
+ all_results.append({
50
+ "sentence": text,
51
+ "prediction": prediction,
52
+ "status": "success"
53
+ })
54
+
55
+ print(f"Processed: '{text[:30]}...' -> {prediction.upper()}")
56
+
57
+ except requests.exceptions.RequestException as e:
58
+ print(f"Error processing '{text[:30]}...': {e}")
59
+
60
+ # If there is an error, we still store it so we don't lose track
61
+ all_results.append({
62
+ "sentence": text,
63
+ "prediction": "ERROR",
64
+ "status": str(e)
65
+ })
66
+
67
+ print("\n--- All 10 requests completed! ---")
68
+
69
+ # 5. Display and save the stored results
70
+ # Converting the list of dictionaries into a Pandas DataFrame is the easiest way to handle the data
71
+ df_results = pd.DataFrame(all_results)
72
+
73
+ print("\nHere is your final data table:")
74
+ print(df_results)
75
+
76
+ # Save the results to a CSV file in your folder
77
+ csv_filename = "api_predictions_results.csv"
78
+ df_results.to_csv(csv_filename, index=False, encoding="utf-8")
79
+ print(f"\nResults have been successfully saved to '{csv_filename}'.")