# Projet : Classification d'images avec Fashion MNIST Ce projet a pour objectif de démontrer un flux de travail complet (end-to-end) pour l'entraînement, le déploiement et le test d'un modèle de Machine Learning (ML) en utilisant Python. Le projet se concentre sur la classification d'images du dataset Fashion MNIST, qui contient des images de vêtements en niveaux de gris de 28x28 pixels. Le projet est divisé en trois parties principales : 1. **Entraînement des modèles** : Utilisation de `train_models.py` pour entraîner plusieurs modèles de classification. 2. **Déploiement de l'API** : Utilisation de Flask pour créer une API qui permet de faire des prédictions avec les modèles entraînés. 3. **Interface utilisateur** : Utilisation de Streamlit pour créer une interface utilisateur simple qui permet de télécharger des images et d'obtenir des prédictions via l'API Flask. ## Étapes du projet ### Prérequis 1. Créer un environement `ml` avec * La version python `3.10` * Télécharger Anaconda à partir de ce [lien](https://www.anaconda.com/download/success) * Lors de l'installation cocher " ajouter anaconda aux variables d'environements " ![Capture](https://hackmd.io/_uploads/SJF6vKHiye.png) * Voici la liste des dépendances nécessaires pour ce projet : ```file=requirements.txt #requirements.txt numpy==1.26.4 pandas==2.2.3 scikit-learn==1.6.1 scipy==1.12.0 matplotlib==3.10.0 seaborn==0.13.2 #tensorflow==2.18.0 #tensorflow-addons==0.22.0 keras==3.8.0 jupyterlab==4.3.5 ipython==8.21.0 ipykernel==6.29.5 ipywidgets==8.1.5 openml==0.15.1 mlxtend==0.23.4 imbalanced-learn==0.13.0 category_encoders==2.8.0 gdown==5.2.0 GPy==1.13.2 graphviz==0.20.3 streamlit==1.42.1 Flask==3.1.0 ``` * Créer un fichier requirements.txt contenant les packages ci-dessus. * Ouvrir anaconda prompt dans le dossier contenenant le fichier `requirements.txt` ![createML](https://hackmd.io/_uploads/SkGkqtroyx.png) ```bash # Créer l'environnement , Taper ceci dans anaconda prompt # si vous avez déjà créer cet environement avec anaconda-navigator passer à la commande suivante conda create --name ml python=3.10 # Activer l'environnement conda activate ml # Installer les dépendances pip install -r requirements.txt ``` 2. Initialisation de `git` * Télécharger `git` à partir de ce [lien](https://git-scm.com/downloads/win) * Avant de commencer, configure ton nom d'utilisateur et ton email si ce n'est pas encore fait sur ta machine : ```bash git config --global user.name "nevermind78" git config --global user.email "ton-email@example.com" ``` * Vérifie la configuration avec : ```bash git config --global --list ``` 2️⃣ Créer un nouveau dossier `projet` , ouvrir un terminal git et se placer dans le dossier du projet qui a été déjà créer ```bash cd projet ``` * Placer les fichiers : - [`api.py`](#api-py) ( api *Flask*) - [`app.py`](#app-py) ( application streamlit front) - [`train_models.py`](#train-models-py) ( Création des modèles) - [`download_test.py`](#download-test-py) ( Télécharger des images de test) 3️⃣ Initialiser un dépôt Git dans ce dossier ```bash git init ``` 4️⃣ Ajouter tous les fichiers du projet au suivi Git ```bash git add . ``` 5️⃣ Créer un commit avec un message explicatif ```bash git commit -m "Initial commit" ``` 6️⃣ Créer un dépôt sur GitHub Va sur GitHub * Crée un dépôt projet25 (⚠️ sans initialiser avec un README) 7️⃣ Lier le dépôt local avec le dépôt GitHub ```bash git remote add origin https://github.com/nevermind78/projet25.git ``` * Vérifie si le lien est bien ajouté : ```bash git remote -v ``` 8️⃣ Définir la branche principale (main) ```bash git branch -M main ``` 9️⃣ Envoyer le projet sur GitHub ```bash git push -u origin main ``` ✅ Ton projet est maintenant synchronisé avec GitHub ! 🎉🚀 🔄 Pour les prochaines modifications : * À chaque changement, utilise : ```bash git add . git commit -m "Description des modifications" git push origin main ``` ### 1. Entraînement des modèles (`train_models.py`) Le script `train_models.py` est responsable de l'entraînement des modèles de classification. Voici les étapes principales : - **Chargement des données** : Le dataset Fashion MNIST est chargé à l'aide de la bibliothèque `openml`. - **Préprocessing** : Les images sont normalisées en divisant les valeurs des pixels par 255 pour les ramener dans l'intervalle [0, 1]. - **Division des données** : Les données sont divisées en ensembles d'entraînement et de test avec une proportion de 10% pour l'entraînement. - **Entraînement des modèles** : Trois modèles sont entraînés : - Régression logistique (`LogisticRegression`) - SVM linéaire (`LinearSVC`) - K-Nearest Neighbors (`KNeighborsClassifier`) - **Sauvegarde des modèles** : Les modèles entraînés sont sauvegardés en utilisant `joblib` pour être utilisés ultérieurement dans l'API. ### train_models.py ```python= import numpy as np import pandas as pd import matplotlib.pyplot as plt from sklearn.model_selection import train_test_split, cross_validate from sklearn.linear_model import LogisticRegression from sklearn.svm import LinearSVC from sklearn.neighbors import KNeighborsClassifier from sklearn.metrics import accuracy_score import joblib import openml as oml # Charger les données fmnist = oml.datasets.get_dataset(40996) X, y, _, _ = fmnist.get_data(target=fmnist.default_target_attribute) # Preprocessing X = X / 255.0 # Normalisation X_train, X_test, y_train, y_test = train_test_split(X, y, stratify=y, train_size=0.1) # Définir les modèles classifiers = [LogisticRegression(max_iter=1000), LinearSVC(max_iter=1000), KNeighborsClassifier()] # Entraîner les modèles for clf in classifiers: clf.fit(X_train, y_train) # Sauvegarder les modèles joblib.dump(classifiers[0], 'logistic_regression.pkl') joblib.dump(classifiers[1], 'linear_svc.pkl') joblib.dump(classifiers[2], 'knn.pkl') print("Les modèles ont été entraînés et sauvegardés.") ``` ### 2. Déploiement de l'API Flask (`api.py`) L'API Flask est utilisée pour servir les modèles entraînés et permettre des prédictions en temps réel. Voici les étapes principales : - **Chargement des modèles** : Les modèles sauvegardés sont chargés en mémoire. - **Endpoint de prédiction** : Un endpoint `/predict` est créé pour recevoir des images et renvoyer des prédictions. - **Traitement de l'image** : L'image téléchargée est convertie en niveaux de gris, redimensionnée à 28x28 pixels, et normalisée. - **Prédiction** : Le modèle sélectionné est utilisé pour prédire la classe de l'image. - **Réponse** : La prédiction est renvoyée sous forme de JSON. ### `api.py` ```python= from flask import Flask, request, jsonify import joblib import numpy as np from PIL import Image import io app = Flask(__name__) # Charger les modèles logistic_regression = joblib.load('logistic_regression.pkl') linear_svc = joblib.load('linear_svc.pkl') knn = joblib.load('knn.pkl') @app.route('/predict', methods=['POST']) def predict(): if 'file' not in request.files: return jsonify({"error": "No file provided"}), 400 file = request.files['file'] # Réinitialiser le pointeur du fichier file.seek(0) try: # Lire le fichier en mémoire file_data = file.read() # Ouvrir l'image à partir des données en mémoire image = Image.open(io.BytesIO(file_data)).convert('L').resize((28, 28)) except Exception as e: return jsonify({"error": f"Failed to process image: {str(e)}"}), 400 # Convertir l'image en tableau NumPy image_array = np.array(image).reshape(1, -1) / 255.0 # Récupérer le modèle sélectionné model_name = request.form.get('model') if model_name == "Logistic Regression": prediction = logistic_regression.predict(image_array) elif model_name == "Linear SVC": prediction = linear_svc.predict(image_array) elif model_name == "KNN": prediction = knn.predict(image_array) else: return jsonify({"error": "Invalid model name"}), 400 # Renvoyer uniquement la prédiction return jsonify({ "prediction": int(prediction[0]) # Convertir en entier pour éviter les problèmes de sérialisation }) if __name__ == '__main__': app.run(debug=True) ``` ### 3. Interface utilisateur avec Streamlit (`app.py`) L'interface utilisateur est créée avec Streamlit pour permettre aux utilisateurs de télécharger des images et d'obtenir des prédictions. Voici les étapes principales : - **Configuration de l'entraînement** : L'utilisateur peut sélectionner la proportion des données à utiliser pour l'entraînement. - **Lancement de l'entraînement** : Un bouton permet de lancer l'entraînement des modèles (simulé dans ce cas). - **Téléchargement d'image** : L'utilisateur peut télécharger une image pour la classification. - **Sélection du modèle** : L'utilisateur peut choisir parmi les trois modèles entraînés. - **Prédiction** : Un bouton permet de lancer la prédiction en envoyant l'image à l'API Flask. - **Affichage du résultat** : La prédiction est affichée sous forme de nom de classe et de numéro de classe. ### `app.py` ```python= import streamlit as st from PIL import Image import requests # Titre de l'application st.title("Classification d'images avec Fashion MNIST") # Classes Fashion MNIST fmnist_classes = [ "T-shirt/top", # Classe 0 "Trouser", # Classe 1 "Pullover", # Classe 2 "Dress", # Classe 3 "Coat", # Classe 4 "Sandal", # Classe 5 "Shirt", # Classe 6 "Sneaker", # Classe 7 "Bag", # Classe 8 "Ankle boot" # Classe 9 ] # URL de l'API Flask (remplacez par l'URL de votre API si nécessaire) API_URL = "http://127.0.0.1:5000/predict" # Téléchargement de l'image uploaded_file = st.file_uploader("Téléchargez une image (28x28 pixels)", type=["png", "jpg", "jpeg"]) # Afficher l'image téléchargée une seule fois if uploaded_file is not None: # Réinitialiser le pointeur du fichier pour éviter l'erreur PIL uploaded_file.seek(0) # Ouvrir l'image image = Image.open(uploaded_file).convert('L') # Convertir en niveaux de gris # Afficher l'image avec une taille réduite col1, col2, col3 = st.columns([1, 2, 1]) with col2: # Utilise la colonne du milieu pour centrer l'image st.image(image, caption="Image téléchargée", width=150) # Sélection du modèle model_name = st.selectbox( "Sélectionnez un modèle", ["Logistic Regression", "Linear SVC", "KNN"] ) # Bouton pour lancer la prédiction if st.button("Prédire"): if uploaded_file is not None: # Réinitialiser le pointeur du fichier uploaded_file.seek(0) # Envoyer la requête à l'API Flask files = {"file": uploaded_file} data = {"model": model_name} response = requests.post(API_URL, files=files, data=data) # Afficher le résultat if response.status_code == 200: result = response.json() prediction = result.get("prediction") # Correction : "prediction" -> "prediction" # Afficher la prédiction class_name = fmnist_classes[prediction] # Convertir le numéro en nom de classe st.success(f"**Prédiction :** {class_name} (Classe {prediction})") else: st.error(f"Erreur lors de la prédiction : {response.text}") else: st.warning("Veuillez télécharger une image avant de lancer la prédiction.") ``` ## Guide étape par étape ### Étape 1 : Entraînement des modèles 0. Télécharger des images pour le test ### `download_test.py` ```python= import numpy as np import matplotlib.pyplot as plt import openml as oml import os # Charger le dataset Fashion MNIST fmnist = oml.datasets.get_dataset(40996) X, y, _, _ = fmnist.get_data(target=fmnist.default_target_attribute) # Convertir X en tableau NumPy X = X.to_numpy() print(y) # Créer un dossier pour sauvegarder les images output_dir = "test_images" os.makedirs(output_dir, exist_ok=True) # Sauvegarder 10 images de test for i in range(10,20): # Vous pouvez changer le nombre d'images à sauvegarder image = X[i].reshape(28, 28) # Redimensionner en 28x28 pixels image_path = os.path.join(output_dir, f"test_image_{i}.png") plt.imsave(image_path, image, cmap='gray') print(f"Image {i} sauvegardée sous {image_path}") ``` 2. Exécutez le script `train_models.py` pour entraîner les modèles et les sauvegarder. ```bash python train_models.py ``` 2. Les modèles entraînés seront sauvegardés sous les noms `logistic_regression.pkl`, `linear_svc.pkl`, et `knn.pkl`. ### Étape 2 : Démarrage de l'API Flask 1. Exécutez le script api.py pour démarrer l'API Flask. ```bash python api.py ``` 2. L'API sera disponible à l'adresse **`http://127.0.0.1:5000.`** ### Étape 3 : Utilisation de l'interface Streamlit 1. Exécutez le script app.py pour démarrer l'interface Streamlit. ```bash streamlit run app.py ``` <div style="background-color: #1e3a5f; border-left: 5px solid #3498db; padding: 10px; margin: 10px 0; color: #ffffff;"> <strong>⚠️ Avertissement :</strong> Si vous rencontrez un problème avec sklearn et joblib et threadpool. Veuillez éxécuter cette commande ( dans l'environement <b>ml</b> ). </div> ```bash= pip install --upgrade scikit-learn threadpoolctl joblib ``` 2. L'interface sera disponible dans votre navigateur à l'adresse indiquée dans le terminal. ![app](https://hackmd.io/_uploads/SJ24nbriyx.png) 3. Téléchargez une image de 28x28 pixels et sélectionnez un modèle pour obtenir une prédiction. ![appML0](https://hackmd.io/_uploads/SJzeyGrskx.gif)