<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: David Scanu </title>
    <description>The latest articles on DEV Community by David Scanu  (@davidscanu).</description>
    <link>https://dev.to/davidscanu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1192319%2Fef316db6-1608-4c97-9809-401dcaf73c89.jpg</url>
      <title>DEV Community: David Scanu </title>
      <link>https://dev.to/davidscanu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/davidscanu"/>
    <language>en</language>
    <item>
      <title>🚗👁️ Segmentation d'Images pour le système embarqué d’une voiture autonome</title>
      <dc:creator>David Scanu </dc:creator>
      <pubDate>Wed, 25 Jun 2025 07:30:17 +0000</pubDate>
      <link>https://dev.to/davidscanu/segmentation-dimages-pour-pour-le-systeme-embarque-dune-voiture-autonome-2f5e</link>
      <guid>https://dev.to/davidscanu/segmentation-dimages-pour-pour-le-systeme-embarque-dune-voiture-autonome-2f5e</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp172wc5pgs3w3w9m98sc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp172wc5pgs3w3w9m98sc.png" alt=" " width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌐 Introduction
&lt;/h2&gt;

&lt;p&gt;Ce projet s'inscrit dans le développement d'un &lt;strong&gt;système embarqué de vision par ordinateur&lt;/strong&gt; pour véhicules autonomes chez &lt;strong&gt;Future Vision Transport&lt;/strong&gt;. L'entreprise conçoit des systèmes permettant aux véhicules autonomes de percevoir leur environnement grâce à l'analyse d'images en temps réel.&lt;/p&gt;

&lt;p&gt;En tant qu'&lt;strong&gt;ingénieur IA dans l'équipe R&amp;amp;D&lt;/strong&gt;, notre mission est de &lt;strong&gt;développer le module de segmentation d'images&lt;/strong&gt; (composant 3) qui s'intègre entre le module de traitement d'images (2) et le système de décision (4). Ce module doit être capable d'&lt;strong&gt;identifier et de segmenter précisément 8 catégories principales d'objets&lt;/strong&gt; dans des images de caméras embarquées.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cette note technique présente la conception et l'implémentation d'un modèle de segmentation d'images optimisé pour la compréhension des scènes urbaines&lt;/strong&gt;. Le système développé s'intègre dans une chaîne complète comprenant l'acquisition d'images en temps réel, le traitement des images, la segmentation sémantique (notre contribution) et le système de décision final.&lt;/p&gt;




&lt;h2&gt;
  
  
  🎯 Objectifs
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Développer un modèle de segmentation d'images performant&lt;/strong&gt; avec &lt;a href="https://keras.io/" rel="noopener noreferrer"&gt;Keras&lt;/a&gt;/&lt;a href="https://www.tensorflow.org/?hl=fr" rel="noopener noreferrer"&gt;TensorFlow&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Concevoir et déployer une &lt;strong&gt;API REST&lt;/strong&gt; avec &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Créer une &lt;strong&gt;application web de démonstration&lt;/strong&gt; avec &lt;a href="https://nextjs.org/" rel="noopener noreferrer"&gt;Next.js&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documenter le processus et les résultats&lt;/strong&gt; de façon claire et professionnelle&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  💾 Dépôt GitHub
&lt;/h2&gt;

&lt;p&gt;L'intégralité du code du projet (notebook, backend et frontend) est disponible sur le dépôt GitHub : &lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p08-images-systeme-voiture-autonome" rel="noopener noreferrer"&gt;Projet 8 : Traitement d'images pour le système embarqué d'une voiture autonome&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  👋 À propos
&lt;/h2&gt;

&lt;p&gt;Projet développé par &lt;a href="https://www.linkedin.com/in/davidscanu14/" rel="noopener noreferrer"&gt;David Scanu&lt;/a&gt; dans le cadre du parcours &lt;a href="https://openclassrooms.com/fr/paths/795-ai-engineer" rel="noopener noreferrer"&gt;AI Engineer&lt;/a&gt; d'OpenClassrooms : &lt;strong&gt;Projet 8 - Traitez les images pour le système embarqué d'une voiture autonome&lt;/strong&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  👁️ 1. Développement du Modèle de Segmentation
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Le &lt;a href="https://colab.research.google.com/drive/1jZ2tdEyJ2xaERUCwyQ5juwPJrEyIAtBN?usp=sharing" rel="noopener noreferrer"&gt;notebook complet de conception du modèle de segmentation d'image&lt;/a&gt; est disponible sur Colab.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.1 Contexte et Enjeux
&lt;/h3&gt;

&lt;p&gt;La &lt;a href="https://fr.wikipedia.org/wiki/Segmentation_d%27image" rel="noopener noreferrer"&gt;segmentation sémantique d'image&lt;/a&gt; dans le contexte automobile représente un défi technique majeur. Contrairement à la classification d'images qui attribue une étiquette à une image entière, la segmentation sémantique doit &lt;strong&gt;identifier et catégoriser chaque pixel de l'image&lt;/strong&gt;. Pour un véhicule autonome, cette capacité est cruciale : il faut distinguer la route des trottoirs, identifier les véhicules, détecter les piétons, reconnaître la végétation, etc.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;La segmentation sémantique consiste à &lt;strong&gt;étiqueter chaque pixel d’une image avec une classe correspondante&lt;/strong&gt; à ce qui est représenté. On parle aussi de  "prédiction dense", car chaque pixel doit être prédit. Elle génère une image, sur laquelle chaque pixel est classifié.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.2 Étude du jeu de données et préparation pour l'entraînement
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.2.1 Le jeu de données Cityscapes
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6kxdlei6o0706kpx0gw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ft6kxdlei6o0706kpx0gw.png" alt=" " width="800" height="389"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nous avons choisi le jeu de données &lt;a href="https://www.cityscapes-dataset.com/dataset-overview/" rel="noopener noreferrer"&gt;Cityscapes&lt;/a&gt;, une référence dans le domaine de la segmentation urbaine. Ce dataset présente plusieurs avantages décisifs pour notre cas d'usage :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;5 000 images avec annotations fines&lt;/strong&gt; réparties en 2 975 images d'entraînement, 500 de validation et 1 525 de test&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Diversité géographique&lt;/strong&gt; : 50 villes européennes différentes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Conditions variées&lt;/strong&gt; : Plusieurs saisons, conditions météorologiques bonnes à moyennes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Richesse des annotations&lt;/strong&gt; : 30 classes détaillées avec des annotations polygonales précises&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Réalisme&lt;/strong&gt; : Images capturées depuis des véhicules en circulation réelle&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.2.2 Stratégie de Regroupement des Classes
&lt;/h4&gt;

&lt;p&gt;L'une des décisions techniques les plus importantes a été le &lt;strong&gt;regroupement des 30+ classes originales de Cityscapes en 8 catégories pertinentes pour la navigation autonome&lt;/strong&gt;. Cette simplification répond à plusieurs objectifs :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pertinence fonctionnelle&lt;/strong&gt; : Regrouper les éléments ayant la même importance pour la décision de navigation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance computationnelle&lt;/strong&gt; : Réduire la complexité du modèle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustesse&lt;/strong&gt; : Éviter la sur-spécialisation sur des classes très spécifiques&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Notre mapping final :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;class_groups&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;flat&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;road&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sidewalk&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;parking&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rail track&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;human&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;person&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rider&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; 
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vehicle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;car&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;truck&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bus&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;motorcycle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bicycle&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;construction&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;building&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;wall&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;fence&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bridge&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;object&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pole&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;traffic sign&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;traffic light&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nature&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;vegetation&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;terrain&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sky&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sky&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;void&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;unlabeled&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;out of roi&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;...]&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette approche nous permet de maintenir une granularité suffisante pour la prise de décision tout en gardant un modèle tractable.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.2.3 Pipeline de Préparation des Données
&lt;/h4&gt;

&lt;p&gt;Notre pipeline de préparation des données intègre plusieurs étapes :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Redimensionnement intelligent&lt;/strong&gt; : Les images Cityscapes originales (2048×1024) sont redimensionnées à 224×224, un compromis entre qualité visuelle et performance computationnelle. Cette taille est également optimale pour l'utilisation de &lt;a href="https://keras.io/api/applications/mobilenet/#mobilenetv2-function" rel="noopener noreferrer"&gt;MobileNetV2 pré-entraîné&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stratégie de validation&lt;/strong&gt; : Pour éviter le &lt;a href="https://datascientest.com/data-leakage-tout-savoir" rel="noopener noreferrer"&gt;"data leakage"&lt;/a&gt;, nous avons adopté une approche rigoureuse :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Division du dataset 'train' original en &lt;strong&gt;80% entraînement&lt;/strong&gt; / &lt;strong&gt;20% validation&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Utilisation du dataset 'val' original comme &lt;strong&gt;dataset de test final&lt;/strong&gt; : cette approche garantit que notre évaluation finale est réalisée sur des données jamais vues&lt;/li&gt;
&lt;li&gt;Les masques du dataset 'test' étaient indisponibles (complètement noirs) : nous n'avons pas utilisé ce dossier&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Augmentation de données&lt;/strong&gt; : Nous avons implémenté des techniques d'augmentation adaptées à la segmentation :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Flip horizontal aléatoire&lt;/strong&gt; (50% de probabilité)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Appliqué de manière synchronisée sur l'image et le masque&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Variation de luminosité aléatoire&lt;/strong&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Appliquée uniquement sur l'image (pas sur le masque)&lt;/li&gt;
&lt;li&gt;Amplitude : ±0.1&lt;/li&gt;
&lt;li&gt;Avec clipping pour maintenir les valeurs dans [0,1]
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;augment_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# Flip horizontal synchronisé image/masque
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;random&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;uniform&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mf"&gt;0.5&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip_left_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;flip_left_right&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;mask&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Variation de luminosité (image seulement)
&lt;/span&gt;    &lt;span class="n"&gt;image&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random_brightness&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mask&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  1.3 Architecture du Modèle : &lt;strong&gt;MobileNetV2-UNet&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Nous avons développé une architecture qui combine la puissance de &lt;a href="https://keras.io/api/applications/mobilenet/" rel="noopener noreferrer"&gt;MobileNetV2&lt;/a&gt; (un réseau léger et efficace) avec la structure en forme de U de l'architecture &lt;a href="https://fr.wikipedia.org/wiki/U-Net" rel="noopener noreferrer"&gt;U-Net&lt;/a&gt; pour réaliser une segmentation d'images.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30g8tmrvi9alrduwhck0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F30g8tmrvi9alrduwhck0.png" alt=" " width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;
Architecture U-Net avec backbone MobileNetV2 pour segmentation sémantique d'images



&lt;h4&gt;
  
  
  1.3.1 Structure générale en forme de U
&lt;/h4&gt;

&lt;p&gt;Notre modèle hybride combine la puissance de &lt;strong&gt;MobileNetV2&lt;/strong&gt; pour l'extraction de caractéristiques avec la capacité de &lt;strong&gt;U-Net&lt;/strong&gt; à reconstruire des segmentations précises.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forme en U&lt;/strong&gt; : L'architecture suit une forme en "U" avec une partie descendante (encodeur) et une partie ascendante (décodeur).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Objectif&lt;/strong&gt; : Attribuer une classe à chaque pixel de l'image (segmentation).&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Partie encodeur (descendante)
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backbone MobileNetV2&lt;/strong&gt; : Utilisation de &lt;a href="https://keras.io/api/applications/mobilenet/" rel="noopener noreferrer"&gt;MobileNetV2&lt;/a&gt; comme encodeur léger et optimisé pour les appareils mobiles.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gel des poids&lt;/strong&gt; : Avec &lt;code&gt;base_model.trainable = False&lt;/code&gt;, les poids pré-entraînés sur ImageNet sont conservés, ce qui accélère l'entraînement et limite le surapprentissage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extraction multi-échelle&lt;/strong&gt; : Les caractéristiques sont extraites à différents niveaux de résolution pour les connexions de saut :

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;skip1&lt;/code&gt; : 112×112
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skip2&lt;/code&gt; : 56×56
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skip3&lt;/code&gt; : 28×28
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;skip4&lt;/code&gt; : 14×14
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;bottleneck&lt;/code&gt; : 7×7 (le niveau le plus profond du U-Net)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;L'encodeur extrait des caractéristiques à cinq niveaux de résolution différents. Cette extraction multi-échelle est cruciale : les premières couches capturent des détails fins (textures, contours) tandis que les couches profondes encodent des informations sémantiques de haut niveau.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stratégie de Transfer Learning&lt;/strong&gt; : Nous avons opté pour une approche de "frozen encoder" (enoder gelé) dans notre configuration "baseline".&lt;/p&gt;

&lt;p&gt;Cette décision présente plusieurs avantages :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Entraînement plus rapide (moins de paramètres à optimiser)&lt;/li&gt;
&lt;li&gt;Stabilité accrue (les caractéristiques ImageNet sont déjà robustes)&lt;/li&gt;
&lt;li&gt;Réduction du risque de sur-apprentissage&lt;/li&gt;
&lt;li&gt;Possibilité d'entraînement avec des ressources limitées&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Partie décodeur (ascendante)
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Reconstruction progressive&lt;/strong&gt; : À chaque étape, la résolution est doublée à l'aide de convolutions transposées :

&lt;ul&gt;
&lt;li&gt;7×7 → 14×14
&lt;/li&gt;
&lt;li&gt;14×14 → 28×28
&lt;/li&gt;
&lt;li&gt;28×28 → 56×56
&lt;/li&gt;
&lt;li&gt;56×56 → 112×112
&lt;/li&gt;
&lt;li&gt;112×112 → 224×224
&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Connexions de saut (Skip connections)&lt;/strong&gt; : Chaque niveau du décodeur est enrichi par les caractéristiques du niveau correspondant de l’encodeur pour préserver les détails spatiaux.&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Traitement post-upsampling&lt;/strong&gt; : Chaque étape comprend :

&lt;ul&gt;
&lt;li&gt;Convolution transposée
&lt;/li&gt;
&lt;li&gt;BatchNormalization
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://fr.wikipedia.org/wiki/Redresseur_(r%C3%A9seaux_neuronaux)" rel="noopener noreferrer"&gt;Activation ReLU&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Concaténation avec les features de l’encodeur
&lt;/li&gt;
&lt;li&gt;Convolution 3×3 pour affiner&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.3.2 Construction et Entraînement du Modèle
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modèle U-Net personnalisé&lt;/strong&gt; basé sur MobileNetV2, avec :

