{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":4104,"databundleVersionId":46661,"sourceType":"competition"},{"sourceId":7251,"sourceType":"datasetVersion","datasetId":2798},{"sourceId":7866129,"sourceType":"datasetVersion","datasetId":4614938},{"sourceId":7869237,"sourceType":"datasetVersion","datasetId":4617269}],"dockerImageVersionId":30673,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"**Pre traitement et l'importation des bibliothèques nécessaires**","metadata":{}},{"cell_type":"code","source":"# copy the weights and configurations for the pre-trained models \n!mkdir ~/.keras\n!mkdir ~/.keras/models7\n!cp ../input/keras-pretrained-models/*notop* ~/.keras/models/\n!cp ../input/keras-pretrained-models/imagenet_class_index.json ~/.keras/models/","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:18:10.401290Z","iopub.execute_input":"2025-05-12T15:18:10.401948Z","iopub.status.idle":"2025-05-12T15:18:14.451548Z","shell.execute_reply.started":"2025-05-12T15:18:10.401921Z","shell.execute_reply":"2025-05-12T15:18:14.450697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\nfrom glob import glob\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom sklearn.metrics import cohen_kappa_score, confusion_matrix, accuracy_score, ConfusionMatrixDisplay","metadata":{"execution":{"iopub.status.busy":"2025-05-12T15:18:48.958162Z","iopub.execute_input":"2025-05-12T15:18:48.958499Z","iopub.status.idle":"2025-05-12T15:18:48.963289Z","shell.execute_reply.started":"2025-05-12T15:18:48.958466Z","shell.execute_reply":"2025-05-12T15:18:48.962428Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"thetrainpath= glob('/kaggle/input/diabetic-retinopathy-train-unzipped/train/*.jpeg')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:19:46.691248Z","iopub.execute_input":"2025-05-12T15:19:46.691969Z","iopub.status.idle":"2025-05-12T15:19:47.096798Z","shell.execute_reply.started":"2025-05-12T15:19:46.691939Z","shell.execute_reply":"2025-05-12T15:19:47.096144Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"file_lbl=\"/kaggle/input/diabetic-retinopathy-detection/trainLabels.csv.zip\"\ndf_train=pd.read_csv(file_lbl,sep=',')\ndf_train","metadata":{"execution":{"iopub.status.busy":"2025-05-12T15:20:10.727269Z","iopub.execute_input":"2025-05-12T15:20:10.727898Z","iopub.status.idle":"2025-05-12T15:20:10.780388Z","shell.execute_reply.started":"2025-05-12T15:20:10.727869Z","shell.execute_reply":"2025-05-12T15:20:10.779524Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Dossier contenant les images d'entraînement\ntrain_images_path = '/kaggle/input/diabetic-retinopathy-train-unzipped/train/'\n\n# Obtenir la liste des fichiers image avec extension .jpeg\nimage_files = glob(os.path.join(train_images_path, '*.jpeg'))\n\n# Chargement du fichier CSV contenant les étiquettes\nlabels_path = os.path.join('/kaggle/input/diabetic-retinopathy-train-unzipped', file_lbl)\nlabels_df = pd.read_csv(labels_path)\n\n# Ajout de l'identifiant du patient et du chemin complet de l'image\nlabels_df['PatientId'] = labels_df['image'].apply(lambda name: name.split('_')[0])\nlabels_df['image_path'] = labels_df['image'].apply(lambda name: os.path.join(train_images_path, f'{name}.jpeg'))\n\n# Vérification de l'existence du fichier image\nlabels_df['is_present'] = labels_df['image_path'].apply(os.path.exists)\nprint(f\"{labels_df['is_present'].sum()} images disponibles sur {labels_df.shape[0]} attendues.\")\n\n# Encodage de l'œil (gauche = 1, droite = 0)\nlabels_df['eye_side'] = labels_df['image'].apply(lambda name: 1 if name.endswith('left') else 0)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:21:38.590147Z","iopub.execute_input":"2025-05-12T15:21:38.590521Z","iopub.status.idle":"2025-05-12T15:23:15.868062Z","shell.execute_reply.started":"2025-05-12T15:21:38.590496Z","shell.execute_reply":"2025-05-12T15:23:15.867151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.utils import to_categorical\n\n# Conversion de la colonne 'level' en vecteurs one-hot\nlabels_df['level_encoded'] = labels_df['level'].apply(\n    lambda label: to_categorical(label, num_classes=labels_df['level'].max() + 1)\n)\n\n# Suppression des lignes contenant des valeurs manquantes\nlabels_df.dropna(inplace=True)\n\n# Filtrage pour ne garder que les images disponibles\nlabels_df = labels_df[labels_df['is_present']]\n\n# Affichage de quelques exemples\nlabels_df.sample(3)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:27:59.502313Z","iopub.execute_input":"2025-05-12T15:27:59.502703Z","iopub.status.idle":"2025-05-12T15:28:01.300477Z","shell.execute_reply.started":"2025-05-12T15:27:59.502677Z","shell.execute_reply":"2025-05-12T15:28:01.299588Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Visualiser la distribution des variables 'level' et 'eye' avec un pairplot\nsns.pairplot(labels_df[['level', 'eye_side']], hue='eye_side', palette='coolwarm')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:53:14.950808Z","iopub.execute_input":"2025-05-12T15:53:14.951154Z","iopub.status.idle":"2025-05-12T15:53:15.727236Z","shell.execute_reply.started":"2025-05-12T15:53:14.951129Z","shell.execute_reply":"2025-05-12T15:53:15.726305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Boxplot pour la distribution des niveaux en fonction de l'œil\nsns.boxplot(x='eye_side', y='level', data=labels_df, palette='coolwarm')\nplt.title('Distribution des niveaux en fonction de l\\'œil')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:54:35.186408Z","iopub.execute_input":"2025-05-12T15:54:35.186723Z","iopub.status.idle":"2025-05-12T15:54:35.415288Z","shell.execute_reply.started":"2025-05-12T15:54:35.186700Z","shell.execute_reply":"2025-05-12T15:54:35.414481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import seaborn as sns\nimport matplotlib.pyplot as plt\n\n# Violinplot pour la distribution des niveaux selon l'œil\nsns.violinplot(x='eye_side', y='level', data=labels_df, palette='muted')\nplt.title('Répartition des niveaux en fonction de l\\'œil')\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T15:55:10.641709Z","iopub.execute_input":"2025-05-12T15:55:10.642543Z","iopub.status.idle":"2025-05-12T15:55:10.966918Z","shell.execute_reply.started":"2025-05-12T15:55:10.642509Z","shell.execute_reply":"2025-05-12T15:55:10.966359Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import resample\nimport matplotlib.pyplot as plt\n\n# Préparation des données à partir du jeu de données 'labels_df'\n# Extraction des identifiants patients uniques avec leurs niveaux de gravité\nunique_patients_df = labels_df[['PatientId', 'level']].drop_duplicates()\n\n# Séparation stratifiée des patients pour garantir une répartition équilibrée des niveaux\ntrain_patients, val_patients = train_test_split(\n    unique_patients_df['PatientId'],\n    test_size=0.25,\n    stratify=unique_patients_df['level'],\n    random_state=2018\n)\n\n# Filtrage des données complètes selon les identifiants sélectionnés\ntrain_df = labels_df[labels_df['PatientId'].isin(train_patients)]\nval_df = labels_df[labels_df['PatientId'].isin(val_patients)]\n\nprint(f\"Nombre d'observations - Entraînement: {train_df.shape[0]}, Validation: {val_df.shape[0]}\")\n\n# Équilibrage de l'ensemble d'entraînement par sur-échantillonnage (oversampling)\n# Calcul du nombre cible d'échantillons pour chaque groupe (level, eye)\ntarget_count = train_df.groupby(['level', 'eye_side']).size().max()\n\n# Application de la stratégie de sur-échantillonnage\nbalanced_train_df = (\n    train_df.groupby(['level', 'eye_side'], group_keys=False)\n    .apply(lambda group: resample(group, replace=True, n_samples=target_count, random_state=2018))\n    .reset_index(drop=True)\n)\n\nprint(f\"Taille après équilibrage de l'ensemble d'entraînement : {balanced_train_df.shape[0]}\")\n\n# Visualisation de la distribution des classes dans l'ensemble équilibré\nfig, axes = plt.subplots(1, 2, figsize=(12, 5))\nbalanced_train_df['level'].value_counts().sort_index().plot(kind='bar', ax=axes[0], title=\"Répartition par niveau\")\nbalanced_train_df['eye_side'].value_counts().sort_index().plot(kind='bar', ax=axes[1], title=\"Répartition par œil\")\nplt.tight_layout()\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T16:13:49.736048Z","iopub.execute_input":"2025-05-12T16:13:49.736750Z","iopub.status.idle":"2025-05-12T16:13:50.243214Z","shell.execute_reply.started":"2025-05-12T16:13:49.736720Z","shell.execute_reply":"2025-05-12T16:13:50.242382Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Re configuration des images (Augmenting)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array\nfrom tensorflow.keras.utils import to_categorical\n\n\n# 1 Initialisation des ImageDataGenerators (avec et sans augmentation)\ntrain_datagen = ImageDataGenerator(\n    rescale           = 1. / 255,\n    rotation_range    = 40,\n    width_shift_range = 0.20,\n    height_shift_range= 0.20,\n    shear_range       = 0.20,\n    zoom_range        = 0.20,\n    horizontal_flip   = True,\n    fill_mode         = \"nearest\"\n)\n\nvalid_datagen = ImageDataGenerator(rescale = 1. / 255)\n\n# 2 Fonction utilitaire pour générer les batches à partir d'un DataFrame\ndef generate_from_dataframe(df,\n                             datagen,\n                             batch_size  : int = 32,\n                             target_size : tuple = (224, 224),\n                             num_classes : int = None,\n                             shuffle     : bool = True):\n    \"\"\"\n    Génère des batches (images, labels) en appliquant des transformations \n    via ImageDataGenerator.\n\n    Paramètres\n    ----------\n    df          : DataFrame avec au minimum les colonnes 'image_path' et 'level'\n    datagen     : un ImageDataGenerator configuré\n    batch_size  : nombre d'images par batch\n    target_size : taille (H, W) des images après redimensionnement\n    num_classes : si précisé, les labels seront encodés en one-hot\n    shuffle     : réorganiser le DataFrame au début de chaque époque\n    \"\"\"\n    while True:\n        # Réorganiser les lignes du DataFrame si nécessaire\n        if shuffle:\n            df = df.sample(frac=1, random_state=None).reset_index(drop=True)\n\n        # Parcourir les données par batchs\n        for start in range(0, len(df), batch_size):\n            end   = start + batch_size\n            batch = df.iloc[start:end]\n\n            # ----- Chargement des images -----\n            imgs, lbls = [], []\n            for _, row in batch.iterrows():\n                # Chargement et redimensionnement de l'image\n                img = load_img(row['image_path'], target_size=target_size)   # <-- colonne adaptée\n                imgs.append(img_to_array(img))\n                lbls.append(row['level'])                                    # <-- toujours 'level'\n\n            # Conversion en tableaux NumPy\n            X = np.array(imgs, dtype=np.float32)\n            y = np.array(lbls, dtype=np.int64)\n\n            # Encodage des labels en one-hot si nécessaire\n            if num_classes is not None:\n                y = to_categorical(y, num_classes=num_classes)\n\n            # ImageDataGenerator.flow est un générateur infini ; on \"déballe\" un batch à la fois\n            for aug_X, aug_y in datagen.flow(X, y, batch_size=batch_size, shuffle=False):\n                yield aug_X, aug_y\n                break   # Sortir après un seul batch pour que la boucle externe contrôle l'ordre\n\n# 3 Détection automatique du nombre de classes et création des générateurs\n# Identification du nombre de classes à partir du DataFrame d'entraînement\nnum_classes = balanced_train_df['level'].nunique()\n\n# Création des générateurs d'entraînement et de validation\ntrain_generator = generate_from_dataframe(\n    balanced_train_df,\n    train_datagen,\n    batch_size   = 32,\n    target_size  = (224, 224),\n    num_classes  = num_classes\n)\n\nvalid_generator = generate_from_dataframe(\n    val_df,\n    valid_datagen,\n    batch_size   = 32,\n    target_size  = (224, 224),\n    num_classes  = num_classes,\n    shuffle      = False  # Pas de réorganisation des données de validation entre les époques\n)\n\n# 4 Vérification rapide : récupérer un batch\nX_b, y_b = next(train_generator)\nprint(f\"Shape des images : {X_b.shape}\")   # -> (32, 224, 224, 3)\nprint(f\"Shape des labels : {y_b.shape}\")   # -> (32, 5) si num_classes == 5\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:18:21.630908Z","iopub.execute_input":"2025-05-12T18:18:21.631501Z","iopub.status.idle":"2025-05-12T18:18:24.855309Z","shell.execute_reply.started":"2025-05-12T18:18:21.631471Z","shell.execute_reply":"2025-05-12T18:18:24.854448Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Les données d'entrainement","metadata":{}},{"cell_type":"markdown","source":"Visualisation 8 images augmentées (Training set)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\ndef visaugmtdimgs(generator, batch_size=8):\n    \"\"\"\n    Visualise un batch d'images augmentées avec leurs labels.\n\n    Paramètres :\n    - generator : générateur d'images augmentées\n    - batch_size : nombre d'images à afficher\n    \"\"\"\n    # Obtenir un batch d'images et de labels\n    t_x, t_y = next(generator)\n\n    # Vérifier la taille du batch pour s'assurer qu'il est assez grand\n    actual_batch_size = min(batch_size, t_x.shape[0])\n\n    # Créer une figure avec des sous-graphiques\n    fig, axes = plt.subplots(2, 4, figsize=(18, 9))\n    axes = axes.flatten()\n\n    for i in range(actual_batch_size):\n        # Dé-normaliser les images pour la visualisation\n        img = np.clip(t_x[i] * 255, 0, 255).astype(np.uint8)\n\n        # Identification du niveau et de l'œil\n        level = np.argmax(t_y[i])  # Récupération du niveau de gravité\n        eye_side = \"left\" if level % 2 == 0 else \"right\"  # Adaptation simplifiée\n\n        # Affichage de l'image\n        axes[i].imshow(img)\n        axes[i].axis('off')\n        axes[i].set_title(f\"Niveau : {level}\")\n\n    # Supprimer les sous-graphiques inutilisés s'il y en a\n    for j in range(actual_batch_size, len(axes)):\n        axes[j].axis('off')\n\n    plt.tight_layout()\n    plt.show()\n\n# Exemple d'utilisation : visualiser les images augmentées du générateur d'entraînement\nvisaugmtdimgs(train_generator, batch_size=8)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:28:39.538369Z","iopub.execute_input":"2025-05-12T18:28:39.538962Z","iopub.status.idle":"2025-05-12T18:28:43.543846Z","shell.execute_reply.started":"2025-05-12T18:28:39.538935Z","shell.execute_reply":"2025-05-12T18:28:43.542996Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Visualisation 10 images augmentées (Training set)","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\ndef visaugmtdimgs(generator, batch_size=10):\n    \"\"\"\n    Visualise un nombre précis d'images augmentées.\n    \n    Paramètres :\n    - generator : générateur d'images augmentées\n    - batch_size : nombre d'images à afficher (exactement)\n    \"\"\"\n    # Initialisation des listes pour accumuler les images et labels\n    images, labels = [], []\n\n    # Accumuler les images jusqu'à obtenir `batch_size` images\n    while len(images) < batch_size:\n        # Obtenir un batch du générateur\n        t_x, t_y = next(generator)\n        images.extend(t_x)\n        labels.extend(t_y)\n\n    # Sélectionner uniquement les `batch_size` premières images\n    images = np.array(images[:batch_size], dtype=np.float32)\n    labels = np.array(labels[:batch_size])\n\n    # Créer la figure avec des sous-graphiques\n    fig, axes = plt.subplots(2, 5, figsize=(20, 10))\n    axes = axes.flatten()\n\n    for i in range(batch_size):\n        # Dé-normaliser les images pour la visualisation\n        img = np.clip(images[i] * 255, 0, 255).astype(np.uint8)\n        label = np.argmax(labels[i])\n\n        # Affichage de l'image\n        axes[i].imshow(img)\n        axes[i].axis('off')\n        axes[i].set_title(f\"Niveau : {label}\")\n\n    plt.tight_layout()\n    plt.show()\n\n# Exemple d'utilisation : visualiser exactement 10 images\nvisaugmtdimgs(train_generator, batch_size=10)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T18:47:09.962919Z","iopub.execute_input":"2025-05-12T18:47:09.963564Z","iopub.status.idle":"2025-05-12T18:47:14.362640Z","shell.execute_reply.started":"2025-05-12T18:47:09.963535Z","shell.execute_reply":"2025-05-12T18:47:14.361754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\ndef plot_valid_img(validation_gen, batch_size=8):\n    \"\"\"\n    Visualise un batch d'images de validation avec leurs informations associées.\n\n    Paramètres :\n    - valid_gen : générateur d'images de validation\n    - batch_size : nombre d'images à afficher\n    \"\"\"\n    # Récupérer un batch complet\n    v_x, v_y = next(validation_gen)\n\n    # Ajuster le batch_size si le batch est plus petit\n    actual_batch_size = min(batch_size, len(v_x))\n\n    # Configuration de la figure avec des sous-graphiques\n    fig, axes = plt.subplots(2, 4, figsize=(20, 10))\n    axes = axes.flatten()\n\n    for i in range(actual_batch_size):\n        # Image\n        img = np.clip(v_x[i] * 255, 0, 255).astype(np.uint8)\n\n        # Label (one-hot -> index)\n        level = np.argmax(v_y[i])\n\n        # Affichage\n        axes[i].imshow(img)\n        axes[i].axis('off')\n        axes[i].set_title(f\"Niveau : {level}\")\n\n    # Cacher les axes inutilisés si le batch est incomplet\n    for j in range(actual_batch_size, len(axes)):\n        axes[j].axis('off')\n\n    plt.tight_layout()\n    plt.show()\n\n# Exemple d'utilisation : Visualiser un batch de validation\nplot_valid_img(valid_generator, batch_size=8)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T19:05:30.780805Z","iopub.execute_input":"2025-05-12T19:05:30.781183Z","iopub.status.idle":"2025-05-12T19:05:35.087293Z","shell.execute_reply.started":"2025-05-12T19:05:30.781154Z","shell.execute_reply":"2025-05-12T19:05:35.085924Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n\nmodel = Sequential([\n    Conv2D(32, (3, 3), activation='relu', input_shape=(224, 224, 3)),\n    MaxPooling2D(2, 2),\n    Conv2D(64, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    Conv2D(128, (3, 3), activation='relu'),\n    MaxPooling2D(2, 2),\n    Flatten(),\n    Dense(512, activation='relu'),\n    Dropout(0.5),\n    Dense(5, activation='softmax') \n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T21:19:04.285506Z","iopub.execute_input":"2025-05-12T21:19:04.285838Z","iopub.status.idle":"2025-05-12T21:19:04.336277Z","shell.execute_reply.started":"2025-05-12T21:19:04.285814Z","shell.execute_reply":"2025-05-12T21:19:04.335321Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(optimizer='adam',\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T21:20:02.359964Z","iopub.execute_input":"2025-05-12T21:20:02.360941Z","iopub.status.idle":"2025-05-12T21:20:02.370240Z","shell.execute_reply.started":"2025-05-12T21:20:02.360898Z","shell.execute_reply":"2025-05-12T21:20:02.369097Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(\n    train_generator,\n    steps_per_epoch=len(balanced_train_df,) // 32,  \n    epochs=2,\n    validation_data=valid_generator,\n    validation_steps=len(val_df) // 32\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T21:23:03.911845Z","iopub.execute_input":"2025-05-12T21:23:03.912210Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Retina Attention model ","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport tensorflow as tf\nfrom tensorflow.keras.applications import InceptionV3\nfrom tensorflow.keras.layers import (\n    Input, Conv2D, Dropout, multiply, GlobalAveragePooling2D,\n    Lambda, Dense, BatchNormalization\n)\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.metrics import TopKCategoricalAccuracy\n\n\n# 1. Initialisation des hyperparamètres\ninput_shape = (224, 224, 3)\nnum_classes = balanced_train_df['level'].nunique()\ndropout_rate = 0.5\nattention_filters = [64, 16, 8]\n\n# 2. Définition de l'Input Layer\nimage_input = Input(shape=input_shape, name=\"Input_Image\")\n\n# 3. Modèle pré-entraîné : InceptionV3 (couche de base)\nbase_model = InceptionV3(\n    input_shape=input_shape,\n    include_top=False,\n    weights='imagenet'\n)\nbase_model.trainable = False\n\n# Extraction des caractéristiques de la base pré-entraînée\nbase_features = base_model(image_input)\nbase_features = BatchNormalization(name=\"Base_BatchNorm\")(base_features)\n\n# 4. Mécanisme d'Attention\nattention_layer = base_features\n\nfor filters in attention_filters:\n    attention_layer = Conv2D(filters, kernel_size=(1, 1), padding='same', activation='relu')(Dropout(dropout_rate)(attention_layer))\n\n# Couche finale d'attention avec sigmoid pour la mise à l'échelle des activations\nattention_layer = Conv2D(1, kernel_size=(1, 1), padding='valid', activation='sigmoid', name=\"Attention_Mask\")(attention_layer)\n\n# Redimensionnement du masque pour qu'il corresponde aux canaux de `base_features`\nup_conv = Conv2D(\n    filters=base_features.shape[-1],\n    kernel_size=(1, 1),\n    padding='same',\n    activation='linear',\n    use_bias=False,\n    name=\"Expand_Mask\"\n)\n\n# Création du poids constant (1) pour la couche `up_conv`\ninitial_weights = np.ones((1, 1, 1, base_features.shape[-1]))\n\n# Assigner manuellement les poids à `up_conv`\nup_conv.build(input_shape=attention_layer.shape)\nup_conv.set_weights([initial_weights])\nup_conv.trainable = False\n\n# Appliquer la couche de redimensionnement\nattention_layer = up_conv(attention_layer)\n\n# 5. Application du masque d'attention\nmasked_features = multiply([attention_layer, base_features], name=\"Masked_Features\")\n\n# 6. Global Average Pooling & Rescaling\ngap_features = GlobalAveragePooling2D(name=\"GAP_Features\")(masked_features)\ngap_mask = GlobalAveragePooling2D(name=\"GAP_Mask\")(attention_layer)\n\n# Recalage pour compenser les pixels masqués\nrescaled_gap = Lambda(lambda x: x[0] / (x[1] + 1e-6), name=\"RescaleGAP\")([gap_features, gap_mask])\n\n# 7. Couches Fully Connected\nfc_layer = Dropout(0.25, name=\"Dropout1\")(rescaled_gap)\nfc_layer = Dense(128, activation='relu', name=\"FC_Layer\")(fc_layer)\nfc_layer = Dropout(0.25, name=\"Dropout2\")(fc_layer)\n\n# 8. Couche de sortie\noutput_layer = Dense(num_classes, activation='softmax', name=\"Output_Layer\")(fc_layer)\n\n# 9. Modèle final\nretina_model = Model(inputs=image_input, outputs=output_layer, name=\"Retina_Attention_Model\")\n\n# 10. Compilation du modèle\ndef top_2_accuracy(y_true, y_pred):\n    return TopKCategoricalAccuracy(k=2)(y_true, y_pred)\n\nretina_model.compile(\n    optimizer='adam',\n    loss='categorical_crossentropy',\n    metrics=['categorical_accuracy', top_2_accuracy]\n)\n\n# Résumé du modèle\nretina_model.summary()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T19:17:29.941340Z","iopub.execute_input":"2025-05-12T19:17:29.941756Z","iopub.status.idle":"2025-05-12T19:17:31.596975Z","shell.execute_reply.started":"2025-05-12T19:17:29.941732Z","shell.execute_reply":"2025-05-12T19:17:31.596136Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau\n\n# Correction du chemin de sauvegarde des poids\nweight_path = \"retina_weights.best.weights.h5\"\n\ncheckpoint = ModelCheckpoint(\n    filepath=weight_path, \n    monitor='val_loss', \n    verbose=1, \n    save_best_only=True, \n    save_weights_only=True, \n    mode='min'\n)\n\n# Réduction du Learning Rate\nreduceLROnPlat = ReduceLROnPlateau(\n    monitor='val_loss', \n    factor=0.8, \n    patience=3, \n    verbose=1, \n    mode='min', \n    min_delta=0.0001,  # `min_delta` remplace `epsilon`\n    cooldown=5, \n    min_lr=1e-5\n)\n\n# Arrêt anticipé\nearly = EarlyStopping(\n    monitor=\"val_loss\", \n    mode=\"min\", \n    patience=6,\n    verbose=1,\n    restore_best_weights=True\n)\n\n# Liste des callbacks\ncallbacks_list = [checkpoint, early, reduceLROnPlat]\nprint(callbacks_list)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:46:01.585836Z","iopub.execute_input":"2025-05-12T20:46:01.586806Z","iopub.status.idle":"2025-05-12T20:46:01.592890Z","shell.execute_reply.started":"2025-05-12T20:46:01.586776Z","shell.execute_reply":"2025-05-12T20:46:01.592017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!rm -rf ~/.keras # clean up before starting training\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:46:47.201769Z","iopub.execute_input":"2025-05-12T20:46:47.202550Z","iopub.status.idle":"2025-05-12T20:46:48.272216Z","shell.execute_reply.started":"2025-05-12T20:46:47.202519Z","shell.execute_reply":"2025-05-12T20:46:48.271187Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.layers import Input, Dense\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.optimizers import Adam\n\n# 1. Définition des variables globales\n# Créer le modèle une seule fois\ninputs = Input(shape=(4,))\noutputs = Dense(1, activation='linear')(inputs)\nsimple_model = Model(inputs, outputs)\n\n# Compilation du modèle (une seule fois)\nsimple_model.compile(optimizer=Adam(learning_rate=1e-4), loss='mse')\n\n# Créer une variable TensorFlow unique (si nécessaire)\nglobal_step = tf.Variable(0, dtype=tf.int64, trainable=False, name='global_step')\n\n\n# 2. Fonction d'entraînement décorée par @tf.function\n@tf.function\ndef train_step(x, y):\n    # Incrémenter global_step en dehors du contexte de GradientTape\n    global_step.assign_add(1)\n\n    with tf.GradientTape() as tape:\n        predictions = simple_model(x)\n        loss = tf.reduce_mean(tf.square(predictions - y))\n    \n    # Calcul des gradients\n    gradients = tape.gradient(loss, simple_model.trainable_variables)\n    \n    # Application des gradients\n    simple_model.optimizer.apply_gradients(zip(gradients, simple_model.trainable_variables))\n    \n    return loss\n\n# 3. Données d'entraînement\nx_train = tf.random.normal((10, 4))\ny_train = tf.random.normal((10, 1))\n\n# 4. Entraînement\nepochs = 50\n\nfor epoch in range(epochs):\n    loss_value = train_step(x_train, y_train)\n    print(f\"Époque {epoch + 1}, Perte : {loss_value.numpy()}\")\n\nprint(f\"Entraînement terminé. Nombre d'étapes globales : {global_step.numpy()}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:49:58.746511Z","iopub.execute_input":"2025-05-12T20:49:58.747280Z","iopub.status.idle":"2025-05-12T20:49:59.086457Z","shell.execute_reply.started":"2025-05-12T20:49:58.747252Z","shell.execute_reply":"2025-05-12T20:49:59.085570Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping, ReduceLROnPlateau, CSVLogger\nfrom tensorflow.keras.optimizers import Adam\n\n# ------------------------------------------------------------------\n# 1. Création du modèle avant toute opération d'entraînement\n# ------------------------------------------------------------------\n# Vérifier si le modèle existe déjà pour éviter une recréation multiple\nif 'retina_model' not in globals():\n    # Recréer le modèle une seule fois\n    retina_model = Model(inputs=image_input, outputs=output_layer, name=\"Retina_Attention_Model\")\n\n# ------------------------------------------------------------------\n# 2. Compilation du modèle\n# ------------------------------------------------------------------\nretina_model.compile(\n    optimizer=Adam(learning_rate=1e-4),  \n    loss='categorical_crossentropy',\n    metrics=['categorical_accuracy', top_2_accuracy]\n)\n\n# ------------------------------------------------------------------\n# 3. Paramètres d'enregistrement des poids\n# ------------------------------------------------------------------\nweight_path = \"retina_attention_model_best.weights.h5\"\n\ncheckpoint = ModelCheckpoint(\n    filepath=weight_path, \n    monitor='val_loss', \n    verbose=1, \n    save_best_only=True, \n    save_weights_only=True, \n    mode='min'\n)\n\n# ------------------------------------------------------------------\n# 4. Callback de réduction du taux d'apprentissage\n# ------------------------------------------------------------------\nreduce_lr = ReduceLROnPlateau(\n    monitor='val_loss', \n    factor=0.5,  \n    patience=3, \n    verbose=1, \n    mode='min', \n    min_delta=1e-4, \n    cooldown=2, \n    min_lr=1e-6\n)\n\n# ------------------------------------------------------------------\n# 5. Arrêt anticipé pour éviter le surapprentissage\n# ------------------------------------------------------------------\nearly_stop = EarlyStopping(\n    monitor='val_loss', \n    mode='min', \n    patience=10, \n    verbose=1, \n    restore_best_weights=True\n)\n\n# ------------------------------------------------------------------\n# 6. Logger CSV pour suivre les performances\n# ------------------------------------------------------------------\ncsv_logger = CSVLogger('training_log.csv', append=True)\n\n# Liste des callbacks\ncallbacks_list = [checkpoint, early_stop, reduce_lr, csv_logger]\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:24:08.927007Z","iopub.execute_input":"2025-05-12T20:24:08.927828Z","iopub.status.idle":"2025-05-12T20:24:08.939210Z","shell.execute_reply.started":"2025-05-12T20:24:08.927797Z","shell.execute_reply":"2025-05-12T20:24:08.938467Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Test des générateurs\nx_batch, y_batch = next(train_generator)\nprint(f\"Shape des images d'entraînement : {x_batch.shape}\")\nprint(f\"Shape des labels d'entraînement : {y_batch.shape}\")\n\nx_val_batch, y_val_batch = next(valid_generator)\nprint(f\"Shape des images de validation : {x_val_batch.shape}\")\nprint(f\"Shape des labels de validation : {y_val_batch.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:25:21.144761Z","iopub.execute_input":"2025-05-12T20:25:21.145548Z","iopub.status.idle":"2025-05-12T20:25:26.879484Z","shell.execute_reply.started":"2025-05-12T20:25:21.145520Z","shell.execute_reply":"2025-05-12T20:25:26.878541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Vérifier que le modèle est bien défini\nretina_model.summary()\n\n# Vérifier si le modèle est compilé\nif retina_model.optimizer is None:\n    print(\"Le modèle n'est pas compilé. Re-compilation...\")\n    retina_model.compile(\n        optimizer=Adam(learning_rate=1e-4),\n        loss='categorical_crossentropy',\n        metrics=['categorical_accuracy', top_2_accuracy]\n    )\nelse:\n    print(\"Le modèle est déjà compilé.\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:27:23.685607Z","iopub.execute_input":"2025-05-12T20:27:23.685935Z","iopub.status.idle":"2025-05-12T20:27:23.727901Z","shell.execute_reply.started":"2025-05-12T20:27:23.685911Z","shell.execute_reply":"2025-05-12T20:27:23.727085Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.layers import Input, Dense\nfrom tensorflow.keras.models import Model\n\n# Créer le modèle une seule fois\ninputs = Input(shape=(4,))\noutputs = Dense(1, activation='linear')(inputs)\nsimple_model = Model(inputs, outputs)\n\n# Compilation du modèle\nsimple_model.compile(optimizer='adam', loss='mse')\n\n# Fonction de mise à jour du modèle\n@tf.function\ndef train_step(x, y):\n    with tf.GradientTape() as tape:\n        predictions = simple_model(x)\n        loss = tf.reduce_mean(tf.square(predictions - y))\n    \n    # Calcul et application des gradients\n    gradients = tape.gradient(loss, simple_model.trainable_variables)\n    simple_model.optimizer.apply_gradients(zip(gradients, simple_model.trainable_variables))\n    \n    return loss\n\n# Données d'exemple\nx_train = tf.random.normal((10, 4))\ny_train = tf.random.normal((10, 1))\n\n# Exécution de la boucle d'entraînement\nfor epoch in range(50):\n    loss_value = train_step(x_train, y_train)\n    print(f\"Époque {epoch+1}, Perte : {loss_value.numpy()}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-12T20:37:15.044054Z","iopub.execute_input":"2025-05-12T20:37:15.044401Z","iopub.status.idle":"2025-05-12T20:37:15.367253Z","shell.execute_reply.started":"2025-05-12T20:37:15.044378Z","shell.execute_reply":"2025-05-12T20:37:15.366412Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"paths_train= glob('/kaggle/input/diabetic-retinopathy-train-unzipped/train/*.jpeg')\nimage=cv2.imread(paths_train[0])\nplt.imshow(image)","metadata":{"execution":{"iopub.status.busy":"2024-03-25T17:11:58.976106Z","iopub.execute_input":"2024-03-25T17:11:58.976572Z","iopub.status.idle":"2024-03-25T17:12:01.661992Z","shell.execute_reply.started":"2024-03-25T17:11:58.97654Z","shell.execute_reply":"2024-03-25T17:12:01.661199Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"paths_test = glob('/kaggle/input/diabetic-retinopathy-test-unzipped/test/*.jpeg')\nimage=cv2.imread(paths_test[0])\nplt.imshow(image)","metadata":{"execution":{"iopub.status.busy":"2024-03-25T17:13:36.166215Z","iopub.execute_input":"2024-03-25T17:13:36.166597Z","iopub.status.idle":"2024-03-25T17:13:40.302918Z","shell.execute_reply.started":"2024-03-25T17:13:36.166554Z","shell.execute_reply":"2024-03-25T17:13:40.301867Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"file_sub=\"/kaggle/input/diabetic-retinopathy-detection/sampleSubmission.csv.zip\"\ndf_submission=pd.read_csv(file_sub,sep=',')\ndf_submission.loc[0, 'level']=1\ndf_submission","metadata":{"execution":{"iopub.status.busy":"2024-03-25T17:19:19.607984Z","iopub.execute_input":"2024-03-25T17:19:19.608377Z","iopub.status.idle":"2024-03-25T17:19:19.657295Z","shell.execute_reply.started":"2024-03-25T17:19:19.60833Z","shell.execute_reply":"2024-03-25T17:19:19.656498Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_submission.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2024-03-25T17:20:51.959362Z","iopub.execute_input":"2024-03-25T17:20:51.959787Z","iopub.status.idle":"2024-03-25T17:20:52.050016Z","shell.execute_reply.started":"2024-03-25T17:20:51.959758Z","shell.execute_reply":"2024-03-25T17:20:52.048889Z"},"trusted":true},"outputs":[],"execution_count":null}]}