Upload 7 files
Browse files- .gitattributes +2 -0
- SN_NgoueDavidRogerYannick_TL_PyTorch.ipynb +0 -0
- SN_NgoueDavidRogerYannick_TL_PyTorch_copy2.ipynb +0 -0
- app.py +428 -0
- glioma.jpg +0 -0
- mobilenetv2.webp +3 -0
- resnet50_image.webp +3 -0
- vgg16_image.jpg +0 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ 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 |
+
mobilenetv2.webp filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
resnet50_image.webp filter=lfs diff=lfs merge=lfs -text
|
SN_NgoueDavidRogerYannick_TL_PyTorch.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
SN_NgoueDavidRogerYannick_TL_PyTorch_copy2.ipynb
ADDED
|
The diff for this file is too large to render.
See raw diff
|
|
|
app.py
ADDED
|
@@ -0,0 +1,428 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import streamlit as st
|
| 2 |
+
from PIL import Image
|
| 3 |
+
import numpy as np
|
| 4 |
+
import torch
|
| 5 |
+
from torchvision import transforms
|
| 6 |
+
import torchvision.models as models
|
| 7 |
+
from torchvision.models import VGG16_Weights, ResNet50_Weights, MobileNet_V2_Weights
|
| 8 |
+
import os
|
| 9 |
+
|
| 10 |
+
# Taille d'entrée pour les modèles
|
| 11 |
+
INPUT_SIZE = 224
|
| 12 |
+
|
| 13 |
+
# Chemins des modèles sauvegardés (adapté pour PyTorch)
|
| 14 |
+
MODEL_PYTORCH_PATH = "saved_models/VGG16_best_accuracy_0.9560.pth" # Exemple
|
| 15 |
+
|
| 16 |
+
# Chargement des classes
|
| 17 |
+
class_names = ['Healthy', 'Tumor']
|
| 18 |
+
|
| 19 |
+
# Chargement des modèles PyTorch (avec gestion des poids)
|
| 20 |
+
models_dict = {
|
| 21 |
+
"VGG16": models.vgg16(weights=VGG16_Weights.DEFAULT),
|
| 22 |
+
"ResNet50": models.resnet50(weights=ResNet50_Weights.DEFAULT),
|
| 23 |
+
"MobileNetV2": models.mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT)
|
| 24 |
+
}
|
| 25 |
+
|
| 26 |
+
def predict_with_pytorch(model_path, image, class_names):
|
| 27 |
+
try:
|
| 28 |
+
checkpoint = torch.load(model_path, map_location=torch.device('cpu')) # Charge sur CPU si GPU pas dispo
|
| 29 |
+
model_name = checkpoint['model_name']
|
| 30 |
+
model = models_dict[model_name]
|
| 31 |
+
|
| 32 |
+
# Gestion des incompatibilités de taille de la dernière couche (si nécessaire)
|
| 33 |
+
try:
|
| 34 |
+
model.load_state_dict(checkpoint['model_state_dict'])
|
| 35 |
+
except RuntimeError as e:
|
| 36 |
+
if "size mismatch for classifier.6" in str(e): # Exemple pour VGG16
|
| 37 |
+
num_features = model.classifier[6].in_features
|
| 38 |
+
model.classifier[6] = torch.nn.Linear(num_features, len(class_names))
|
| 39 |
+
model.load_state_dict(checkpoint['model_state_dict'], strict=False)
|
| 40 |
+
else:
|
| 41 |
+
raise
|
| 42 |
+
|
| 43 |
+
model.eval()
|
| 44 |
+
|
| 45 |
+
data_transforms = transforms.Compose([
|
| 46 |
+
transforms.Resize(256),
|
| 47 |
+
transforms.CenterCrop(224),
|
| 48 |
+
transforms.ToTensor(),
|
| 49 |
+
transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
|
| 50 |
+
])
|
| 51 |
+
|
| 52 |
+
image_tensor = data_transforms(image).unsqueeze(0)
|
| 53 |
+
|
| 54 |
+
with torch.no_grad():
|
| 55 |
+
output = model(image_tensor)
|
| 56 |
+
probabilities = torch.nn.functional.softmax(output, dim=1)[0].tolist()
|
| 57 |
+
_, predicted_class = torch.max(output, 1)
|
| 58 |
+
predicted_label = class_names[predicted_class.item()]
|
| 59 |
+
|
| 60 |
+
return predicted_label, probabilities
|
| 61 |
+
|
| 62 |
+
except FileNotFoundError:
|
| 63 |
+
return "Erreur: Fichier de modèle non trouvé.", None
|
| 64 |
+
except Exception as e:
|
| 65 |
+
return f"Erreur lors de la prédiction: {e}", None
|
| 66 |
+
|
| 67 |
+
|
| 68 |
+
# Fonction JS pour animer les ballons
|
| 69 |
+
def show_balloons():
|
| 70 |
+
st.markdown("""
|
| 71 |
+
<script type="text/javascript">
|
| 72 |
+
function createBalloon(x, y) {
|
| 73 |
+
var balloon = document.createElement('div');
|
| 74 |
+
balloon.style.position = 'absolute';
|
| 75 |
+
balloon.style.left = x + 'px';
|
| 76 |
+
balloon.style.top = y + 'px';
|
| 77 |
+
balloon.style.width = '50px';
|
| 78 |
+
balloon.style.height = '50px';
|
| 79 |
+
balloon.style.background = 'url(https://example.com/balloon.png) no-repeat center center';
|
| 80 |
+
balloon.style.backgroundSize = 'contain';
|
| 81 |
+
balloon.style.animation = 'floatBalloon 6s ease-in-out infinite';
|
| 82 |
+
document.body.appendChild(balloon);
|
| 83 |
+
}
|
| 84 |
+
|
| 85 |
+
for (let i = 0; i < 5; i++) {
|
| 86 |
+
var x = Math.random() * window.innerWidth;
|
| 87 |
+
var y = Math.random() * window.innerHeight;
|
| 88 |
+
createBalloon(x, y);
|
| 89 |
+
}
|
| 90 |
+
</script>
|
| 91 |
+
""", unsafe_allow_html=True)
|
| 92 |
+
|
| 93 |
+
# CSS pour une interface moderne avec dégradés et icônes
|
| 94 |
+
st.markdown("""
|
| 95 |
+
<style>
|
| 96 |
+
body {
|
| 97 |
+
background: linear-gradient(135deg, #6e7fef, #f0c6d1);
|
| 98 |
+
font-family: 'Arial', sans-serif;
|
| 99 |
+
color: #333;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.title {
|
| 103 |
+
text-align: center;
|
| 104 |
+
font-size: 36px;
|
| 105 |
+
font-weight: bold;
|
| 106 |
+
color: #ff85a2;
|
| 107 |
+
text-shadow: 2px 2px 5px rgba(0, 0, 0, 0.3);
|
| 108 |
+
margin-top: 20px;
|
| 109 |
+
}
|
| 110 |
+
|
| 111 |
+
.upload-section {
|
| 112 |
+
text-align: center;
|
| 113 |
+
margin: 20px;
|
| 114 |
+
}
|
| 115 |
+
|
| 116 |
+
.btn-primary {
|
| 117 |
+
background-color: #6e7fef;
|
| 118 |
+
border-color: #6e7fef;
|
| 119 |
+
color: white;
|
| 120 |
+
font-weight: bold;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.btn-primary:hover {
|
| 124 |
+
background-color: #5573d7;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
.result {
|
| 128 |
+
text-align: center;
|
| 129 |
+
font-size: 24px;
|
| 130 |
+
color: #444;
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
.about-section {
|
| 134 |
+
margin-top: 40px;
|
| 135 |
+
font-size: 16px;
|
| 136 |
+
line-height: 1.6;
|
| 137 |
+
color: #555;
|
| 138 |
+
}
|
| 139 |
+
|
| 140 |
+
.legend {
|
| 141 |
+
font-size: 14px;
|
| 142 |
+
color: #555;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
.sidebar .sidebar-content {
|
| 146 |
+
background: linear-gradient(135deg, #ff85a2, #ffeb3b);
|
| 147 |
+
color: #333;
|
| 148 |
+
padding-top: 20px;
|
| 149 |
+
}
|
| 150 |
+
|
| 151 |
+
.sidebar .sidebar-content .block-container {
|
| 152 |
+
padding-left: 20px;
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
.sidebar .sidebar-content .block {
|
| 156 |
+
background-color: rgba(255, 255, 255, 0.7);
|
| 157 |
+
padding: 10px;
|
| 158 |
+
border-radius: 8px;
|
| 159 |
+
margin-bottom: 10px;
|
| 160 |
+
}
|
| 161 |
+
|
| 162 |
+
.stSidebar {
|
| 163 |
+
background: linear-gradient(45deg, #EE4C2C, #FF8126, #FFC32C);
|
| 164 |
+
color: white;
|
| 165 |
+
font-size: 16px;
|
| 166 |
+
}
|
| 167 |
+
|
| 168 |
+
.logo {
|
| 169 |
+
max-width: 200px;
|
| 170 |
+
margin: 20px auto;
|
| 171 |
+
}
|
| 172 |
+
|
| 173 |
+
.logo-description {
|
| 174 |
+
text-align: center;
|
| 175 |
+
font-size: 18px;
|
| 176 |
+
color: white;
|
| 177 |
+
margin-bottom: 30px;
|
| 178 |
+
}
|
| 179 |
+
|
| 180 |
+
.sidebar select {
|
| 181 |
+
width: 100%;
|
| 182 |
+
padding: 10px;
|
| 183 |
+
background-color: #f3f3f3;
|
| 184 |
+
border-radius: 8px;
|
| 185 |
+
font-size: 16px;
|
| 186 |
+
border: 1px solid #ccc;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
@keyframes floatBalloon {
|
| 190 |
+
0% { transform: translateY(0); opacity: 1; }
|
| 191 |
+
50% { transform: translateY(-200px); opacity: 0.5; }
|
| 192 |
+
100% { transform: translateY(0); opacity: 1; }
|
| 193 |
+
}
|
| 194 |
+
</style>
|
| 195 |
+
""", unsafe_allow_html=True)
|
| 196 |
+
|
| 197 |
+
# Application Streamlit
|
| 198 |
+
st.markdown('<div class="title">Application de Classification d\'Images</div>', unsafe_allow_html=True)
|
| 199 |
+
|
| 200 |
+
menu = st.sidebar.selectbox("Menu", ["🧠 Accueil", "🧠 Classification de l'état cérébral avec VGG16", "Comparatif entre modèles", "👨💻À propos"])
|
| 201 |
+
|
| 202 |
+
if menu == "🧠 Accueil":
|
| 203 |
+
st.write("Bienvenue dans notre application de classification d'images. Cette application a été développée pour la classification d'images dans le contexte du **Brain Tumor MRI images**, un dataset médical contenant des images de tomodensitométrie (CT) de reins, avec des catégories représentant des reins normaux, des kystes, des tumeurs et des calculs rénaux.")
|
| 204 |
+
|
| 205 |
+
st.write("""
|
| 206 |
+
Cette application a pour objectif de classer ces images en différentes catégories (**Normal** Aucun problème: , **Tumor**: Tumeur cérébrale) à l'aide de modèles de machine learning.
|
| 207 |
+
Nous avons effectué du Transfer Learning sur trois modèles pré entrainés et avons fait un comparatif des trois avant de choisir **VGG16** comme celui avec les meilleurs caractéristiques.
|
| 208 |
+
Ces modèles ont été entraînés sur le dataset Brain Tumor MRI images et peuvent être utilisés pour prédire la catégorie d'une image donnée, en détectant des anomalies ou en validant l'état du rein à partir des images CT.
|
| 209 |
+
""")
|
| 210 |
+
|
| 211 |
+
# Création des onglets pour chaque modèle
|
| 212 |
+
tab_resnet50, tab_vgg16, tab_mobilenetv2 = st.tabs(["ResNet50", "VGG16", "MobileNetV2"])
|
| 213 |
+
|
| 214 |
+
with tab_resnet50:
|
| 215 |
+
st.image("resnet50_image.webp", caption="ResNet50", width=700)
|
| 216 |
+
st.write("""
|
| 217 |
+
**ResNet50** est un réseau de neurones convolutif profond (CNN) très populaire pour la classification d'images, introduit dans l'article "Deep Residual Learning for Image Recognition".
|
| 218 |
+
|
| 219 |
+
### Avantages :
|
| 220 |
+
- Utilise des **connexions résiduelles** pour résoudre les problèmes de dégradation des performances lors de l'augmentation de la profondeur du réseau.
|
| 221 |
+
- Excellente précision sur de grandes bases de données d'images comme ImageNet.
|
| 222 |
+
- Convient pour le **fine-tuning** sur des données spécifiques grâce à son architecture pré-entraînée.
|
| 223 |
+
|
| 224 |
+
### Utilisation :
|
| 225 |
+
ResNet50 est largement utilisé dans des tâches comme :
|
| 226 |
+
- La reconnaissance d'objets.
|
| 227 |
+
- La segmentation d'images.
|
| 228 |
+
- La détection de maladies en imagerie médicale.
|
| 229 |
+
""")
|
| 230 |
+
|
| 231 |
+
with tab_vgg16:
|
| 232 |
+
st.image("vgg16_image.jpg", caption="VGG16", width=700)
|
| 233 |
+
st.write("""
|
| 234 |
+
**VGG16** est un modèle de CNN développé par l'équipe de recherche Visual Geometry Group (VGG). Il est connu pour sa simplicité et son efficacité dans la classification d'images.
|
| 235 |
+
|
| 236 |
+
### Avantages :
|
| 237 |
+
- Architecture simple avec des couches convolutives empilées suivies de couches entièrement connectées.
|
| 238 |
+
- Bonne généralisation, même pour des données en dehors de son domaine d'origine.
|
| 239 |
+
- Facilement extensible pour des tâches comme la segmentation et la détection.
|
| 240 |
+
|
| 241 |
+
### Utilisation :
|
| 242 |
+
VGG16 est utilisé pour :
|
| 243 |
+
- La classification d'images dans des bases de données variées.
|
| 244 |
+
- L'extraction de caractéristiques pour des modèles personnalisés.
|
| 245 |
+
- Les applications médicales nécessitant des modèles interprétables.
|
| 246 |
+
""")
|
| 247 |
+
|
| 248 |
+
with tab_mobilenetv2:
|
| 249 |
+
st.image("mobilenetv2.webp", caption="MobileNetV2", width=700)
|
| 250 |
+
st.write("""
|
| 251 |
+
**MobileNetV2** est un modèle léger optimisé pour les appareils mobiles et embarqués. Il repose sur des blocs convolutifs de profondeur et des connexions résiduelles.
|
| 252 |
+
|
| 253 |
+
### Avantages :
|
| 254 |
+
- Très efficace en termes de calcul avec un compromis optimal entre précision et vitesse.
|
| 255 |
+
- Convient aux appareils à faible puissance (comme les smartphones).
|
| 256 |
+
- Supporte le déploiement facile via TensorFlow Lite ou PyTorch Mobile.
|
| 257 |
+
|
| 258 |
+
### Utilisation :
|
| 259 |
+
MobileNetV2 est utilisé pour :
|
| 260 |
+
- La reconnaissance d'images en temps réel sur des appareils mobiles.
|
| 261 |
+
- Les applications embarquées nécessitant des modèles compacts.
|
| 262 |
+
- Les tâches de vision par ordinateur sur des données limitées en ressources.
|
| 263 |
+
""")
|
| 264 |
+
|
| 265 |
+
st.write("Ces modèles pré-entraînés sont tous des choix puissants, adaptés à divers scénarios. Le choix dépend des besoins en performances, en taille de modèle et en capacité d'adaptation aux appareils cibles.")
|
| 266 |
+
|
| 267 |
+
|
| 268 |
+
|
| 269 |
+
elif menu == "🧠 Classification de l'état cérébral avec VGG16":
|
| 270 |
+
# Ajout d'un sous-titre explicatif pour informer sur la fonctionnalité
|
| 271 |
+
st.subheader("Classification avec VGG16 (PyTorch)")
|
| 272 |
+
|
| 273 |
+
# Présentation de la fonctionnalité pour l'utilisateur
|
| 274 |
+
st.markdown("""
|
| 275 |
+
Cette section vous permet de **classer une image d'état des reins** en fonction de son apparence.
|
| 276 |
+
Le modèle utilise **VGG16**, une architecture d'apprentissage profond optimisée pour analyser les images.
|
| 277 |
+
Voici ce que vous devez faire :
|
| 278 |
+
1. Téléchargez une image au format `jpg`, `jpeg` ou `png`.
|
| 279 |
+
2. Cliquez sur le bouton **Classifier** pour lancer l'analyse.
|
| 280 |
+
3. Obtenez le résultat du diagnostic (Normal ou Anomalie) accompagné d'un graphique des probabilités.
|
| 281 |
+
""")
|
| 282 |
+
|
| 283 |
+
# Étape 1 : L'utilisateur télécharge une image
|
| 284 |
+
uploaded_file = st.file_uploader("Téléchargez une image des reins (format jpg, jpeg ou png)", type=["jpg", "jpeg", "png"])
|
| 285 |
+
|
| 286 |
+
if uploaded_file is not None:
|
| 287 |
+
# Affiche l'image téléchargée
|
| 288 |
+
image = Image.open(uploaded_file)
|
| 289 |
+
st.image(image, caption="Image téléchargée avec succès", use_container_width=True)
|
| 290 |
+
|
| 291 |
+
# Explication pour l'étape suivante
|
| 292 |
+
st.markdown("""
|
| 293 |
+
Cliquez sur le bouton **Classifier** pour que le modèle analyse l'image et détermine si l'état des reins est **Normal** ou présente une **Anomalie**.
|
| 294 |
+
""")
|
| 295 |
+
|
| 296 |
+
# Étape 2 : L'utilisateur clique pour classifier l'image
|
| 297 |
+
if st.button("Classifier"):
|
| 298 |
+
# Appel de la fonction de prédiction avec le modèle ResNet50
|
| 299 |
+
label, probabilities = predict_with_pytorch(MODEL_PYTORCH_PATH, image, class_names)
|
| 300 |
+
|
| 301 |
+
# Affichage du résultat
|
| 302 |
+
st.markdown(f"""
|
| 303 |
+
### Résultat de la classification :
|
| 304 |
+
**Classe prédite :** {label}
|
| 305 |
+
""", unsafe_allow_html=True)
|
| 306 |
+
|
| 307 |
+
# Affichage des probabilités sous forme de graphique
|
| 308 |
+
st.markdown("""
|
| 309 |
+
#### Confiance du modèle dans chaque catégorie :
|
| 310 |
+
Le graphique ci-dessous montre la probabilité associée à chaque classe. Une probabilité élevée indique la classe la plus probable.
|
| 311 |
+
""")
|
| 312 |
+
st.bar_chart(probabilities)
|
| 313 |
+
|
| 314 |
+
# Affichage d'un message visuel en fonction de la classe prédite
|
| 315 |
+
if label == "Healthy":
|
| 316 |
+
st.balloons() # Animation festive si le résultat est "Normal"
|
| 317 |
+
st.success("Félicitations ! L'image a été classée comme **Normale**.")
|
| 318 |
+
else:
|
| 319 |
+
st.error("Désolé, le modèle indique une **Anomalie** dans l'image téléchargée.")
|
| 320 |
+
st.markdown("""
|
| 321 |
+
#### Que faire en cas d'anomalie ?
|
| 322 |
+
Si une anomalie est détectée, il est recommandé de :
|
| 323 |
+
- Vérifier l'image téléchargée pour s'assurer qu'elle est correcte.
|
| 324 |
+
- Contacter un professionnel de santé pour une analyse approfondie.
|
| 325 |
+
""")
|
| 326 |
+
|
| 327 |
+
|
| 328 |
+
elif menu == "Comparatif entre modèles":
|
| 329 |
+
st.write("""
|
| 330 |
+
|
| 331 |
+
## **Analyse et Conclusions**
|
| 332 |
+
|
| 333 |
+
### **Pourquoi VGG16 est un meilleur choix ?**
|
| 334 |
+
|
| 335 |
+
Dans ce projet, nous avons utilisé **VGG16** pour la classification d'images en nous basant sur le **transfert d'apprentissage** sous **PyTorch**. Après avoir comparé plusieurs modèles, **VGG16 s'est révélé être le plus adapté** aux tâches de classification d'images grâce aux éléments suivants :
|
| 336 |
+
|
| 337 |
+
---
|
| 338 |
+
|
| 339 |
+
### **1. Simplicité et efficacité de l’architecture**
|
| 340 |
+
L’architecture de **VGG16** repose sur des couches convolutives empilées de manière séquentielle, suivies de couches entièrement connectées. Cette approche simplifiée permet :
|
| 341 |
+
- Une **meilleure généralisation** sur des tâches de classification avec peu de données.
|
| 342 |
+
- Une extraction de **caractéristiques précises et hiérarchisées**, facilitant l’adaptation du modèle via le transfert learning.
|
| 343 |
+
|
| 344 |
+
👉 **Avantage** : Contrairement à ResNet50, VGG16 ne dépend pas de connexions résiduelles complexes, ce qui facilite sa mise en œuvre et son ajustement en fonction des besoins spécifiques du projet.
|
| 345 |
+
|
| 346 |
+
---
|
| 347 |
+
|
| 348 |
+
### **2. Robustesse et fiabilité pour des images complexes**
|
| 349 |
+
VGG16 a été utilisé dans de nombreux projets de **vision par ordinateur** et s’est avéré efficace dans divers contextes. Son architecture permet de capturer des **détails fins** dans les images, ce qui est un atout pour :
|
| 350 |
+
- La **reconnaissance d’objets** et de **textures complexes**.
|
| 351 |
+
- La **classification médicale**, où la précision est cruciale, ce qui est le cas de notre jeu de données.
|
| 352 |
+
|
| 353 |
+
👉 **Avantage** : Sa capacité à apprendre des caractéristiques riches **sans nécessiter une optimisation trop poussée** en fait un modèle fiable et éprouvé.
|
| 354 |
+
|
| 355 |
+
---
|
| 356 |
+
|
| 357 |
+
### **3. Équilibre entre performance et coût computationnel**
|
| 358 |
+
Bien que **ResNet50** possède moins de paramètres (~25M contre ~138M pour VGG16), cela ne signifie pas nécessairement une meilleure performance sur des datasets limités. En effet, **VGG16 tire parti de sa structure régulière** pour apprendre efficacement même lorsque les données sont en quantité modérée.
|
| 359 |
+
|
| 360 |
+
- **VGG16** fonctionne bien **sans nécessiter de grandes ressources GPU**, ce qui le rend **idéal pour des environnements à puissance limitée**.
|
| 361 |
+
- Son absence de connexions résiduelles permet d’éviter des erreurs d’instabilité lors de l’entraînement.
|
| 362 |
+
|
| 363 |
+
👉 **Avantage** : **Facile à entraîner** et adapté aux **configurations matérielles classiques**.
|
| 364 |
+
|
| 365 |
+
---
|
| 366 |
+
|
| 367 |
+
### **4. Meilleures performances en transfert learning**
|
| 368 |
+
L'utilisation de **VGG16 pré-entraîné sur ImageNet** sous PyTorch nous a permis d'obtenir :
|
| 369 |
+
- Une **précision élevée** sur notre ensemble de validation.
|
| 370 |
+
- Une **stabilité des performances**, sans risque de dégradation des gradients.
|
| 371 |
+
|
| 372 |
+
👉 **Avantage** : En **gelant les couches de convolution** et en **réentraînant uniquement la tête de classification**, VGG16 s’adapte rapidement à de nouvelles tâches.
|
| 373 |
+
|
| 374 |
+
---
|
| 375 |
+
|
| 376 |
+
### **5. Comparaison avec d’autres modèles**
|
| 377 |
+
|
| 378 |
+
| Critère | VGG16 | ResNet50 | MobileNetV2 |
|
| 379 |
+
|-----------------------|------------------------|--------------------------|-------------------------|
|
| 380 |
+
| **Nombre de paramètres** | ~138M | ~25M | ~3.4M |
|
| 381 |
+
| **Profondeur** | 16 couches | 50 couches | Profondeur dynamique |
|
| 382 |
+
| **Performance** | Haute précision | Très bonne mais plus complexe à optimiser | Légèrement inférieure |
|
| 383 |
+
| **Taille et vitesse** | Modérée | Plus rapide mais parfois instable | Très légère et rapide |
|
| 384 |
+
|
| 385 |
+
- **ResNet50** : Son architecture résiduelle est puissante, mais **nécessite un ajustement plus fin des hyperparamètres**, ce qui peut poser problème sur des datasets limités.
|
| 386 |
+
- **MobileNetV2** : Très léger, mais **moins performant** pour des tâches nécessitant une haute précision.
|
| 387 |
+
|
| 388 |
+
👉 **Pourquoi VGG16 ?** Sa simplicité et son efficacité en font un choix sûr et performant pour **la classification d’images sous PyTorch**.
|
| 389 |
+
|
| 390 |
+
---
|
| 391 |
+
|
| 392 |
+
### **6. Résultats observés dans ce projet**
|
| 393 |
+
En utilisant **VGG16 avec du transfert learning**, nous avons obtenu :
|
| 394 |
+
✅ Une **précision élevée**, même avec un dataset limité.
|
| 395 |
+
✅ Une **convergence rapide**, sans nécessiter d'ajustements complexes.
|
| 396 |
+
✅ Une **bonne stabilité des résultats**, sans risque de sur-apprentissage excessif.
|
| 397 |
+
|
| 398 |
+
---
|
| 399 |
+
|
| 400 |
+
## **Conclusion**
|
| 401 |
+
|
| 402 |
+
En résumé, **VGG16** s'est avéré être **le meilleur choix pour ce projet** en raison de :
|
| 403 |
+
- **Son architecture simple et efficace**, qui facilite son implémentation sous PyTorch.
|
| 404 |
+
- **Son excellente capacité d’apprentissage** pour des tâches de classification d’images complexes.
|
| 405 |
+
- **Son efficacité en transfert learning**, permettant une adaptation rapide sans nécessiter d’énormes ressources GPU.
|
| 406 |
+
|
| 407 |
+
👉 **Recommandation** : Pour des tâches de **classification d’images nécessitant une précision élevée et une mise en œuvre rapide**, **VGG16 est le modèle idéal sous PyTorch**. 🚀
|
| 408 |
+
""")
|
| 409 |
+
|
| 410 |
+
|
| 411 |
+
elif menu == "👨💻À propos":
|
| 412 |
+
st.header("À propos de moi")
|
| 413 |
+
st.markdown(
|
| 414 |
+
"""
|
| 415 |
+
<div style="text-align:center; font-family: Arial; margin: 20px 0;">
|
| 416 |
+
<h2>Mon Parcours</h2>
|
| 417 |
+
<p>Je suis un passionné de l'intelligence artificielle et de la donnée. Actuellement en Master 2 en IA et Big Data, je travaille sur des solutions innovantes dans le domaine de l'Intelligence Artificielle appliquée à la santé.</p>
|
| 418 |
+
</div>
|
| 419 |
+
<div style="display: flex; justify-content: center; gap: 30px; flex-wrap: wrap;">
|
| 420 |
+
<div style="text-align: center;">
|
| 421 |
+
<img src="https://avatars.githubusercontent.com/u/1234567" alt="Ngoue David" style="width: 150px; height: 150px; border-radius: 50%;">
|
| 422 |
+
<h4>Ngoue David</h4>
|
| 423 |
+
<p>🎓 Master 2 IA & Big Data</p>
|
| 424 |
+
<p>📧 <a href="mailto:ngouedavidrogeryannick@gmail.com">ngouedavidrogeryannick@gmail.com</a></p>
|
| 425 |
+
<p>🌐 <a href="https://github.com/TheBeyonder237" target="_blank">Profil GitHub</a></p>
|
| 426 |
+
</div>
|
| 427 |
+
</div>
|
| 428 |
+
""", unsafe_allow_html=True)
|
glioma.jpg
ADDED
|
mobilenetv2.webp
ADDED
|
Git LFS Details
|
resnet50_image.webp
ADDED
|
Git LFS Details
|
vgg16_image.jpg
ADDED
|