&lt;ul&gt;
&lt;li&gt;Paramètres ajustables : nombre de classes, taille d'entrée, taux d'apprentissage, backbone gelé ou non.&lt;/li&gt;
&lt;li&gt;Sortie : carte de segmentation pixel-par-pixel via une convolution 1×1 suivie d'une &lt;a href="https://fr.wikipedia.org/wiki/Fonction_softmax" rel="noopener noreferrer"&gt;activation &lt;code&gt;softmax&lt;/code&gt;&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Compilation : &lt;a href="https://www.ultralytics.com/fr/glossary/adam-optimizer" rel="noopener noreferrer"&gt;Optimiseur Adam&lt;/a&gt;, perte &lt;a href="https://keras.io/api/losses/probabilistic_losses/#sparsecategoricalcrossentropy-class" rel="noopener noreferrer"&gt;SparseCategoricalCrossentropy&lt;/a&gt;, et métrique &lt;a href="https://keras.io/api/metrics/accuracy_metrics/#sparsecategoricalaccuracy-class" rel="noopener noreferrer"&gt;SparseCategoricalAccuracy&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;Le choix de &lt;code&gt;SparseCategoricalCrossentropy&lt;/code&gt; est adapté car nos masques contiennent directement les indices des classes (format sparse) plutôt que des vecteurs one-hot.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_segmentation_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_classes&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;input_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
                            &lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;base_trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Create a segmentation model with configurable parameters
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Input tensor
&lt;/span&gt;    &lt;span class="n"&gt;inputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create MobileNetV2 base model
&lt;/span&gt;    &lt;span class="n"&gt;base_model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;applications&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;MobileNetV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;include_top&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;imagenet&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Configuration de l'entraînement du modèle de base
&lt;/span&gt;    &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_trainable&lt;/span&gt;

    &lt;span class="c1"&gt;# Create encoder using MobileNetV2
&lt;/span&gt;    &lt;span class="c1"&gt;# Get outputs at different levels for skip connections
&lt;/span&gt;    &lt;span class="n"&gt;skip1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block_1_expand_relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;      &lt;span class="c1"&gt;# 112x112
&lt;/span&gt;    &lt;span class="n"&gt;skip2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block_3_expand_relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;      &lt;span class="c1"&gt;# 56x56
&lt;/span&gt;    &lt;span class="n"&gt;skip3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block_6_expand_relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;      &lt;span class="c1"&gt;# 28x28
&lt;/span&gt;    &lt;span class="n"&gt;skip4&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block_13_expand_relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;     &lt;span class="c1"&gt;# 14x14
&lt;/span&gt;
    &lt;span class="c1"&gt;# Get bottleneck
&lt;/span&gt;    &lt;span class="n"&gt;bottleneck&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_layer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;block_16_project&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;output&lt;/span&gt;    &lt;span class="c1"&gt;# 7x7
&lt;/span&gt;
    &lt;span class="c1"&gt;# Use Model API to create encoder model
&lt;/span&gt;    &lt;span class="n"&gt;encoder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;base_model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nb"&gt;input&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;skip1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skip2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skip3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skip4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bottleneck&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

    &lt;span class="c1"&gt;# Encoder part - use the encoder model
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;inputs&lt;/span&gt;
    &lt;span class="n"&gt;skips&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;encoder&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Bottleneck
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;skips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;  &lt;span class="c1"&gt;# Use the bottleneck from encoder
&lt;/span&gt;
    &lt;span class="c1"&gt;# Decoder part - upsampling and skip connections
&lt;/span&gt;    &lt;span class="c1"&gt;# First upsampling: 7x7 -&amp;gt; 14x14
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2DTranspose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BatchNormalization&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concatenate&lt;/span&gt;&lt;span class="p"&gt;()([&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;256&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Second upsampling: 14x14 -&amp;gt; 28x28
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2DTranspose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BatchNormalization&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concatenate&lt;/span&gt;&lt;span class="p"&gt;()([&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Third upsampling: 28x28 -&amp;gt; 56x56
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2DTranspose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BatchNormalization&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concatenate&lt;/span&gt;&lt;span class="p"&gt;()([&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Fourth upsampling: 56x56 -&amp;gt; 112x112
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2DTranspose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BatchNormalization&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Concatenate&lt;/span&gt;&lt;span class="p"&gt;()([&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;skips&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]])&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;32&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Final upsampling: 112x112 -&amp;gt; 224x224
&lt;/span&gt;    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2DTranspose&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strides&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;BatchNormalization&lt;/span&gt;&lt;span class="p"&gt;()(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Activation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;x&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Output layer
&lt;/span&gt;    &lt;span class="n"&gt;outputs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Conv2D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num_classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;same&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;softmax&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Create model
&lt;/span&gt;    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;MobileNetV2-UNet&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Compile model avec learning rate configurable
&lt;/span&gt;    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;losses&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SparseCategoricalCrossentropy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SparseCategoricalAccuracy&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="c1"&gt;# keras.metrics.MeanIoU(num_classes=num_classes)
&lt;/span&gt;        &lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  Détails des paramètres
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total des paramètres&lt;/strong&gt; : 5,418,600

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Entraînables&lt;/strong&gt; : 3,575,624 (décodeur et tête de segmentation)
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-entraînables&lt;/strong&gt; : 1,842,976 (backbone gelé)&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Si &lt;code&gt;base_trainable=True&lt;/code&gt;, &lt;strong&gt;tous les paramètres deviennent entraînables&lt;/strong&gt;, offrant plus de flexibilité au prix d'un entraînement plus long.&lt;/li&gt;

&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.3.3 Justification du choix architectural
&lt;/h4&gt;

&lt;p&gt;Le choix de l'architecture MobileNetV2-UNet résulte d'une analyse approfondie des contraintes de notre projet embarqué, combinant les avantages complémentaires de deux architectures éprouvées :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pourquoi U-Net ?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Architecture de référence&lt;/strong&gt; pour la segmentation sémantique avec structure encoder-decoder&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connexions résiduelles (skip connections)&lt;/strong&gt; préservant les détails spatiaux fins lors de la reconstruction&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptée à la reconstruction&lt;/strong&gt; de résolution complète depuis des caractéristiques compressées&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Pourquoi MobileNetV2 ?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Conception spécifique&lt;/strong&gt; pour les applications mobiles et embarquées avec ressources limitées&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optimisations avancées&lt;/strong&gt; via les "depthwise separable convolutions" pour un rapport performance/efficacité optimal&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Transfer learning efficace&lt;/strong&gt; grâce aux poids pré-entraînés sur ImageNet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vitesse d'exécution&lt;/strong&gt; compatible avec les contraintes temps réel du véhicule autonome&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette architecture hybride MobileNetV2-UNet présente des bénéfices uniques pour notre cas d'usage :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Efficacité computationnelle&lt;/strong&gt; : Optimisée pour les environnements à ressources contraintes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Robustesse par transfer learning&lt;/strong&gt; : Exploitation des représentations ImageNet pour une convergence rapide&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Adaptabilité multi-tâches&lt;/strong&gt; : Architecture générique applicable à diverses tâches de segmentation urbaine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Préservation de l'information&lt;/strong&gt; : Maintien des détails spatiaux critiques pour la précision de segmentation&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;Cette combinaison offre le meilleur compromis entre précision de segmentation et efficacité embarquée, essentiel pour un système de vision automobile en temps réel.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  1.4 Entraînement et optimisation
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.4.1 Stratégie d'entraînement
&lt;/h4&gt;

&lt;p&gt;Notre approche d'entraînement intègre plusieurs techniques d'optimisation :&lt;/p&gt;

&lt;h5&gt;
  
  
  Callbacks Avancés
&lt;/h5&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ReduceLROnPlateau&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;val_loss&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;factor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patience&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;min_lr&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;1e-6&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;EarlyStopping&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;monitor&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;val_sparse_categorical_accuracy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;patience&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;restore_best_weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;callbacks&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;ModelCheckpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;filepath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;best_model.keras&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;save_best_only&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;mode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;max&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;ReduceLROnPlateau&lt;/strong&gt; : Réduction adaptative du taux d'apprentissage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;EarlyStopping&lt;/strong&gt; : Arrêt anticipé pour éviter le sur-apprentissage
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ModelCheckpoint&lt;/strong&gt; : Sauvegarde du meilleur modèle&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Gestion des expériences de Machine Learning avec MLflow
&lt;/h5&gt;

&lt;p&gt;Nous avons intégré &lt;a href="https://mlflow.org/" rel="noopener noreferrer"&gt;MLflow&lt;/a&gt; pour le suivi des expériences, permettant :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Versioning des modèles&lt;/strong&gt; et configurations&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Traçabilité complète des hyperparamètres&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Comparaison objective des performances&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Reproductibilité des résultats&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  1.4.2 Configuration Baseline
&lt;/h4&gt;

&lt;p&gt;Notre configuration "baseline" établit un point de référence solide :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;EXPERIMENT_CONFIG&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exp_name&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;exp_001_baseline&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;description&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Baseline MobileNetV2-UNet avec frozen encoder&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;params&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;learning_rate&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.0001&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;batch_size&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;epochs&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;base_model_trainable&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;validation_split&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;augmentation&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette configuration privilégie la stabilité et la reproductibilité, servant de fondation pour les expérimentations futures.&lt;/p&gt;

&lt;h4&gt;
  
  
  1.4.3 Analyse de l'entraînement du modèle
&lt;/h4&gt;

&lt;p&gt;L'entraînement de notre modèle MobileNetV2-UNet s'est déroulé sur &lt;strong&gt;18 époques&lt;/strong&gt; avec une &lt;strong&gt;convergence satisfaisante&lt;/strong&gt;. Les graphiques d'évolution révèlent un comportement d'apprentissage sain et typique d'un modèle bien configuré.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys8yh6vk3nqm00wy5cf1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fys8yh6vk3nqm00wy5cf1.png" alt=" " width="800" height="333"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Évolution de la Perte&lt;/strong&gt; : La &lt;strong&gt;courbe de loss montre&lt;/strong&gt; une décroissance rapide et régulière depuis des valeurs initiales élevées (≈1.4) vers une stabilisation autour de 0.25 pour l'entraînement et 0.4 pour la validation. Cette convergence rapide durant les 5 premières époques témoigne de l'&lt;strong&gt;efficacité du &lt;a href="https://datascientest.com/transfer-learning" rel="noopener noreferrer"&gt;transfer learning&lt;/a&gt;&lt;/strong&gt; avec MobileNetV2 pré-entraîné sur ImageNet. L'écart modéré entre les courbes train et validation (≈0.15) indique un &lt;strong&gt;niveau de sur-apprentissage acceptable&lt;/strong&gt;, sans divergence critique.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Progression de l'Accuracy&lt;/strong&gt; : L'évolution de la précision confirme l'apprentissage efficace avec une montée rapide de 55% à plus de 85% en quelques époques, puis une stabilisation progressive vers 91% pour l'entraînement et 87% pour la validation. Cette convergence démontre que le modèle a atteint sa capacité d'apprentissage optimale avec la configuration actuelle (encoder gelé). L'écart final de 4% entre train et validation reste dans une &lt;strong&gt;fourchette acceptable pour un modèle de production&lt;/strong&gt;, suggérant une &lt;strong&gt;bonne généralisation&lt;/strong&gt; sur des données non vues.&lt;/p&gt;

&lt;p&gt;Cette dynamique d'entraînement valide notre approche conservative avec &lt;strong&gt;encoder gelé&lt;/strong&gt;, offrant un modèle stable et performant en un temps d'entraînement réduit, parfaitement adapté aux contraintes de développement rapide d'un système embarqué.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.5 Évaluation et Métriques
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.5.1 Métriques de Performance
&lt;/h4&gt;

&lt;p&gt;L'évaluation de modèles de segmentation nécessite des métriques spécialisées. Nous utilisons principalement :&lt;/p&gt;

&lt;h5&gt;
  
  
  Intersection over Union (IoU)
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;Mesure le &lt;strong&gt;chevauchement entre la prédiction et la vérité terrain&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;IoU = Intersection / Union
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Cette métrique est particulièrement pertinente car elle pénalise à la fois les faux positifs et les faux négatifs.&lt;/p&gt;

&lt;h5&gt;
  
  
  Mean IoU (mIoU)
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Moyenne des IoU de toutes les classes&lt;/strong&gt;, offrant une vue d'ensemble des performances.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h5&gt;
  
  
  Précision Pixel-wise
&lt;/h5&gt;

&lt;blockquote&gt;
&lt;p&gt;Pourcentage de pixels correctement classifiés, métrique intuitive mais pouvant être biaisée par les classes majoritaires.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  1.5.2 Résultats de la Configuration Baseline
&lt;/h4&gt;

&lt;p&gt;Notre modèle baseline atteint des performances encourageantes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Mean IoU&lt;/strong&gt; : 63.25%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Précision globale&lt;/strong&gt; : 87.95%&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perte finale&lt;/strong&gt; : 0.4123&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Analyse par Classe :
&lt;/h5&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Classe&lt;/th&gt;
&lt;th&gt;IoU&lt;/th&gt;
&lt;th&gt;Commentaire&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;flat&lt;/td&gt;
&lt;td&gt;0.9084&lt;/td&gt;
&lt;td&gt;🟢 Excellent (routes bien détectées)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;human&lt;/td&gt;
&lt;td&gt;0.3196&lt;/td&gt;
&lt;td&gt;🔴 Difficile (objets petits/variables)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;vehicle&lt;/td&gt;
&lt;td&gt;0.7469&lt;/td&gt;
&lt;td&gt;🔵 Bon (formes caractéristiques)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;construction&lt;/td&gt;
&lt;td&gt;0.7454&lt;/td&gt;
&lt;td&gt;🔵 Bon (structures larges)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;object&lt;/td&gt;
&lt;td&gt;0.0648&lt;/td&gt;
&lt;td&gt;🔴 Très difficile (objets fins)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;nature&lt;/td&gt;
&lt;td&gt;0.7983&lt;/td&gt;
&lt;td&gt;🔵 Bon (textures distinctives)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sky&lt;/td&gt;
&lt;td&gt;0.8339&lt;/td&gt;
&lt;td&gt;🟢 Excellent (région homogène)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;void&lt;/td&gt;
&lt;td&gt;0.6425&lt;/td&gt;
&lt;td&gt;🟠 Acceptable&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h5&gt;
  
  
  Matrice de confusion
&lt;/h5&gt;

&lt;p&gt;La &lt;a href="https://fr.wikipedia.org/wiki/Matrice_de_confusion" rel="noopener noreferrer"&gt;matrice de confusion&lt;/a&gt; constitue un outil d'évaluation pour les modèles de classification, particulièrement crucial en segmentation sémantique où chaque pixel doit être correctement assigné à sa classe.&lt;/p&gt;

&lt;p&gt;Dans le contexte de la classification et de la segmentation sémantique, chaque prédiction peut être catégorisée selon quatre types fondamentaux qui déterminent la qualité du modèle :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Vrai positif (VP)&lt;/strong&gt; : Le modèle détecte correctement la présence d'une classe là où elle existe réellement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Vrai négatif (VN)&lt;/strong&gt; : Le modèle rejette correctement une classe là où elle n'existe pas
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faux positif (FP)&lt;/strong&gt; : Le modèle génère une fausse alerte en détectant une classe absente (surestimation)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Faux négatif (FN)&lt;/strong&gt; : Le modèle manque une classe présente, échouant à la détecter (sous-estimation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour un système de vision automobile, cette analyse est importante car elle révèle &lt;strong&gt;quelles confusions pourraient compromettre la sécurité&lt;/strong&gt; (ex: confondre un piéton avec un objet statique).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvd29qfaqdh1b7g4ty6cq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvd29qfaqdh1b7g4ty6cq.png" alt=" " width="800" height="723"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  1.5.3 Analyse des Performances
&lt;/h4&gt;

&lt;h5&gt;
  
  
  Points Forts :
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Excellente détection des surfaces planes (routes, ciel)&lt;/li&gt;
&lt;li&gt;Bonne segmentation des grandes structures (bâtiments, végétation)&lt;/li&gt;
&lt;/ul&gt;

&lt;h5&gt;
  
  
  Points d'Amélioration :
&lt;/h5&gt;

&lt;ul&gt;
&lt;li&gt;Détection des objets fins (poteaux, panneaux) perfectible&lt;/li&gt;
&lt;li&gt;Segmentation des humains variable (due à leur taille et variabilité)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Besoin d'optimisation pour les petits objets&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  1.6 Pipeline de Prédiction
&lt;/h3&gt;

&lt;p&gt;Pour valider les performances de notre modèle en conditions réelles, nous avons développé un &lt;strong&gt;pipeline de prédiction complet&lt;/strong&gt; permettant de traiter aussi bien des &lt;strong&gt;images du jeu de données de test&lt;/strong&gt; que des &lt;strong&gt;images externes&lt;/strong&gt;. Ce pipeline intègre toutes les étapes nécessaires depuis le &lt;strong&gt;chargement du modèle jusqu'à l'analyse statistique des résultats&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;predict_single_image&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;image_array&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;)):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Réalise une prédiction complète avec préprocessing et post-analyse&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Chargement et préprocessing adaptatif
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;image_path&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;image_pil&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;RGB&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;image_array&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_pil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Pipeline de normalisation identique à l'entraînement
&lt;/span&gt;    &lt;span class="n"&gt;image_resized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;image&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;resize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_array&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;img_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;method&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;bilinear&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;image_normalized&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cast&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_resized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;float32&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="mf"&gt;255.0&lt;/span&gt;
    &lt;span class="n"&gt;image_batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;expand_dims&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_normalized&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Prédiction et conversion en masque de classes
&lt;/span&gt;    &lt;span class="n"&gt;predictions&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;predict&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;image_batch&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;verbose&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;pred_mask&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;argmax&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;axis&lt;/span&gt;&lt;span class="o"&gt;=-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;numpy&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Analyse statistique automatique par classe
&lt;/span&gt;    &lt;span class="n"&gt;unique_classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;unique&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pred_mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;return_counts&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;total_pixels&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pred_mask&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;

    &lt;span class="n"&gt;class_stats&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;zip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unique_classes&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;counts&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="n"&gt;class_name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;group_names&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="n"&gt;percentage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="n"&gt;total_pixels&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;
        &lt;span class="n"&gt;class_stats&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;class_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_id&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;class_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;class_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;pixel_count&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;percentage&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;percentage&lt;/span&gt;
        &lt;span class="p"&gt;})&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;prediction_mask&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;pred_mask&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;class_statistics&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;class_stats&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;predictions_raw&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;predictions&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  1.6.1. Résultats de prédiction
&lt;/h4&gt;

&lt;p&gt;Les résultats de prédiction se présentent sous la forme suivante :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Masque de Segmentation (pixels)&lt;/strong&gt; : Le résultat principal est un &lt;strong&gt;masque 224×224&lt;/strong&gt; où chaque pixel contient l'&lt;strong&gt;ID de la classe prédite&lt;/strong&gt; (0-7). Cette représentation permet une analyse spatiale précise de la scène.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distribution Statistique des Classes&lt;/strong&gt; : Pour chaque prédiction, nous générons automatiquement un tableau statistique détaillant la répartition des classes :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="err"&gt;📊&lt;/span&gt; &lt;span class="n"&gt;Classes&lt;/span&gt; &lt;span class="n"&gt;détectées&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
           &lt;span class="n"&gt;flat&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mi"&gt;19536&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;38.9&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Routes et surfaces de circulation
&lt;/span&gt;   &lt;span class="n"&gt;construction&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;    &lt;span class="mi"&gt;14510&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;28.9&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Bâtiments et infrastructures  
&lt;/span&gt;         &lt;span class="n"&gt;nature&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="mi"&gt;8285&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;16.5&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Végétation et terrain naturel
&lt;/span&gt;           &lt;span class="n"&gt;void&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="mi"&gt;5459&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="mf"&gt;10.9&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Zones non classifiées
&lt;/span&gt;        &lt;span class="n"&gt;vehicle&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="mi"&gt;1630&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="mf"&gt;3.2&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Véhicules en circulation
&lt;/span&gt;          &lt;span class="n"&gt;human&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;      &lt;span class="mi"&gt;594&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="mf"&gt;1.2&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Piétons et cyclistes
&lt;/span&gt;            &lt;span class="n"&gt;sky&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mi"&gt;98&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Ciel visible
&lt;/span&gt;         &lt;span class="nb"&gt;object&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;       &lt;span class="mi"&gt;64&lt;/span&gt; &lt;span class="nf"&gt;pixels &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;  &lt;span class="mf"&gt;0.1&lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c1"&gt;# Signalisation et mobilier urbain
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Visualisation Tripartite&lt;/strong&gt; : Notre système génère systématiquement trois vues : l'image originale, la vérité terrain (quand disponible), et la prédiction colorisée selon notre palette de couleurs spécifique au domaine automobile.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cz3f90ag6yxbv17nejy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9cz3f90ag6yxbv17nejy.png" alt=" " width="800" height="275"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4.3 Analyse qualitative des performances
&lt;/h3&gt;

&lt;p&gt;L'évaluation sur des images réelles révèle des &lt;strong&gt;performances encourageantes&lt;/strong&gt; avec des points forts et des axes d'amélioration clairement identifiés :&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Excellente Détection des Structures Dominantes&lt;/strong&gt; : Notre modèle démontre une capacité remarquable à identifier les éléments structurants de la scène urbaine. La segmentation des surfaces planes (routes, trottoirs) atteint 38.9% de couverture dans l'exemple analysé, avec des contours nets et une classification cohérente. Les bâtiments et constructions (28.9%) sont également très bien délimités, ce qui est crucial pour la navigation autonome.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Robustesse sur la végétation et l'environnement&lt;/strong&gt; : La détection de la végétation (16.5%) montre une bonne capacité de généralisation du modèle. Les arbres, buissons et espaces verts sont correctement identifiés malgré leur variabilité de texture et de forme, témoignant de l'&lt;strong&gt;efficacité du transfer learning depuis ImageNet&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Défis sur les objets de petite taille&lt;/strong&gt; : L'analyse révèle des difficultés attendues sur les éléments fins et de petite taille. Les objets de signalisation ne représentent que 0.1% des pixels détectés, ce qui correspond à la fois à leur &lt;strong&gt;faible représentation spatiale réelle&lt;/strong&gt; et aux &lt;strong&gt;limitations du modèle sur ces éléments critiques&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Gestion Intelligente des Zones Ambiguës&lt;/strong&gt; : La catégorie "void" (10.9%) capture efficacement les zones d'incertitude et les éléments non classifiables, évitant les fausses classifications qui pourraient être dangereuses. Cette approche conservative est préférable dans un contexte automobile.&lt;/p&gt;

&lt;p&gt;Cette analyse confirme que notre architecture MobileNetV2-UNet offre un &lt;strong&gt;équilibre optimal&lt;/strong&gt; pour les contraintes d'un système de vision embarqué, avec des performances robustes sur les éléments critiques pour la prise de décision de navigation tout en maintenant une efficacité computationnelle compatible avec les ressources limitées d'un véhicule autonome.&lt;/p&gt;

&lt;h3&gt;
  
  
  1.7 Innovations et optimisations futures
&lt;/h3&gt;

&lt;h4&gt;
  
  
  1.7.1 Pistes d'amélioration identifiées
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Entraînement Progressif&lt;/strong&gt;&lt;br&gt;
Stratégie en deux phases :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Phase 1 : Encoder gelé (configuration actuelle)&lt;/li&gt;
&lt;li&gt;Phase 2 : Fine-tuning avec encoder dégelé et taux d'apprentissage réduit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Augmentation de données avancée&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Simulation de conditions météorologiques (pluie, brouillard)&lt;/li&gt;
&lt;li&gt;Variations d'éclairage plus poussées&lt;/li&gt;
&lt;li&gt;Transformations géométriques adaptées au contexte automobile&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Architecture Hybride&lt;/strong&gt;&lt;br&gt;
Exploration de techniques comme :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://fr.wikipedia.org/wiki/Attention_(apprentissage_automatique)" rel="noopener noreferrer"&gt;Attention mechanisms&lt;/a&gt; pour améliorer la détection des petits objets&lt;/li&gt;
&lt;li&gt;Multi-scale training pour robustesse aux variations d'échelle&lt;/li&gt;
&lt;li&gt;Ensembling de modèles pour améliorer la robustesse&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  1.8 Conclusion de la partie modélisation
&lt;/h3&gt;

&lt;p&gt;Le développement de notre &lt;strong&gt;modèle de segmentation MobileNetV2-UNet&lt;/strong&gt; représente un équilibre réussi entre performance et efficacité computationnelle. Avec un &lt;strong&gt;Mean IoU de 63.25 %&lt;/strong&gt; et une &lt;strong&gt;précision globale de 87.95 %&lt;/strong&gt;, notre modèle "baseline" fournit une base solide pour le système de vision du véhicule autonome.&lt;/p&gt;

&lt;p&gt;L'architecture choisie démontre sa &lt;strong&gt;pertinence pour les contraintes embarquées&lt;/strong&gt;, et les résultats détaillés par classe révèlent des performances cohérentes avec les attentes pour un modèle de première génération. Les pistes d'amélioration identifiées offrent un &lt;strong&gt;roadmap clair pour les développements futurs&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;La mise en place d'un &lt;strong&gt;pipeline MLOps avec &lt;a href="https://mlflow.org/" rel="noopener noreferrer"&gt;MLflow&lt;/a&gt;&lt;/strong&gt; et notre organisation modulaire garantissent la reproductibilité et facilitent l'&lt;strong&gt;itération continue&lt;/strong&gt; sur les performances du modèle.&lt;/p&gt;


&lt;h2&gt;
  
  
  🔮 2. Développement du Backend FastAPI - API de Segmentation Sémantique
&lt;/h2&gt;

&lt;p&gt;Le backend de l'application est une API REST développée avec &lt;a href="https://fastapi.tiangolo.com/" rel="noopener noreferrer"&gt;FastAPI&lt;/a&gt;. Cette API &lt;strong&gt;expose notre modèle de deep learning&lt;/strong&gt; (&lt;strong&gt;MobileNetV2-UNet&lt;/strong&gt;) entraîné pour la &lt;strong&gt;segmentation sémantique d'images urbaines&lt;/strong&gt; du dataset Cityscapes.&lt;/p&gt;
&lt;h3&gt;
  
  
  Architecture technique
&lt;/h3&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app/backend/
├── main.py              # Point d'entrée FastAPI
├── config.py            # Configuration et variables d'environnement
├── models/
│   └── predictor.py     # Logique de prédiction et chargement du modèle
├── routers/
│   └── segmentation.py  # Endpoints de l'API
├── schemas/
│   └── prediction.py    # Modèles Pydantic pour validation
├── utils/
│   └── image_processing.py  # Utilitaires de traitement d'image
└── requirements.txt     # Dépendances Python
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Fonctionnalités principales
&lt;/h3&gt;
&lt;h4&gt;
  
  
  1. Chargement du modèle depuis MLflow
&lt;/h4&gt;

&lt;p&gt;Le modèle est hébergé sur &lt;strong&gt;MLflow&lt;/strong&gt; et chargé dynamiquement au démarrage de l'API :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Modèle&lt;/strong&gt; : &lt;strong&gt;MobileNetV2-UNet&lt;/strong&gt; (format Keras 3.x)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Poids&lt;/strong&gt; : ~25MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classes&lt;/strong&gt; : 8 catégories (flat, human, vehicle, construction, object, nature, sky, void)&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  2. Prédiction avec génération d'artefacts
&lt;/h4&gt;

&lt;p&gt;L'API génère pour chaque prédiction :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Masque de segmentation&lt;/strong&gt; : Classification pixel par pixel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualisations&lt;/strong&gt; : Images côte à côte et superposition&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Statistiques&lt;/strong&gt; : Distribution des classes détectée&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Sauvegarde&lt;/strong&gt; : Artefacts de prédiction sauvegardés dans le dossier &lt;code&gt;/predictions&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Endpoints de l'API
&lt;/h3&gt;
&lt;h4&gt;
  
  
  &lt;code&gt;POST /api/v1/segmentation/predict&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Notre endpoint principal pour la segmentation d'images.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Entrée&lt;/strong&gt; : Image (PNG, JPEG) via &lt;code&gt;multipart/form-data&lt;/code&gt;&lt;br&gt;
&lt;strong&gt;Sortie&lt;/strong&gt; : JSON contenant :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"class_statistics"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"image_size"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="err"&gt;largeur&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;hauteur&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dominant_class"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"flat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dominant_class_percentage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mf"&gt;42.5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"images"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"original"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/png;base64,..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"prediction_mask"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/png;base64,..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"overlay"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/png;base64,..."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"side_by_side"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"data:image/png;base64,..."&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;GET /api/v1/segmentation/health&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Ce endpoint vérifie l'état de santé de l'API.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"status"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"healthy"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model_loaded"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;GET /api/v1/segmentation/model/info&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Ce endpooint renvoie des informations détaillées sur le modèle chargé.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"model_name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MobileNetV2-UNet"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"input_shape"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;224&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"num_classes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"class_names"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"flat"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"human"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"vehicle"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;...&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"tensorflow_version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2.18.0"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;GET /docs&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;&lt;strong&gt;Documentation interactive Swagger UI&lt;/strong&gt; générée automatiquement par FastAPI. Ce endpoint est &lt;strong&gt;très utile pour effectuer des requêtes de tests&lt;/strong&gt; vers notre API, en attendant de développer le frontend.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziizv5ilqrss61f8tx37.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fziizv5ilqrss61f8tx37.png" alt=" " width="800" height="699"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Technologies utilisées
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;FastAPI&lt;/strong&gt; : Framework web asynchrone haute performance&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TensorFlow 2.18&lt;/strong&gt; (CPU) : Inférence du modèle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Gunicorn + Uvicorn&lt;/strong&gt; : Serveur ASGI pour la production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pillow&lt;/strong&gt; : Manipulation d'images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MLflow&lt;/strong&gt; : Gestion et versioning du modèle&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Optimisations pour la production
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;TensorFlow CPU&lt;/strong&gt; : Version allégée sans GPU (250MB vs 500MB)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workers limités&lt;/strong&gt; : 1 worker pour économiser la RAM&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Timeout ajusté&lt;/strong&gt; : 120s pour les prédictions complexes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stockage temporaire&lt;/strong&gt; : Utilisation de &lt;code&gt;/tmp&lt;/code&gt; sur Railway&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Déploiement sur Railway
&lt;/h3&gt;

&lt;p&gt;Notre backend FastAPI est déployée sur &lt;a href="https://railway.com/" rel="noopener noreferrer"&gt;Railway&lt;/a&gt; qui offre des ressources suffisante pour déployer un modèle de segmentation d'image, &lt;strong&gt;gratuitement&lt;/strong&gt;. &lt;/p&gt;

&lt;h4&gt;
  
  
  Configuration Railway
&lt;/h4&gt;

&lt;p&gt;Le déploiement sur Railway utilise un fichier &lt;code&gt;railway.json&lt;/code&gt; :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"$schema"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://railway.app/railway.schema.json"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"build"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"builder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"NIXPACKS"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"buildCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"pip install -r requirements.txt"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deploy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"startCommand"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"uvicorn main:app --host 0.0.0.0 --port $PORT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"restartPolicyType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ON_FAILURE"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"restartPolicyMaxRetries"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Variables d'environnement
&lt;/h4&gt;

&lt;p&gt;Les "credentials" sont configurés via le &lt;strong&gt;dashboard Railway&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MLFLOW_TRACKING_URI&lt;/code&gt; : URL du serveur MLflow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; / &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; : Accès S3 pour MLflow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RUN_ID&lt;/code&gt; : Identifiant de l'expérience MLflow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PORT&lt;/code&gt; : Port d'écoute (géré automatiquement)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;FRONTEND_URL&lt;/code&gt; : URL de l'interface frontend (pour éviter les erreurs CORS)&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Processus de déploiement
&lt;/h4&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Initialisation&lt;/strong&gt; : &lt;code&gt;railway init&lt;/code&gt; pour créer le projet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; : Ajout des variables via le dashboard&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement&lt;/strong&gt; : &lt;code&gt;railway up&lt;/code&gt; pour déployer le code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Domaine&lt;/strong&gt; : &lt;code&gt;railway domain&lt;/code&gt; pour générer l'URL publique&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  URL de production
&lt;/h4&gt;

&lt;p&gt;L'API est accessible à : &lt;code&gt;https://future-vision-api-*******.up.railway.app&lt;/code&gt; (URL masquée car non protégée par un mécanisme d'authentification)&lt;/p&gt;

&lt;p&gt;Cette architecture permet un déploiement rapide et scalable d'un modèle de deep learning, avec une API REST moderne et bien documentée, idéale pour être consommée par une application frontend.&lt;/p&gt;




&lt;h2&gt;
  
  
  ⚡ 3. Développement de l'interface frontend Next.js
&lt;/h2&gt;

&lt;h3&gt;
  
  
  3.1 Architecture et choix techniques
&lt;/h3&gt;

&lt;p&gt;L'interface utilisateur a été développée avec &lt;a href="https://nextjs.org/docs" rel="noopener noreferrer"&gt;Next.js 15.3&lt;/a&gt; en JavaScript, privilégiant la simplicité et la performance. Le framework &lt;a href="https://fr.react.dev/" rel="noopener noreferrer"&gt;React&lt;/a&gt; permet de développer une interface adaptée aux besoins de &lt;strong&gt;visualisation des résultats de segmentation&lt;/strong&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stack technique
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Next.js 15.3&lt;/strong&gt; : &lt;strong&gt;Framework React&lt;/strong&gt; pour le développement frontend&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bootstrap 5.3&lt;/strong&gt; : &lt;strong&gt;Framework CSS&lt;/strong&gt; pour un design responsive et professionnel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fetch API&lt;/strong&gt; : Communication avec l'&lt;strong&gt;API FastAPI de prédiction&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Base64&lt;/strong&gt; : Gestion des &lt;strong&gt;images encodées&lt;/strong&gt; retournées par l'API&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.2 Fonctionnalités principales
&lt;/h3&gt;

&lt;p&gt;L'application propose une interface intuitive pour tester le modèle de segmentation sémantique :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Upload d'images&lt;/strong&gt; : Sélection et prévisualisation des images (formats JPEG, PNG, GIF)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validation&lt;/strong&gt; : Contrôle de la taille maximale (4096x4096px) et du format&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Prédiction en temps réel&lt;/strong&gt; : Appel à l'API avec feedback visuel de progression&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualisation multi-format&lt;/strong&gt; :

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image avec overlay&lt;/strong&gt; de segmentation semi-transparent&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Comparaison côte à côte&lt;/strong&gt; (originale vs prédiction)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Masque de segmentation&lt;/strong&gt; isolé&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;

&lt;strong&gt;Statistiques détaillées&lt;/strong&gt; : Distribution des classes, classe dominante, métadonnées&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.3 Interface utilisateur
&lt;/h3&gt;

&lt;p&gt;L'interface suit les principes de design UX/UI pour une utilisation professionnelle :&lt;/p&gt;

&lt;h4&gt;
  
  
  État initial
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Formulaire d'upload central avec instructions claires&lt;/li&gt;
&lt;li&gt;Validation en temps réel du fichier sélectionné&lt;/li&gt;
&lt;li&gt;Boutons d'action désactivés tant qu'aucune image n'est sélectionnée&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvgiku933efuxlrbw8sh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbvgiku933efuxlrbw8sh.png" alt=" " width="800" height="736"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Résultats de prédiction
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Affichage principal de l'image avec overlay de segmentation&lt;/li&gt;
&lt;li&gt;Panneau latéral avec statistiques et distribution des classes&lt;/li&gt;
&lt;li&gt;Section de comparaison détaillée avec visualisations multiples&lt;/li&gt;
&lt;li&gt;Design responsive adapté aux différentes tailles d'écran&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvsj0tgh5pl8johyljgk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjvsj0tgh5pl8johyljgk.png" alt=" " width="800" height="1119"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3.4 Déploiement et Accessibilité
&lt;/h3&gt;

&lt;p&gt;L'application est déployée sur &lt;a href="https://vercel.com/docs" rel="noopener noreferrer"&gt;Vercel&lt;/a&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;URL de production&lt;/strong&gt; : &lt;a href="https://oc-ai-engineer-p08-*******.vercel.app/" rel="noopener noreferrer"&gt;https://oc-ai-engineer-p08-*******.vercel.app/&lt;/a&gt; (URL masquée car non protégée par un mécanisme d'authentification)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement automatique&lt;/strong&gt; : Intégration continue depuis le repository Git&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration&lt;/strong&gt; : Variables d'environnement pour l'URL de l'API backend

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;NEXT_PUBLIC_API_URL&lt;/code&gt; : URL de l'API REST de prédiction&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;h3&gt;
  
  
  3.5 Intégration API
&lt;/h3&gt;

&lt;p&gt;L'interface communique avec l'&lt;strong&gt;API FastAPI&lt;/strong&gt; de ségmentation sémantique d'images via des &lt;strong&gt;requêtes HTTP&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Endpoint&lt;/strong&gt; : &lt;code&gt;POST /predict&lt;/code&gt; pour l'analyse d'images&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Format&lt;/strong&gt; : Multipart/form-data pour l'upload de fichiers&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Réponse&lt;/strong&gt; : JSON contenant les images encodées et statistiques&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette architecture &lt;strong&gt;facilite la maintenance&lt;/strong&gt; et permet une &lt;strong&gt;évolution future&lt;/strong&gt; vers des fonctionnalités avancées comme la gestion de lots d'images ou l'historique des prédictions.&lt;/p&gt;




&lt;h2&gt;
  
  
  📋 Conclusion
&lt;/h2&gt;

&lt;p&gt;Ce projet de développement d'un &lt;strong&gt;système de segmentation d'images pour véhicule autonome&lt;/strong&gt; a permis de concevoir une &lt;strong&gt;solution complète&lt;/strong&gt;, de la &lt;strong&gt;modélisation&lt;/strong&gt; au &lt;strong&gt;déploiement en production&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Réalisations techniques
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Modélisation IA&lt;/strong&gt; : Nous avons développé un modèle &lt;strong&gt;MobileNetV2-UNet&lt;/strong&gt; atteignant &lt;strong&gt;63.25% de Mean IoU&lt;/strong&gt; sur 8 catégories d'objets urbains. L'architecture hybride combine l'&lt;strong&gt;efficacité de MobileNetV2&lt;/strong&gt; pour les contraintes embarquées avec la &lt;strong&gt;précision de U-Net&lt;/strong&gt; pour la reconstruction spatiale.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pipeline MLOps&lt;/strong&gt; : L'intégration de &lt;strong&gt;MLflow&lt;/strong&gt; a permis un &lt;strong&gt;suivi rigoureux des expériences&lt;/strong&gt; et le versioning des modèles, garantissant la reproductibilité et la traçabilité des développements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Architecture API&lt;/strong&gt; : Le &lt;strong&gt;backend FastAPI expose le modèle via une API REST moderne&lt;/strong&gt; avec &lt;strong&gt;génération automatique de visualisations&lt;/strong&gt; et &lt;strong&gt;statistiques détaillées&lt;/strong&gt;, optimisée pour un déploiement efficient.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Interface Utilisateur&lt;/strong&gt; : L'application &lt;strong&gt;Next.js&lt;/strong&gt; offre une &lt;strong&gt;interface intuitive&lt;/strong&gt; pour tester le modèle avec visualisations multi-formats (overlay, comparaison, masques) et facilement déployée sur Vercel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Axes d'Amélioration
&lt;/h3&gt;

&lt;p&gt;Les principales pistes d'optimisation incluent un &lt;strong&gt;entraînement progressif&lt;/strong&gt; (encoder dégelé en phase 2), une &lt;strong&gt;augmentation de données avancée&lt;/strong&gt; simulant conditions météorologiques et variations d'éclairage, l'intégration d'&lt;strong&gt;attention mechanisms&lt;/strong&gt; pour améliorer la détection des petits objets (panneaux, poteaux). Également, l'ajout d'un &lt;strong&gt;système d'authentification API&lt;/strong&gt;, d'un &lt;strong&gt;cache de prédictions&lt;/strong&gt; et de &lt;strong&gt;métriques de monitoring&lt;/strong&gt; en production compléterait l'industrialisation du système.&lt;/p&gt;

&lt;h3&gt;
  
  
  A propos de ce projet
&lt;/h3&gt;

&lt;p&gt;Ce projet démontre la faisabilité technique d'un &lt;strong&gt;module de segmentation pour Future Vision Transport&lt;/strong&gt;, avec une base solide pour l'évolution vers un &lt;strong&gt;système de production robuste&lt;/strong&gt;.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>computervision</category>
      <category>python</category>
      <category>openclassrooms</category>
    </item>
    <item>
      <title>💬❤️ Analyse de Sentiments de Tweets grâce au Deep Learning : Une Approche MLOps</title>
      <dc:creator>David Scanu </dc:creator>
      <pubDate>Fri, 11 Apr 2025 19:45:25 +0000</pubDate>
      <link>https://dev.to/davidscanu/analyse-de-sentiments-de-tweets-grace-au-deep-learning-une-approche-mlops-3ib7</link>
      <guid>https://dev.to/davidscanu/analyse-de-sentiments-de-tweets-grace-au-deep-learning-une-approche-mlops-3ib7</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9g3e3jg9j9o56ifjz9af.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9g3e3jg9j9o56ifjz9af.png" alt="People tweeting" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Cet article a été rédigé dans le cadre du projet : Réalisez une analyse de sentiments grâce au Deep Learning du parcours &lt;a href="https://openclassrooms.com/fr/paths/795-ai-engineer" rel="noopener noreferrer"&gt;AI Engineer&lt;/a&gt; d'&lt;a href="https://openclassrooms.com/f" rel="noopener noreferrer"&gt;OpenClassrooms&lt;/a&gt;. Les données utilisées sont issues du jeu de données open source &lt;a href="https://www.kaggle.com/datasets/kazanova/sentiment140" rel="noopener noreferrer"&gt;Sentiment140&lt;/a&gt;. Le code source complet est disponible sur &lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;🎓 OpenClassrooms • Parcours &lt;a href="https://openclassrooms.com/fr/paths/795-ai-engineer" rel="noopener noreferrer"&gt;AI Engineer&lt;/a&gt; | 👋 &lt;em&gt;Étudiant&lt;/em&gt; : &lt;a href="https://www.linkedin.com/in/davidscanu14/" rel="noopener noreferrer"&gt;David Scanu&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslbftyfpuhwkis2qr5w4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fslbftyfpuhwkis2qr5w4.png" alt="Application De prédiction de tweet d'Air Paradis" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  🌐 Contexte et problématique métier
&lt;/h2&gt;

&lt;p&gt;Dans le cadre de ma formation d'&lt;a href="https://openclassrooms.com/fr/paths/795-ai-engineer" rel="noopener noreferrer"&gt;AI Engineer&lt;/a&gt; chez &lt;a href="https://openclassrooms.com/fr/" rel="noopener noreferrer"&gt;OpenClassrooms&lt;/a&gt;, ce projet s'inscrit dans un scénario professionnel où j'interviens en tant qu'ingénieur IA chez MIC (Marketing Intelligence Consulting), entreprise de conseil spécialisée en marketing digital.&lt;/p&gt;

&lt;p&gt;Notre client, &lt;strong&gt;✈️ Air Paradis&lt;/strong&gt; (compagnie aérienne), souhaite &lt;strong&gt;anticiper les bad buzz sur les réseaux sociaux&lt;/strong&gt;. La mission consiste à développer un produit IA permettant de prédire le sentiment associé à un tweet, afin d'améliorer la gestion de sa réputation en ligne.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚡ Mission
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Développer un modèle d'IA permettant de prédire le sentiment associé à un tweet.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Créer un prototype fonctionnel d'un modèle d'analyse de sentiments pour tweets selon trois approches différentes :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modèle sur mesure simple&lt;/strong&gt; : Approche classique (régression logistique) pour une prédiction rapide&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modèle sur mesure avancé&lt;/strong&gt; : Utilisation de réseaux de neurones profonds avec différents word embeddings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modèle avancé BERT&lt;/strong&gt; : Exploration de l'apport en performance d'un modèle BERT&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette mission implique également la mise en œuvre d'une &lt;strong&gt;démarche MLOps complète&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilisation de &lt;strong&gt;MLFlow pour le tracking des expérimentations et le stockage des modèles&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Création d'un &lt;strong&gt;pipeline de déploiement continu&lt;/strong&gt; (Git + Github + plateforme Cloud).&lt;/li&gt;
&lt;li&gt;Intégration de &lt;strong&gt;tests unitaires automatisés&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;Mise en place d'un &lt;strong&gt;suivi de performance en production&lt;/strong&gt; via Azure A&lt;a href="https://learn.microsoft.com/fr-fr/azure/azure-monitor/app/app-insights-overview" rel="noopener noreferrer"&gt;pplication Insight&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🔧 Technologies utilisées
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Langages&lt;/strong&gt; : Python&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bibliothèques ML/DL&lt;/strong&gt; : Scikit-learn, TensorFlow/Keras, Transformers (BERT)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;MLOps&lt;/strong&gt; : MLFlow, Git, GitHub Actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt; : FastAPI, Heroku&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frontend&lt;/strong&gt; : Next.js / React&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; : Azure Application Insight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traitement texte&lt;/strong&gt; : NLTK, Word Embeddings&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏛️ Structure du projet
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;📦 oc-ai-engineer-p07-analyse-sentiments-deep-learning/
┣━━ 📂 app/
┃   ┣━━ 📂 fastapi/                         # Backend API de prédiction
┃   ┗━━ 📂 frontend/                        # Application Next.js
┃
┣━━ 📂 documentation/                       # Documentation du projet
┃   ┗━━ 📃 guide-app-insights.md            # Guide de suivi des feedback utilisateur et des alertes avec Azure Application insights
┃
┗━━ 📂 notebooks/                           # Notebooks Jupyter pour l'analyse et modèles
    ┣━━ 📝 01_Analyse_exploratoire.ipynb     # Exploration et visualisation des données
    ┣━━ 📝 02_Modele_simple.ipynb            # Bag of Words et classificateurs classiques
    ┣━━ 📝 03_Modele_avance_Word2Vec.ipynb   # LSTM avec Word2Vec
    ┗━━ 📝 04_Modele_BERT.ipynb              # DistilBERT pour analyse de sentiment
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  📔 Notebooks du projet
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/notebooks/scanu-david-01-notebook-analyse-exploratoire-20250306.ipynb" rel="noopener noreferrer"&gt;📊 Notebook 1 : Analyse exploratoire des données&lt;/a&gt; - Exploration du dataset Sentiment140 et visualisations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/notebooks/scanu-david-02-notebook-modele-simple-20250306.ipynb" rel="noopener noreferrer"&gt;🔍 Notebook 2 : Modèle classique (TF-IDF + Regression Logistique)&lt;/a&gt; - Implémentation de l'approche "sur mesure simple"&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/notebooks/scanu-david-03-notebook-modele-avance-20250306.ipynb" rel="noopener noreferrer"&gt;🧠 Notebook 3 : Modèle avancé (Word2Vec + LSTM)&lt;/a&gt; - Réseau de neurones avec word embeddings&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://colab.research.google.com/drive/1TFq3selzmDCTReGfa2NvvlaNSRZMhdzY?usp=sharing" rel="noopener noreferrer"&gt;🚀 Notebook 4 : Modèle BERT pour l'analyse de sentiment&lt;/a&gt; - Fine-tuning de DistilBERT (Google Colab)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🧭 Guides
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/app/fastapi/README.md" rel="noopener noreferrer"&gt;Guide d'utilisation de l'API FastAPI&lt;/a&gt; : API FastAPI qui expose un modèle de deep learning pour l'analyse de sentiment&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/app/frontend/README.md" rel="noopener noreferrer"&gt;Guide d'utilisation du frontend Next.JS&lt;/a&gt; : Application Next.js avec Bootstrap pour l'interface utilisateur&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/DavidScanu/oc-ai-engineer-p07-analyse-sentiments-deep-learning/blob/main/documentation/guide-app-insights.md" rel="noopener noreferrer"&gt;Guide de Monitoring pour Air Paradis&lt;/a&gt; : Mise en place du feedback utilisateur et des alertes avec Azure Application insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  📑 Méthodologie et données
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Le jeu de données Sentiment140
&lt;/h3&gt;

&lt;p&gt;Pour ce projet, nous avons utilisé le jeu de données open source Sentiment140, qui contient 1,6 million de tweets annotés selon leur polarité (négative ou positive). Ce dataset comprend six champs principaux :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;target&lt;/strong&gt; : la polarité du tweet (0 = négatif, 4 = positif)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ids&lt;/strong&gt; : l'identifiant du tweet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;date&lt;/strong&gt; : la date du tweet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;flag&lt;/strong&gt; : une requête éventuelle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;user&lt;/strong&gt; : l'utilisateur ayant posté le tweet&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;text&lt;/strong&gt; : le contenu textuel du tweet&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Nous avons choisi ce jeu de données pour sa taille conséquente et sa pertinence vis-à-vis de notre objectif d'analyse de sentiments sur Twitter. Sa structure binaire (positif/négatif) correspond parfaitement à notre besoin de détecter les opinions négatives pouvant potentiellement nuire à l'image d'Air Paradis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Analyse exploratoire des données Sentiment140
&lt;/h3&gt;

&lt;p&gt;Notre analyse exploratoire a révélé des caractéristiques distinctives importantes entre les tweets positifs et négatifs :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Les tweets positifs contiennent &lt;strong&gt;93% plus d'URLs&lt;/strong&gt; que les négatifs&lt;/li&gt;
&lt;li&gt;Les tweets positifs contiennent &lt;strong&gt;48% plus de mentions (@)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Les tweets positifs utilisent &lt;strong&gt;39% plus de hashtags (#)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Les tweets positifs utilisent &lt;strong&gt;39% plus de points d'exclamation (!)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Les tweets négatifs contiennent &lt;strong&gt;24% plus d'ellipses (...)&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Les tweets négatifs sont légèrement plus longs et contiennent plus de mots&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette analyse nous a permis de mieux comprendre les spécificités du langage sur Twitter et d'identifier des éléments discriminants entre sentiments positifs et négatifs. Ces observations ont directement influencé notre stratégie de prétraitement et la conception de nos modèles.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prétraitement des données textuelles
&lt;/h3&gt;

&lt;p&gt;En nous basant sur l'analyse exploratoire, nous avons développé une fonction de prétraitement spécifique pour les tweets :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;preprocess_tweet&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Prétraite un tweet en appliquant plusieurs transformations :
    - Conversion en minuscules
    - Remplacement des URLs, mentions et hashtags par des tokens spéciaux
    - Suppression des caractères spéciaux
    - Tokenisation et lemmatisation
    - Suppression des stopwords
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="c1"&gt;# Vérifier si le tweet est une chaîne de caractères
&lt;/span&gt;    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nf"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;""&lt;/span&gt;

    &lt;span class="c1"&gt;# Convertir en minuscules
&lt;/span&gt;    &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lower&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="c1"&gt;# Remplacer les URLs par un token spécial
&lt;/span&gt;    &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;https?://\S+|www\.\S+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;URL&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Remplacer les mentions par un token spécial
&lt;/span&gt;    &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;@\w+&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;MENTION&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Traiter les hashtags (conserver le # comme token séparé et le mot qui suit)
&lt;/span&gt;    &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;#(\w+)&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;# \1&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Supprimer les caractères spéciaux et les nombres, mais garder les tokens spéciaux
&lt;/span&gt;    &lt;span class="n"&gt;tweet&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;[^\w\s&amp;lt;&amp;gt;@#!?]&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;''&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Tokenisation
&lt;/span&gt;    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;word_tokenize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tweet&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Lemmatisation
&lt;/span&gt;    &lt;span class="n"&gt;lemmatizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;WordNetLemmatizer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;lemmatizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;lemmatize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Supprimer les stopwords, mais conserver les négations importantes
&lt;/span&gt;    &lt;span class="n"&gt;stop_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stopwords&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;words&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;english&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="n"&gt;important_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;no&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;not&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nor&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;neither&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;never&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nobody&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nothing&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;nowhere&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;stop_words&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;stop_words&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;important_words&lt;/span&gt;
    &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;tokens&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;stop_words&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

    &lt;span class="c1"&gt;# Rejoindre les tokens en une chaîne
&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt; &lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tokens&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notre stratégie de prétraitement s'est concentrée sur trois aspects clés :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Traitement des éléments spéciaux&lt;/strong&gt; : Plutôt que de simplement supprimer les URLs, mentions et hashtags, nous les avons remplacés par des tokens spéciaux (&lt;code&gt;&amp;lt;URL&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;MENTION&amp;gt;&lt;/code&gt;) afin de préserver l'information de leur présence, tout en séparant les hashtags pour conserver leur contenu sémantique.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Conservation des négations&lt;/strong&gt; : Nous avons exclu les mots de négation de la liste des stopwords pour préserver le sens du sentiment exprimé.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lemmatisation plutôt que stemming&lt;/strong&gt; : Après avoir testé les deux approches, nous avons privilégié la lemmatisation qui préserve mieux le sens des mots tout en réduisant la dimensionnalité du vocabulaire.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  🧠 Approches de modélisation
&lt;/h2&gt;

&lt;p&gt;Pour répondre à la demande d'Air Paradis, nous avons développé et comparé trois approches de modélisation distinctes, de la plus simple à la plus avancée.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modèle sur mesure simple (approche classique)
&lt;/h3&gt;

&lt;p&gt;Notre première approche s'est appuyée sur des techniques classiques de machine learning, combinant une &lt;strong&gt;vectorisation&lt;/strong&gt; des tweets avec des &lt;strong&gt;algorithmes de classification&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Nous avons d'abord exploré &lt;strong&gt;deux méthodes de représentation vectorielle de texte&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bag of Words&lt;/strong&gt; : transformation des tweets en vecteurs numériques basés sur la fréquence d'apparition de chaque mot&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;TF-IDF&lt;/strong&gt; : pondération des mots selon leur importance relative dans le tweet et leur rareté dans l'ensemble du corpus&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pour la phase de classification, nous avons testé &lt;strong&gt;quatre algorithmes différents&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Régression Logistique&lt;/strong&gt; : modèle linéaire adapté aux problèmes de classification binaire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SVM Linéaire&lt;/strong&gt; : recherche d'un hyperplan optimal séparant les sentiments positifs et négatifs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Random Forest&lt;/strong&gt; : ensemble d'arbres de décision offrant robustesse et réduction du surapprentissage&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Naive Bayes&lt;/strong&gt; : classifieur probabiliste particulièrement adapté aux données textuelles&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Après optimisation des hyperparamètres via validation croisée, le &lt;strong&gt;SVM Linéaire combiné au Bag of Words&lt;/strong&gt; s'est révélé être la solution la plus performante avec les hyperparamètres suivants :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Coefficient de régularisation  :&lt;strong&gt;C=0.01&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Configuration  :&lt;strong&gt;dual=True&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;Nombre maximal d'itérations : &lt;strong&gt;max_iter=1000&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les métriques d'évaluation confirment l'efficacité de ce modèle :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;F1 Score&lt;/strong&gt; : 0.785 (équilibre entre précision et rappel)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;F2 Score&lt;/strong&gt; : 0.798 (privilégiant le rappel pour minimiser les faux négatifs)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ROC AUC&lt;/strong&gt; : 0.852 (bonne capacité discriminative)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Précision globale&lt;/strong&gt; : 79,8% sur notre jeu de test&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette approche, malgré sa relative simplicité, fournit déjà une &lt;strong&gt;base solide pour la détection des sentiments négatifs dans les tweets concernant Air Paradis&lt;/strong&gt;. Elle constitue une référence précieuse pour évaluer les gains potentiels des modèles plus sophistiqués que nous avons développés par la suite.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modèle sur mesure avancé (réseaux de neurones avec word embeddings)
&lt;/h3&gt;

&lt;p&gt;Pour notre deuxième approche, nous avons exploré les techniques de deep learning avec des embeddings de mots et des réseaux de neurones récurrents. Nous avons d'abord optimisé notre environnement pour utiliser efficacement le GPU disponible (GTX 1060 3GB) :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Optimisations matérielles&lt;/strong&gt; :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Désactivation du recurrent_dropout pour permettre l'utilisation de CuDNNLSTM optimisé&lt;/li&gt;
&lt;li&gt;Activation de XLA (Accelerated Linear Algebra) pour optimiser les graphes d'opérations&lt;/li&gt;
&lt;li&gt;Utilisation de la précision mixte (float16/float32)&lt;/li&gt;
&lt;li&gt;Augmentation de la taille du batch à 256 pour exploiter le parallélisme&lt;/li&gt;
&lt;li&gt;Optimisation du pipeline de données avec tf.data.Dataset et prefetch&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Word Embeddings&lt;/strong&gt; : nous avons comparé deux techniques d'embeddings pour représenter les mots dans un espace vectoriel dense :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Word2Vec pré-entraîné sur un large corpus de tweets&lt;/li&gt;
&lt;li&gt;GloVe (Global Vectors for Word Representation)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Architecture du réseau&lt;/strong&gt; : nous avons implémenté un réseau de neurones bidirectionnel avec plusieurs couches LSTM et des mécanismes de régularisation :&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;create_optimized_lstm_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;embedding_matrix&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;max_seq_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;MAX_SEQUENCE_LENGTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;vocab_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;embedding_dim&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;embedding_matrix&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;

    &lt;span class="c1"&gt;# Entrée du modèle
&lt;/span&gt;    &lt;span class="n"&gt;input_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Input&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;max_seq_length&lt;/span&gt;&lt;span class="p"&gt;,))&lt;/span&gt;

    &lt;span class="c1"&gt;# Couche d'embedding avec des poids pré-entraînés
&lt;/span&gt;    &lt;span class="n"&gt;embedding_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Embedding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;input_dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;vocab_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;output_dim&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;embedding_dim&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;weights&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;embedding_matrix&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
        &lt;span class="n"&gt;input_length&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;max_seq_length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;trainable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;trainable&lt;/span&gt;
    &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;input_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Dropout spatial
&lt;/span&gt;    &lt;span class="n"&gt;dropout_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;SpatialDropout1D&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.3&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;embedding_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Couche LSTM bidirectionnelle optimisée pour GPU
&lt;/span&gt;    &lt;span class="n"&gt;lstm_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bidirectional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LSTM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;recurrent_dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# Optimisation GPU
&lt;/span&gt;            &lt;span class="n"&gt;return_sequences&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;dropout_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Deuxième couche LSTM
&lt;/span&gt;    &lt;span class="n"&gt;lstm_layer_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Bidirectional&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;LSTM&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;units&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;recurrent_dropout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.0&lt;/span&gt;  &lt;span class="c1"&gt;# Optimisation GPU
&lt;/span&gt;        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;lstm_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Couche dense avec activation ReLU
&lt;/span&gt;    &lt;span class="n"&gt;dense_1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;64&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;relu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;lstm_layer_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;dropout_2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dropout&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;0.4&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;dense_1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Couche de sortie
&lt;/span&gt;    &lt;span class="n"&gt;output_layer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Dense&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;activation&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sigmoid&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;dropout_2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Créer et compiler le modèle
&lt;/span&gt;    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;input_layer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;output_layer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;compile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;optimizer&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;tf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;keras&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;optimizers&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Adam&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;learning_rate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mf"&gt;0.001&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="n"&gt;loss&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;binary_crossentropy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;accuracy&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;L'architecture de notre modèle LSTM comprend :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Une couche d'embedding initialisée avec les poids pré-entraînés Word2Vec&lt;/li&gt;
&lt;li&gt;Un dropout spatial pour réduire la corrélation entre les features consécutives&lt;/li&gt;
&lt;li&gt;Deux couches LSTM bidirectionnelles (128 puis 64 unités) pour capturer les dépendances contextuelles&lt;/li&gt;
&lt;li&gt;Des couches de dropout pour la régularisation et éviter le surapprentissage&lt;/li&gt;
&lt;li&gt;Une couche dense intermédiaire avec activation ReLU &lt;/li&gt;
&lt;li&gt;Une couche de sortie avec activation sigmoïde pour la classification binaire&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les résultats de l'entraînement montrent une progression constante de l'accuracy, comme on peut le voir sur les graphiques ci-dessous :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48j9lz9bh84os9nkp2bz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F48j9lz9bh84os9nkp2bz.png" alt="Courbe d'apprentissage" width="800" height="329"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cette approche plus sophistiquée nous a permis d'atteindre une précision de 81,8% sur l'ensemble de validation, avec un score de 85,2% sur le jeu d'entraînement, surpassant ainsi le modèle simple.&lt;/p&gt;

&lt;h3&gt;
  
  
  Modèle BERT (approche transformer)
&lt;/h3&gt;

&lt;p&gt;Pour notre troisième approche, nous avons exploré l'état de l'art en NLP en utilisant BERT (Bidirectional Encoder Representations from Transformers) :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Modèle pré-entraîné&lt;/strong&gt; : nous avons utilisé DistilBERT, une version allégée et distillée de BERT, pour réduire les coûts de calcul tout en maintenant des performances élevées&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fine-tuning&lt;/strong&gt; : nous avons affiné le modèle sur notre jeu de données spécifique d'analyse de sentiments&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Pour cette approche, nous avons utilisé le modèle &lt;code&gt;DistilBertForSequenceClassification&lt;/code&gt; de la bibliothèque Hugging Face, qui est spécifiquement conçu pour les tâches de classification de séquences textuelles :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;train_bert_sentiment&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distilbert-base-uncased&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;
    Fonction principale pour l&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;entraînement du modèle DistilBERT sur une tâche d&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;analyse de sentiments.
    &lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;

    &lt;span class="c1"&gt;# Définir les paramètres
&lt;/span&gt;    &lt;span class="n"&gt;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model_name&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;batch_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;learning_rate&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mf"&gt;2e-5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;epochs&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;max_length&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;sample_size&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;sample_size&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;# Charger les données
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Chargement du dataset...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;column_names&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;target&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ids&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;date&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;flag&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;user&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;raw_data&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pd&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;read_csv&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;encoding&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;utf-8&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;names&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;column_names&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Préparer les données
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Préparation des données...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;data_splits&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;prepare_data&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sample_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;sample_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Initialiser le tokenizer et le modèle
&lt;/span&gt;    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Initialisation du modèle DistilBERT...&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;tokenizer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DistilBertTokenizer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DistilBertForSequenceClassification&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;from_pretrained&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;num_labels&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;  &lt;span class="c1"&gt;# Sentiment binaire (0 = négatif, 1 = positif)
&lt;/span&gt;    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Ajustement du batch size selon la mémoire GPU
&lt;/span&gt;    &lt;span class="n"&gt;adjusted_batch_size&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;min&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Création des datasets et des dataloaders
&lt;/span&gt;    &lt;span class="n"&gt;train_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TweetDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;train&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;texts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;train&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;val_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TweetDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;val&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;texts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;val&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;test_dataset&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;TweetDataset&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;texts&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;data_splits&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;test&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;labels&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;train_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;train_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;adjusted_batch_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;shuffle&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;val_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;val_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;adjusted_batch_size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;test_loader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;DataLoader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;test_dataset&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;batch_size&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;adjusted_batch_size&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Détection du device (GPU/CPU)
&lt;/span&gt;    &lt;span class="n"&gt;device&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;device&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cuda&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;torch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;cuda&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;is_available&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;cpu&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Entraînement du modèle avec accumulation de gradients pour optimiser l'utilisation mémoire
&lt;/span&gt;    &lt;span class="n"&gt;gradient_accumulation_steps&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;max&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;16&lt;/span&gt; &lt;span class="o"&gt;//&lt;/span&gt; &lt;span class="n"&gt;adjusted_batch_size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;history&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;train_model&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;train_loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;val_loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;test_loader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;device&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;epochs&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;gradient_accumulation_steps&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;gradient_accumulation_steps&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# Enregistrement du modèle dans MLflow
&lt;/span&gt;    &lt;span class="n"&gt;run_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;log_model_to_mlflow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;params&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;tokenizer&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;tokenizer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;metrics&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;metrics&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;run_id&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;run_id&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;DistilBERT est particulièrement adapté à notre tâche car il :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Utilise une &lt;strong&gt;architecture transformer bidirectionnelle&lt;/strong&gt; pour capturer le contexte dans les deux directions&lt;/li&gt;
&lt;li&gt;A été &lt;strong&gt;pré-entraîné sur un large corpus de textes&lt;/strong&gt;, ce qui lui permet de comprendre les nuances linguistiques&lt;/li&gt;
&lt;li&gt;Est &lt;strong&gt;40% plus léger que BERT&lt;/strong&gt; tout en conservant 97% de ses performances&lt;/li&gt;
&lt;li&gt;S'intègre parfaitement dans un &lt;strong&gt;pipeline MLOps&lt;/strong&gt; grâce à son API standardisée&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Cette approche &lt;strong&gt;transformers&lt;/strong&gt; nous a permis d'atteindre une &lt;strong&gt;précision de 91,3 %&lt;/strong&gt;, démontrant la puissance des &lt;strong&gt;architectures basées sur l'attention&lt;/strong&gt; pour la compréhension du langage naturel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Comparaison des performances des modèles
&lt;/h3&gt;

&lt;p&gt;Voici un récapitulatif des performances obtenues avec nos différentes approches :&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Modèle&lt;/th&gt;
&lt;th&gt;Précision (Accuracy)&lt;/th&gt;
&lt;th&gt;F1-Score&lt;/th&gt;
&lt;th&gt;Temps d'entraînement&lt;/th&gt;
&lt;th&gt;Taille du modèle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Régression Logistique + TF-IDF&lt;/td&gt;
&lt;td&gt;79,8%&lt;/td&gt;
&lt;td&gt;0,797&lt;/td&gt;
&lt;td&gt;~5 minutes&lt;/td&gt;
&lt;td&gt;~15 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSTM + Word2Vec&lt;/td&gt;
&lt;td&gt;85,2%&lt;/td&gt;
&lt;td&gt;0,851&lt;/td&gt;
&lt;td&gt;~2 heures&lt;/td&gt;
&lt;td&gt;~90 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LSTM + GloVe&lt;/td&gt;
&lt;td&gt;84,7%&lt;/td&gt;
&lt;td&gt;0,846&lt;/td&gt;
&lt;td&gt;~2 heures&lt;/td&gt;
&lt;td&gt;~88 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DistilBERT fine-tuné&lt;/td&gt;
&lt;td&gt;91,3%&lt;/td&gt;
&lt;td&gt;0,912&lt;/td&gt;
&lt;td&gt;~4 heures (GPU)&lt;/td&gt;
&lt;td&gt;~250 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Pour le déploiement en production, nous avons retenu le modèle &lt;strong&gt;LSTM avec Word2Vec&lt;/strong&gt;, qui offre le meilleur compromis entre performance et ressources requises. Bien que DistilBERT ait obtenu de meilleurs résultats, sa taille et ses exigences en termes de ressources de calcul le rendaient moins adapté à un déploiement sur une infrastructure Cloud gratuite.&lt;/p&gt;

&lt;h2&gt;
  
  
  ⚙️ Mise en œuvre du MLOps
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Principes du MLOps
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Le MLOps (Machine Learning Operations) est une méthodologie qui vise à standardiser et à automatiser le cycle de vie des modèles de machine learning&lt;/strong&gt;, de leur développement à leur déploiement en production. Pour ce projet, nous avons mis en œuvre plusieurs principes clés du MLOps :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Reproductibilité&lt;/strong&gt; : environnement de développement versionné et documenté&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatisation&lt;/strong&gt; : pipeline de déploiement continu&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; : suivi des performances du modèle en production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Amélioration continue&lt;/strong&gt; : collecte de feedback et réentraînement périodique&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette approche nous a permis de créer une solution robuste et évolutive pour Air Paradis.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tracking des expérimentations avec MLFlow
&lt;/h3&gt;

&lt;p&gt;Pour assurer une gestion efficace des expérimentations, nous avons utilisé &lt;a href="https://mlflow.org/docs/latest/index.html" rel="noopener noreferrer"&gt;MLFlow&lt;/a&gt;, un outil open-source spécialisé dans le &lt;strong&gt;suivi et la gestion des modèles de machine learning&lt;/strong&gt; :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Tracking des métriques&lt;/strong&gt; : pour chaque expérimentation, nous avons enregistré automatiquement les paramètres du modèle, les métriques de performance (accuracy, F1-score, précision, rappel) et les artefacts générés&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Centralisation des modèles&lt;/strong&gt; : tous les modèles entraînés ont été stockés de manière centralisée avec leurs métadonnées&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualisation&lt;/strong&gt; : l'interface utilisateur de MLFlow nous a permis de comparer visuellement les différentes expérimentations&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtvbhmrrjepcj6cj6zw7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fbtvbhmrrjepcj6cj6zw7.png" alt="Serveur MLFLow" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cette approche nous a permis de garder une trace claire de l'évolution de nos modèles et de sélectionner objectivement le plus performant pour le déploiement.&lt;/p&gt;

&lt;h2&gt;
  
  
  💻 Interface utilisateur
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architecture de l'application
&lt;/h3&gt;

&lt;p&gt;Notre solution se compose de deux parties principales :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Backend (FastAPI)&lt;/strong&gt; :

&lt;ul&gt;
&lt;li&gt;API REST exposant le modèle d'analyse de sentiments&lt;/li&gt;
&lt;li&gt;Endpoints pour la prédiction individuelle et par lots&lt;/li&gt;
&lt;li&gt;Système de feedback et de monitoring&lt;/li&gt;
&lt;li&gt;Téléchargement automatique des artefacts du modèle depuis MLFlow&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftelklwg14wd6h1q3jwk1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftelklwg14wd6h1q3jwk1.png" alt="Page /docs du serveur FastAPI" width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Frontend (Next.js)&lt;/strong&gt; :

&lt;ul&gt;
&lt;li&gt;Interface utilisateur intuitive et responsive&lt;/li&gt;
&lt;li&gt;Mode clair/sombre pour le confort visuel&lt;/li&gt;
&lt;li&gt;Visualisation des résultats de prédiction&lt;/li&gt;
&lt;li&gt;Système de collecte de feedback&lt;/li&gt;
&lt;li&gt;Widget d'indication de connexion avec l'API&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9kesxlbg2d6tjod1xce.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp9kesxlbg2d6tjod1xce.png" alt="Mockup macbook de l'application frontend" width="800" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Fonctionnalités de l'interface utilisateur
&lt;/h3&gt;

&lt;p&gt;L'interface utilisateur offre plusieurs fonctionnalités clés pour faciliter l'analyse de sentiments :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyse individuelle&lt;/strong&gt; : prédiction du sentiment d'un tweet unique&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Exemples prédéfinis&lt;/strong&gt; : tweets d'exemple positifs et négatifs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Historique&lt;/strong&gt; : conservation des analyses précédentes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback&lt;/strong&gt; : possibilité de signaler des prédictions incorrectes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette interface a été conçue pour être &lt;strong&gt;intuitive et accessible aux équipes marketing d'Air Paradis&lt;/strong&gt;, sans nécessiter de connaissances techniques approfondies.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔄 Pipeline de déploiement continu
&lt;/h2&gt;

&lt;p&gt;Pour automatiser le déploiement de notre modèle, nous avons mis en place un &lt;strong&gt;pipeline CI/CD (Intégration Continue / Déploiement Continu)&lt;/strong&gt; avec les composants suivants :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Versionnement du code&lt;/strong&gt; : utilisation de Git pour le contrôle de version&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;GitHub Actions&lt;/strong&gt; : automatisation des tests et du déploiement à chaque push sur la branche principale&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement sur Heroku&lt;/strong&gt; : plateforme Cloud pour héberger notre API de prédiction&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tests unitaires automatisés
&lt;/h3&gt;

&lt;p&gt;Pour garantir la fiabilité de notre solution, nous avons implémenté des &lt;strong&gt;tests unitaires automatisés&lt;/strong&gt; couvrant les aspects critiques :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Test du endpoint de santé&lt;/strong&gt; : Vérifie que l'API répond correctement sur &lt;code&gt;/health&lt;/code&gt; avec un code 200 et confirme que le statut retourné est "ok". Le modèle est chargé correctement.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Test du endpoint de prédiction&lt;/strong&gt; : S'assure que l'API traite correctement les requêtes POST sur &lt;code&gt;/predict&lt;/code&gt;, accepte un texte à analyser et renvoie un résultat contenant les champs "sentiment" et "confidence".
&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_health_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/health&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;status&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ok&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;test_predict_endpoint&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/predict&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;text&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;I love flying with this airline!&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status_code&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sentiment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
    &lt;span class="k"&gt;assert&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;confidence&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;result&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  GitHub Actions
&lt;/h3&gt;

&lt;p&gt;Le déploiement est entièrement automatisé grâce à &lt;strong&gt;GitHub Actions&lt;/strong&gt; :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Déclenchement&lt;/strong&gt; : À chaque commit/push sur la branche principale, GitHub Actions lance le workflow.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Tests automatisés&lt;/strong&gt; : Le workflow exécute tous les tests unitaires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement conditionnel&lt;/strong&gt; : Uniquement si les tests réussissent, l'application est déployée automatiquement sur Heroku.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Création du workflow GitHub Actions
&lt;/h4&gt;

&lt;p&gt;Pour la création du workflow GitHub Actions, nous créons un fichier &lt;code&gt;.github/workflows/heroku-deploy.yml&lt;/code&gt; à la racine dont voici le contenu :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Heroku&lt;/span&gt;

&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;branches&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;app/fastapi/**'&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Set up Python&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/setup-python@v2&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;python-version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="s"&gt;3.10'&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install dependencies&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./app/fastapi&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pip install --upgrade pip&lt;/span&gt;
          &lt;span class="s"&gt;pip install -r requirements.txt&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;working-directory&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;./app/fastapi&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;python -m pytest tests/test_api.py -v&lt;/span&gt;
        &lt;span class="na"&gt;env&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;MLFLOW_TRACKING_URI&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.MLFLOW_TRACKING_URI }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_ACCESS_KEY_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.AWS_SECRET_ACCESS_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;RUN_ID&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.RUN_ID }}&lt;/span&gt;
          &lt;span class="na"&gt;APPINSIGHTS_INSTRUMENTATION_KEY&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.APPINSIGHTS_INSTRUMENTATION_KEY }}&lt;/span&gt;

  &lt;span class="na"&gt;deploy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;needs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ubuntu-latest&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v2&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Heroku CLI&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
            &lt;span class="s"&gt;curl https://cli-assets.heroku.com/install.sh | sh&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Deploy to Heroku&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;akhileshns/heroku-deploy@v3.12.12&lt;/span&gt;
        &lt;span class="na"&gt;with&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="na"&gt;heroku_api_key&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEROKU_API_KEY }}&lt;/span&gt;
          &lt;span class="na"&gt;heroku_app_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;air-paradis-sentiment-api"&lt;/span&gt;
          &lt;span class="na"&gt;heroku_email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ secrets.HEROKU_EMAIL }}&lt;/span&gt;
          &lt;span class="na"&gt;appdir&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;app/fastapi"&lt;/span&gt;
          &lt;span class="na"&gt;region&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;eu"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Configuration des secrets GitHub
&lt;/h4&gt;

&lt;p&gt;Le workflow &lt;strong&gt;GitHub Actions&lt;/strong&gt; a besoin d'accéder aux &lt;strong&gt;variables d'environnement&lt;/strong&gt;. Nous avons donc renseigner les "secrets" nécessaires. Dans notre dépôt GitHub, nous allons dans "Settings" &amp;gt; "Secrets and variables" &amp;gt; "Actions", puis nous cliquons sur "New repository secret". Nous ajoutons les secrets suivants:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Nom du secret&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEROKU_API_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clé API Heroku&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HEROKU_EMAIL&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Email du compte Heroku&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;MLFLOW_TRACKING_URI&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;URI du serveur MLflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;RUN_ID&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;ID du run MLflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;APPINSIGHTS_INSTRUMENTATION_KEY&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Clé Application Insights&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Déploiement sur Heroku
&lt;/h3&gt;

&lt;p&gt;Pour le déploiement de notre solution, nous avons choisi &lt;a href="https://www.heroku.com/" rel="noopener noreferrer"&gt;Heroku&lt;/a&gt; pour plusieurs raisons :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Plan gratuit&lt;/strong&gt; : conforme à la demande de limiter les coûts pour ce prototype&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intégration avec GitHub&lt;/strong&gt; : facilite le déploiement continu avec GitHub Actions&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalabilité&lt;/strong&gt; : possibilité d'évoluer si le projet est approuvé pour la production&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Région Europe&lt;/strong&gt; : conformité avec les exigences de localisation des données&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Configuration Heroku
&lt;/h4&gt;

&lt;p&gt;Notre application utilise les fichiers de configuration suivants pour Heroku :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Procfile&lt;/strong&gt; : &lt;code&gt;web: uvicorn main:app --host=0.0.0.0 --port=${PORT:-8000}&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;runtime.txt&lt;/strong&gt; : &lt;code&gt;python-3.10.12&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;requirements.txt&lt;/strong&gt; : Liste de toutes les dépendances nécessaires&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Les variables d'environnement sur Heroku incluent :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MLFLOW_TRACKING_URI&lt;/code&gt; : URI du serveur MLflow&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;RUN_ID&lt;/code&gt; : Identifiant du run MLflow du modèle déployé&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;APPINSIGHTS_INSTRUMENTATION_KEY&lt;/code&gt; : Clé pour Azure Application Insights&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Exemple d'exécution et déploiement réussis
&lt;/h3&gt;

&lt;p&gt;La capture d'écran suivante indique les &lt;strong&gt;tests ont été passés avec succès&lt;/strong&gt; et que le déploiement est réussi sur &lt;strong&gt;Heroku&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8kea1d9cidmc6bp272r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff8kea1d9cidmc6bp272r.png" alt="Capture d'écran d'un run GitHub Actions" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Avantages de notre pipeline CI/CD
&lt;/h3&gt;

&lt;p&gt;Notre pipeline de déploiement continu offre plusieurs avantages significatifs :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Automatisation complète&lt;/strong&gt; : Aucune intervention manuelle nécessaire&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fiabilité accrue&lt;/strong&gt; : Tests systématiques réduisant les risques&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Traçabilité&lt;/strong&gt; : Chaque déploiement lié à un commit Git spécifique&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feedback rapide&lt;/strong&gt; : Information immédiate en cas de problème&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette approche MLOps moderne nous permet de nous concentrer sur l'amélioration de notre modèle d'analyse de sentiment plutôt que sur les aspects opérationnels, tout en garantissant que chaque nouvelle version est correctement validée avant la mise en production.&lt;/p&gt;

&lt;h2&gt;
  
  
  📡 Suivi de la performance en production
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Mise en place d'Azure Application Insights
&lt;/h3&gt;

&lt;p&gt;Pour assurer un suivi efficace des performances du modèle en production, nous avons intégré Azure Application Insights, un service d'analyse des performances applicatives :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Télémétrie&lt;/strong&gt; : collecte automatique des données de performance de l'API&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Événements personnalisés&lt;/strong&gt; : enregistrement d'événements spécifiques liés au modèle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Visualisation&lt;/strong&gt; : tableaux de bord pour suivre l'évolution des performances&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette intégration nous permet de disposer d'une vision complète du comportement de notre modèle en situation réelle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Système de feedback utilisateur
&lt;/h3&gt;

&lt;p&gt;Un élément clé de notre approche MLOps est la collecte de feedback utilisateur sur les prédictions du modèle :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Interface de validation&lt;/strong&gt; : pour chaque prédiction, l'utilisateur peut indiquer si elle est correcte ou non&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Collecte structurée&lt;/strong&gt; : enregistrement du tweet, de la prédiction initiale et de la correction éventuelle&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stockage centralisé&lt;/strong&gt; : toutes les données de feedback sont centralisées dans Azure Application Insights&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Dans Azure Application Insights, pour consulter les &lt;strong&gt;feedbacks de tweets incorrectement prédits&lt;/strong&gt;, il suffit d'exécuter la commande suivante :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;customEvents
| where name == "model_feedback" and customDimensions.is_correct == "False"
| sort by timestamp desc
| project timestamp, 
        tweet = tostring(customDimensions.tweet), 
        prediction = tostring(customDimensions.prediction), 
        corrected_sentiment = tostring(customDimensions.corrected_sentiment)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59roizfuhudinm7fjfol.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59roizfuhudinm7fjfol.png" alt="Feedbacks de tweets incorrectement prédits " width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ce système permet de &lt;strong&gt;constituer progressivement un corpus d'exemples difficiles qui serviront à améliorer le modèle&lt;/strong&gt;. Ces exemples difficiles sont particulièrement précieux car ils représentent les cas limites où le modèle actuel échoue, révélant ainsi ses points faibles spécifiques.&lt;/p&gt;

&lt;p&gt;En collectant systématiquement ces tweets mal classifiés, nous créons un &lt;strong&gt;dataset enrichi qui cible précisément les lacunes du modèle&lt;/strong&gt;. Cette approche d'apprentissage actif (&lt;em&gt;active learning&lt;/em&gt;) est beaucoup plus efficace qu'une simple augmentation de données aléatoire, car elle concentre les efforts d'amélioration sur les zones problématiques.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration des alertes automatiques
&lt;/h3&gt;

&lt;p&gt;Pour détecter rapidement les problèmes potentiels, nous avons configuré un &lt;strong&gt;système d'alertes automatiques&lt;/strong&gt; :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Définition du seuil&lt;/strong&gt; : déclenchement d'une alerte si &lt;strong&gt;3 prédictions incorrectes sont signalées dans un intervalle de 5 minutes&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notification&lt;/strong&gt; : envoi d'un email aux responsables du projet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Suivi&lt;/strong&gt; : journalisation des alertes pour analyse ultérieure.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiytp14vvvye8ray3ax1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiytp14vvvye8ray3ax1.png" alt="Capture de l'écran alertes de Azure Application Insights" width="800" height="563"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Ce mécanisme proactif permet à l'équipe d'intervenir rapidement en cas de dégradation des performances du modèle.&lt;/p&gt;

&lt;h3&gt;
  
  
  Stratégie d'amélioration continue du modèle
&lt;/h3&gt;

&lt;p&gt;Pour garantir la pertinence du modèle dans le temps, nous définissons une stratégie d'amélioration continue :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Analyse périodique&lt;/strong&gt; : examen mensuel des tweets mal prédits pour identifier des patterns&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enrichissement des données&lt;/strong&gt; : ajout des exemples difficiles au jeu d'entraînement&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Réentraînement&lt;/strong&gt; : mise à jour trimestrielle du modèle avec les nouvelles données&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement automatisé&lt;/strong&gt; : mise en production de la nouvelle version via le pipeline CI/CD&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Cette approche cyclique permet d'adapter le modèle à l'évolution du langage sur Twitter et aux spécificités des conversations concernant Air Paradis.&lt;/p&gt;

&lt;h2&gt;
  
  
  🏁 Conclusion
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Résultats obtenus
&lt;/h3&gt;

&lt;p&gt;Ce projet nous a permis de développer un &lt;strong&gt;prototype fonctionnel d'analyse de sentiments pour tweets&lt;/strong&gt;, répondant pleinement aux attentes d'Air Paradis :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Performance&lt;/strong&gt; : notre modèle &lt;strong&gt;LSTM avec Word2Vec&lt;/strong&gt; atteint une précision de 85,2%, offrant une détection fiable des sentiments négatifs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement&lt;/strong&gt; : la solution est accessible via une API REST déployée sur Heroku.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Interface&lt;/strong&gt; : une application ergonomique permet aux équipes marketing d'utiliser facilement le modèle.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring&lt;/strong&gt; : un système complet de suivi et d'alertes garantit la détection rapide des problèmes potentiels.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Perspectives d'évolution
&lt;/h3&gt;

&lt;p&gt;Si ce prototype est validé par Air Paradis, plusieurs axes d'amélioration pourraient être explorés :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Déploiement du modèle BERT&lt;/strong&gt; : migration vers une infrastructure permettant d'exploiter les performances supérieures de BERT&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyse en temps réel&lt;/strong&gt; : intégration avec l'API Twitter pour une surveillance continue&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Classification multi-classes&lt;/strong&gt; : distinction entre sentiments négatifs, neutres et positifs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Analyse thématique&lt;/strong&gt; : identification des sujets spécifiques générant des sentiments négatifs&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Avantages pour Air Paradis
&lt;/h3&gt;

&lt;p&gt;Cette solution d'analyse de sentiments offre plusieurs avantages stratégiques pour Air Paradis :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Détection précoce&lt;/strong&gt; : identification des bad buzz potentiels avant qu'ils ne prennent de l'ampleur&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Réactivité&lt;/strong&gt; : capacité à intervenir rapidement sur les problèmes signalés&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Intelligence client&lt;/strong&gt; : meilleure compréhension des préoccupations et des attentes des clients&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Protection de l'image&lt;/strong&gt; : préservation de la réputation de la compagnie sur les réseaux sociaux&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;En conclusion, ce projet illustre comment &lt;strong&gt;les technologies d'IA, combinées à une approche MLOps structurée, peuvent apporter une réelle valeur ajoutée dans la gestion de la réputation en ligne d'une entreprise&lt;/strong&gt;. Air Paradis dispose désormais d'un outil puissant pour anticiper et gérer efficacement sa présence sur les réseaux sociaux.&lt;/p&gt;

</description>
      <category>machinelearning</category>
      <category>deeplearning</category>
      <category>python</category>
      <category>nextjs</category>
    </item>
    <item>
      <title>🌊 Déployer un serveur MLflow dans un Codespace Github</title>
      <dc:creator>David Scanu </dc:creator>
      <pubDate>Wed, 20 Mar 2024 11:42:36 +0000</pubDate>
      <link>https://dev.to/davidscanu/deployer-un-serveur-mlflow-dans-un-codespace-github-1pm5</link>
      <guid>https://dev.to/davidscanu/deployer-un-serveur-mlflow-dans-un-codespace-github-1pm5</guid>
      <description>&lt;p&gt;Voici toutes les étapes pour lancer un &lt;strong&gt;serveur MLflow&lt;/strong&gt; directement dans une machine virtuelle &lt;strong&gt;GitHub Codespace&lt;/strong&gt;. Le gros avantage de cette méthode est quelle permet de lancer &lt;strong&gt;rapidement&lt;/strong&gt; et &lt;strong&gt;gratuitement&lt;/strong&gt; un serveur MLflow pour suivre vos expériences de machine learning. Voici le dépôt GitHub dont vous aurez besoin :&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/DavidScanu/mlflow-server-devcontainer" rel="noopener noreferrer"&gt;Lancer un serveur MLflow dans un codespace (GitHub)&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Les &lt;strong&gt;codespaces sont des environnements de développement hébergés sur GitHub&lt;/strong&gt;. Ils offrent un environnement de développement ou que vous soyez, depuis votre navigateur.&lt;/p&gt;

&lt;h2&gt;
  
  
  🚀 Partie 1 : Lancer un serveur MLflow dans codespace
&lt;/h2&gt;

&lt;p&gt;Vous avez besoin d'un serveur &lt;strong&gt;MLflow hébergé gratuitement&lt;/strong&gt; ? Suivez les étapes suivantes.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Dupliquez (fork) ce dépôt
&lt;/h3&gt;

&lt;p&gt;Dupliquez (fork) le dépôt suivant : &lt;a href="https://github.com/DavidScanu/mlflow-server-devcontainer" rel="noopener noreferrer"&gt;Lancer un serveur MLflow dans un codespace (GitHub)&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Renseignez les variables d'environnement
&lt;/h3&gt;

&lt;p&gt;Allez à la page de configuration des &lt;strong&gt;variables d'environnement pour Codespaces&lt;/strong&gt; du dépôt, à l'adresse suivante : &lt;code&gt;https://github.com/[votre-nom-utilisateur]/mlflow-server-devcontainer/settings/secrets/codespaces&lt;/code&gt;. Renseignez les variables suivantes :&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ARTIFACT_STORE_URI&lt;/code&gt; : L'URI de stockage des artéfacts (Amazon S3).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt; et &lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt; : Les identifiants de connexion à l'espace de stockage Amazon S3. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;BACKEND_STORE_URI&lt;/code&gt; : L'URI de votre base de donnée. Pour une base de donnée PostgreSQL, l'URI se présente au format : &lt;code&gt;postgresql://[username]:[password]@[host]:[port]/[database]&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Plus de renseignements sur la configuration d'un serveur de tracking MLflow : &lt;a href="https://mlflow.org/docs/latest/tracking.html#set-up-the-mlflow-tracking-environment" rel="noopener noreferrer"&gt;Set up the MLflow Tracking Environment&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp66zrbe5j4mc3qt0ocsw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp66zrbe5j4mc3qt0ocsw.png" alt="Variables d'environnement pour Codespaces" width="800" height="678"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Lancez un nouveau codespace
&lt;/h3&gt;

&lt;p&gt;Lancez un nouveau codespace à partir de votre dépôt (UI de GitHub: Code / Codespaces / +)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xsoqd8ngr8wetvsd0so.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6xsoqd8ngr8wetvsd0so.png" alt="Lancez un nouveau codespace" width="800" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Ouvrez le port 5001
&lt;/h3&gt;

&lt;p&gt;Dans le Terminal, onglet "Ports", &lt;strong&gt;définissez l'URL du port 5001 comme public&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f67dt2nynqx87yh9gag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3f67dt2nynqx87yh9gag.png" alt="Ouvrez le port 5001" width="800" height="144"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  5. Accédez à l'UI MLflow
&lt;/h3&gt;

&lt;p&gt;Accéder à l'UI MLflow en accédant à l'&lt;strong&gt;URL public exposée par codespace&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw4oicdm97y4byqrwt2d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqw4oicdm97y4byqrwt2d.png" alt="Accédez à l'UI MLflow" width="800" height="491"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Utilisez cette URL pour le tracking de vos travaux de machine learning depuis un notebook Colab ou notebook local, soit en définissant la variable d'environnement &lt;code&gt;MLFLOW_TRACKING_URI&lt;/code&gt;, soit en exécutant le code Python suivant dans votre notebook :&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;mlflow&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set_tracking_uri&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;uri&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;http://&amp;lt;host&amp;gt;:&amp;lt;port&amp;gt;&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. (Optionnel) Testez votre serveur MLflow
&lt;/h3&gt;

&lt;p&gt;A l'intérieur de votre codespace, exécutez les étapes suivantes : &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Entrainez un modèle&lt;/strong&gt; : &lt;code&gt;python3 demo/train.py&lt;/code&gt;. Vous devez voir apparaître un nouveau run dans l'UI MLflow et dans le Terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copiez le numéro de Run&lt;/strong&gt; : Copiez le numéro de run (run id) qui apparaît dans le Terminal.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Utilisez un modèle&lt;/strong&gt; : &lt;code&gt;python3 demo/try-model.py&lt;/code&gt;. Entrez le numero de run (run id) dans le Terminal. Cette commande retourne un modèle dans le Terminal, cela signifie que vos modèle trackés par votre serveur MLflow sont disponibles à l'utilisation.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsb09mej1guppiyb6zcc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvsb09mej1guppiyb6zcc.png" alt="Testez votre serveur MLflow" width="800" height="252"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  7. Utilisation depuis un notebook Colab
&lt;/h3&gt;

&lt;p&gt;Démonstration de l'utilisation du serveur de tracking depuis &lt;a href="https://colab.research.google.com/drive/1sHlb9vpEj3y-v1rtHJ-5TaC-sTXii1D0?usp=sharing" rel="noopener noreferrer"&gt;ce notebook Colab&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Modifiez les variables d'environnement suivantes dans l'onglet "🔑 Secrets" :

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;MLFLOW_TRACKING_URI&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS_ACCESS_KEY_ID&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;AWS_SECRET_ACCESS_KEY&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsotwsn6vj2phkkdnyw80.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsotwsn6vj2phkkdnyw80.png" alt="Utilisation depuis un notebook Colab" width="800" height="568"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Votre serveur MLflow fonctionne maintenant depuis votre codespace et vous pouvez trackez vos expériences de machine learning. &lt;strong&gt;N'oubliez pas de lancer et d'éteindre votre codespace à chaque utilisation&lt;/strong&gt;. Sans quoi, du temps d'utilisation vous sera décompté.&lt;/p&gt;

&lt;h2&gt;
  
  
  Partie 2 : Comment ça marche ?
&lt;/h2&gt;

&lt;p&gt;Si vous souhaitez simplement et rapidement lancer un serveur MLflow dans un codespace, seule la première partie de cet article vous est utile. Cette deuxième partie n'est utile que si vous souhaitez comprendre comment fonctionne la configuration d'un conteneur de développement (Dev Container) dans un codespace. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Les machines virtuelles codespace sont en réalité des conteneurs de développement (Dev Container), basés sur des images Docker&lt;/strong&gt;. Pour créer notre &lt;strong&gt;serveur MLflow personnalisé&lt;/strong&gt; qui fonctionne dans un codespace, nous avons créé une configuration de conteneur de développement (&lt;strong&gt;Dev Container&lt;/strong&gt;) à partir d'une &lt;strong&gt;image Docker&lt;/strong&gt; et d'un &lt;strong&gt;docker-compose.yaml&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Configuration d'un conteneur de développement
&lt;/h3&gt;

&lt;p&gt;Pour configurer un conteneur de développement (Dev Container), nous créons les fichiers suivants :  &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Un dossier &lt;code&gt;.devcontainer/&lt;/code&gt; : dossier de stockage de tous les fichiers de configuration du codespace.&lt;/li&gt;
&lt;li&gt;un fichier &lt;code&gt;devcontainer.json&lt;/code&gt; : stocke les paramètres spécifiques à notre conteneur de développement (Dev container).&lt;/li&gt;
&lt;li&gt;un fichier &lt;code&gt;Dockerfile&lt;/code&gt; : la configuration de l'image Docker qui configure le conteneur de développement avec les logiciels &lt;strong&gt;Python 3.10&lt;/strong&gt;, &lt;strong&gt;Docker&lt;/strong&gt; et &lt;strong&gt;GIT&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;un fichier &lt;code&gt;docker-compose.yaml&lt;/code&gt; (Docker Compose) : permet de construire l'image Docker à partir du Dockerfile et de configurer les variables d'environnement dans le conteneur&lt;/li&gt;
&lt;li&gt;un fichier &lt;code&gt;requirements.txt&lt;/code&gt; : permet d'installer les bibliothèques Python&lt;/li&gt;
&lt;li&gt;un fichier &lt;code&gt;.dockerignore&lt;/code&gt; : permet d'ignorer certains dossier qu'on souhaite ignorer dans l'image finale. &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Passons en revue les différents fichiers de configuration.&lt;/p&gt;

&lt;h4&gt;
  
  
  devcontainer.json
&lt;/h4&gt;

&lt;p&gt;C'est le fichier principal de configuration du conteneur de développement. Il permet de : &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Créer un environnement de développement&lt;/strong&gt; à partir du fichier &lt;code&gt;docker-compose.yaml&lt;/code&gt;. Le paramètre &lt;code&gt;"dockerComposeFile"&lt;/code&gt; indique le chemin vers le fichier &lt;code&gt;docker-compose.yaml&lt;/code&gt; (qui lui-même utilise le &lt;code&gt;Dockerfile&lt;/code&gt;). &lt;code&gt;"service"&lt;/code&gt; indique quel service dans le fichier &lt;code&gt;docker-compose.yaml&lt;/code&gt; doit être utilisé comme conteneur principal pour le codespace. &lt;code&gt;"workspaceFolder"&lt;/code&gt; indique le dossier principal de travail à ouvrir dans le codespace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rediriger le port&lt;/strong&gt; sur lequel le serveur écoute, c-à-d &lt;code&gt;5001&lt;/code&gt; pour notre cas avec le paramètre &lt;code&gt;"forwardPorts"&lt;/code&gt;. Le paramètre &lt;code&gt;"onAutoForward": "openBrowser"&lt;/code&gt; indique au conteneur d'ouvrir l'URL public sur le port 5001 à chaque lancement du codespace.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ajouter des "features"&lt;/strong&gt; avec le paramètre &lt;code&gt;"features"&lt;/code&gt;: Les "features" permettent d'ajouter rapidement et facilement davantage d’outils supplémentaires à notre conteneur de développement. Ici , nous avons ajouté &lt;strong&gt;Git&lt;/strong&gt; et &lt;strong&gt;Docker&lt;/strong&gt; (Docker est inutile pour notre cas d'utilisation).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Personnaliser VS Code&lt;/strong&gt; à l'intérieur du codespace &lt;code&gt;"customizations"&lt;/code&gt;: installer des extensions et customiser la présentation.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MLflow Server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"dockerComposeFile"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"../docker-compose.yaml"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"mlflow-server"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"workspaceFolder"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/mlflow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Use&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;'forwardPorts'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;list&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;of&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;ports&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;inside&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;available&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;locally.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"forwardPorts"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5001&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="nl"&gt;"portsAttributes"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"5001"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"label"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"MLflow server port"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"onAutoForward"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"openBrowser"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Features&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;to&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;dev&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container.&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;More&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;info:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;https://containers.dev/features.&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"features"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/devcontainers/features/docker-in-docker:2"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{},&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"ghcr.io/devcontainers/features/git:1"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;

    &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;VS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;Code&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;customization&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;inside&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;the&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;container&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"customizations"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"vscode"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"settings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"workbench.colorTheme"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Default Dark Modern"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"extensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode-remote.vscode-remote-extensionpack"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-azuretools.vscode-docker"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-python.vscode-pylance"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-python.python"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-vscode-remote.remote-containers"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"GitHub.codespaces"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"ms-toolsai.jupyter"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="s2"&gt;"bierner.markdown-preview-github-styles"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Dockerfile
&lt;/h4&gt;

&lt;p&gt;Le reste de la configuration est un peu plus simple. Nous créons une image docker avec un &lt;code&gt;Dockerfile&lt;/code&gt; à partir d'une image &lt;strong&gt;Python 3.10&lt;/strong&gt;, dans laquelle nous installons &lt;strong&gt;MLflow&lt;/strong&gt;, &lt;strong&gt;Boto3&lt;/strong&gt;, &lt;strong&gt;Psycopg&lt;/strong&gt; et &lt;strong&gt;Scikit-learn&lt;/strong&gt; avec le fichier &lt;code&gt;requirements.txt&lt;/code&gt;. Puis nous lançons le serveur MLflow en utilisant les variables d'environnement du conteneur, définies dans le &lt;code&gt;docker-compose.yaml&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; python:3.10-slim&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /mlflow/mlflow-data&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;python &lt;span class="nt"&gt;-m&lt;/span&gt; pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--upgrade&lt;/span&gt; pip

&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; requirements.txt .&lt;/span&gt;

&lt;span class="k"&gt;RUN &lt;/span&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt

&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; mlflow server --port $PORT --host 0.0.0.0 --backend-store-uri $BACKEND_STORE_URI --default-artifact-root $ARTIFACT_STORE_URI&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Docker Compose (compose.yaml)
&lt;/h4&gt;

&lt;p&gt;Enfin, nous créons un conteneur à partir de l'image définie dans le &lt;code&gt;Dockerfile&lt;/code&gt; (&lt;code&gt;build : .&lt;/code&gt;). Nous exposons le &lt;strong&gt;port 5001&lt;/strong&gt;. Nous définissons les variables d'environnement qui provienne des réglages des secrets du codespace.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;version: '3'
services:
  mlflow-server:
    build : .
    ports:
      - "5001:5001"
    environment:
      - PORT=5001
      - BACKEND_STORE_URI=$BACKEND_STORE_URI
      - ARTIFACT_STORE_URI=$ARTIFACT_STORE_URI
      - AWS_ACCESS_KEY_ID=$AWS_ACCESS_KEY_ID
      - AWS_SECRET_ACCESS_KEY=$AWS_SECRET_ACCESS_KEY
    volumes:
      - .:/mlflow
    restart: always
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Et voilà ! Vous savez maintenant configurez votre propre conteneur de développement avec les outils et "features" dont vous avez besoin !&lt;/p&gt;

&lt;h2&gt;
  
  
  📃 Documentation
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/en/codespaces/setting-up-your-project-for-codespaces/adding-a-dev-container-configuration/introduction-to-dev-containers" rel="noopener noreferrer"&gt;Introduction to dev containers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.visualstudio.com/docs/devcontainers/create-dev-container" rel="noopener noreferrer"&gt;Create a Dev Container&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://containers.dev/guide/dockerfile" rel="noopener noreferrer"&gt;Dev Containers - Using Images, Dockerfiles, and Docker Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://containers.dev/implementors/features/" rel="noopener noreferrer"&gt;Dev Container Features reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://containers.dev/features" rel="noopener noreferrer"&gt;Available Dev Container Features&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.github.com/fr/codespaces" rel="noopener noreferrer"&gt;Documentation Codespaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mlflow.org/docs/latest/tracking/tutorials/remote-server.html" rel="noopener noreferrer"&gt;MLflow remote server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>tutorial</category>
      <category>python</category>
      <category>devops</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
