{"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":"## Préparer l'environement","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":{"execution":{"iopub.status.busy":"2024-09-02T20:22:51.451743Z","iopub.execute_input":"2024-09-02T20:22:51.452018Z","iopub.status.idle":"2024-09-02T20:22:55.387791Z","shell.execute_reply.started":"2024-09-02T20:22:51.451992Z","shell.execute_reply":"2024-09-02T20:22:55.386629Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd\nimport matplotlib.pyplot as plt \nfrom skimage.io import imread\nimport os\nfrom glob import glob ","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:22:55.390215Z","iopub.execute_input":"2024-09-02T20:22:55.391091Z","iopub.status.idle":"2024-09-02T20:22:56.983095Z","shell.execute_reply.started":"2024-09-02T20:22:55.391050Z","shell.execute_reply":"2024-09-02T20:22:56.982090Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data d'entrainement\npaths_train= glob('/kaggle/input/diabetic-retinopathy-train-unzipped/train/*.jpeg')","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:22:56.988053Z","iopub.execute_input":"2024-09-02T20:22:56.988330Z","iopub.status.idle":"2024-09-02T20:22:57.493707Z","shell.execute_reply.started":"2024-09-02T20:22:56.988305Z","shell.execute_reply":"2024-09-02T20:22:57.492834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Les labels\nfile_lbl=\"/kaggle/input/diabetic-retinopathy-detection/trainLabels.csv.zip\"\ndf_train=pd.read_csv(file_lbl,sep=',')\ndf_train","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:22:57.495015Z","iopub.execute_input":"2024-09-02T20:22:57.495711Z","iopub.status.idle":"2024-09-02T20:22:57.546548Z","shell.execute_reply.started":"2024-09-02T20:22:57.495674Z","shell.execute_reply":"2024-09-02T20:22:57.545649Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#répertoire contenant les images d'entrainement\nimage_dir = '/kaggle/input/diabetic-retinopathy-train-unzipped/train/'\n\n# Lister les fichiers d'images\npaths_train = glob(os.path.join(image_dir, '*.jpeg'))\n\n# Lire les labels\nretina_df = pd.read_csv(os.path.join('/kaggle/input/diabetic-retinopathy-train-unzipped', file_lbl))\n\n# Extraire le PatientId et créer le chemin des images\nretina_df['PatientId'] = retina_df['image'].map(lambda x: x.split('_')[0])\nretina_df['path'] = retina_df['image'].map(lambda x: os.path.join(image_dir, '{}.jpeg'.format(x)))\nretina_df['exists'] = retina_df['path'].map(os.path.exists)\nprint(retina_df['exists'].sum(), 'images found of', retina_df.shape[0], 'total')\nretina_df['eye'] = retina_df['image'].map(lambda x: 1 if x.split('_')[-1]=='left' else 0)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:22:57.547861Z","iopub.execute_input":"2024-09-02T20:22:57.548199Z","iopub.status.idle":"2024-09-02T20:23:52.599586Z","shell.execute_reply.started":"2024-09-02T20:22:57.548166Z","shell.execute_reply":"2024-09-02T20:23:52.598615Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.utils import to_categorical\nretina_df['level_cat'] = retina_df['level'].map(lambda x: to_categorical(x, 1+retina_df['level'].max()))\n\nretina_df.dropna(inplace = True)\nretina_df = retina_df[retina_df['exists']]\nretina_df.sample(3)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:23:52.601134Z","iopub.execute_input":"2024-09-02T20:23:52.601517Z","iopub.status.idle":"2024-09-02T20:24:06.395076Z","shell.execute_reply.started":"2024-09-02T20:23:52.601483Z","shell.execute_reply":"2024-09-02T20:24:06.394165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Examine the distribution of eye and severity","metadata":{}},{"cell_type":"code","source":"retina_df[['level', 'eye']].hist(figsize = (10, 5))","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:06.396374Z","iopub.execute_input":"2024-09-02T20:24:06.396918Z","iopub.status.idle":"2024-09-02T20:24:06.929182Z","shell.execute_reply.started":"2024-09-02T20:24:06.396891Z","shell.execute_reply":"2024-09-02T20:24:06.928289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Diviser la data en ensbl d'entrainement et de test","metadata":{}},{"cell_type":"code","source":"import pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.utils import resample\n\n# Supposons que votre dataframe initial s'appelle 'retina_df'\n# et qu'il contient les colonnes 'level' et 'eye'\n\n# Étape 1: Diviser le dataset en ensembles d'entraînement et de validation\nrr_df = retina_df[['PatientId', 'level']].drop_duplicates()\n\ntrain_ids, valid_ids = train_test_split(rr_df['PatientId'], test_size=0.25, random_state=2018, stratify=rr_df['level'])\n\nraw_train_df = retina_df[retina_df['PatientId'].isin(train_ids)]\nvalid_df = retina_df[retina_df['PatientId'].isin(valid_ids)]\n\nprint(f\"train {raw_train_df.shape[0]} validation {valid_df.shape[0]}\")\n\n# Étape 2: Balancer l'ensemble d'entraînement\n# Déterminez le nombre maximum d'échantillons dans chaque classe (level, eye)\nmax_samples = raw_train_df.groupby(['level', 'eye']).size().max()\n\n# Appliquez l'oversampling uniquement sur l'ensemble d'entraînement\nbalanced_train_df = raw_train_df.groupby(['level', 'eye'], as_index=False).apply(\n    lambda x: resample(x, replace=True, n_samples=max_samples, random_state=42)\n).reset_index(drop=True)\n\n# Affichez la taille de la nouvelle distribution dans l'ensemble d'entraînement équilibré\nprint(\"Nouvelle taille de l'ensemble d'entraînement:\", balanced_train_df.shape[0])\n\n# Vérifiez la distribution après l'équilibrage\nbalanced_train_df[['level', 'eye']].hist(figsize=(10, 5))\n\n# L'ensemble de validation reste tel quel, sans équilibrage pour évaluer correctement les performances du modèle\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:06.930564Z","iopub.execute_input":"2024-09-02T20:24:06.931015Z","iopub.status.idle":"2024-09-02T20:24:08.360958Z","shell.execute_reply.started":"2024-09-02T20:24:06.930976Z","shell.execute_reply":"2024-09-02T20:24:08.359988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## augmenter les images dans le cadre de l'entraînement du modèle","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator, load_img, img_to_array\nfrom tensorflow.keras.utils import to_categorical\n\n# Configuration de l'ImageDataGenerator\n# Configuration de l'ImageDataGenerator\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=40,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\nvalid_datagen = ImageDataGenerator(\n    rescale=1./255\n)\n\n# Fonction pour générer les images et les labels\ndef generate_data_from_dataframe(df, datagen, batch_size=32, target_size=(224, 224)):\n    while True:\n        for start in range(0, len(df), batch_size):\n            batch_df = df.iloc[start:start + batch_size]\n            images = []\n            labels = []\n            for _, row in batch_df.iterrows():\n                img = load_img(row['path'], target_size=target_size)\n                img_array = img_to_array(img)\n                images.append(img_array)\n                # Utilisez directement le tableau NumPy comme label\n                labels.append(row['level_cat'])\n            images = np.array(images)\n            labels = np.array(labels)\n            # Directement yield les images et labels transformés\n            # Assurez-vous que shuffle=False dans le datagen.flow si vous contrôlez le mélange ailleurs\n            for x, y in datagen.flow(images, labels, batch_size=batch_size, shuffle=False):\n                yield x, y\n\n# Générateurs pour l'entraînement et la validation\ntrain_generator = generate_data_from_dataframe(raw_train_df, train_datagen, batch_size=32, target_size=(224, 224))\nvalid_generator = generate_data_from_dataframe(valid_df, valid_datagen, batch_size=32, target_size=(224, 224))\n\n# Exemple de génération d'une batch d'images augmentées\nfor images_batch, labels_batch in train_generator:\n    break  # Afficher seulement la première batch","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:08.365722Z","iopub.execute_input":"2024-09-02T20:24:08.366690Z","iopub.status.idle":"2024-09-02T20:24:11.321172Z","shell.execute_reply.started":"2024-09-02T20:24:08.366649Z","shell.execute_reply":"2024-09-02T20:24:11.320399Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training set","metadata":{}},{"cell_type":"code","source":"# Fonction pour visualiser les images augmentées\ndef visualize_augmented_images(generator, batch_size=8):\n    # Obtenir un batch d'images et de labels\n    t_x, t_y = next(generator)\n\n    # Créer une figure avec des sous-graphiques\n    fig, m_axs = plt.subplots(2, 4, figsize=(16, 8))\n    for (c_x, c_y, c_ax) in zip(t_x, t_y, m_axs.flatten()):\n        # Dé-normaliser les images pour la visualisation\n        c_x = np.clip(c_x * 255, 0, 255).astype(np.uint8)\n        # Afficher l'image\n        c_ax.imshow(c_x)\n        # Titre avec la sévérité\n        c_ax.set_title('Severity {}'.format(np.argmax(c_y)))\n        c_ax.axis('off')\n\n    plt.show()\n\n# Visualiser les images augmentées\nvisualize_augmented_images(train_generator)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:11.322267Z","iopub.execute_input":"2024-09-02T20:24:11.322576Z","iopub.status.idle":"2024-09-02T20:24:12.607909Z","shell.execute_reply.started":"2024-09-02T20:24:11.322550Z","shell.execute_reply":"2024-09-02T20:24:12.606992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Validation set","metadata":{}},{"cell_type":"code","source":"def plot_validation_images(valid_gen):\n    v_x, v_y = next(valid_gen)  # Récupère un batch du générateur de validation\n    fig, m_axes = plt.subplots(2, 4, figsize=(16, 8))  # Configure un subplot pour afficher les images\n\n    for (img, label, ax) in zip(v_x, v_y, m_axes.flatten()):\n        # Affiche l'image. Les images sont déjà normalisées, donc pour visualisation, on remet à l'échelle de 0 à 255\n        ax.imshow(np.clip(img * 255, 0, 255).astype(np.uint8))\n        # Détermine la classe de l'image par l'indice du maximum dans le vecteur one-hot\n        ax.set_title('Severity: {}'.format(np.argmax(label)))\n        ax.axis('off')  # Cache les axes pour une meilleure visibilité\n\n    plt.show()\n\n# Appel de la fonction pour visualiser les images de validation\nplot_validation_images(valid_generator)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:12.609057Z","iopub.execute_input":"2024-09-02T20:24:12.609362Z","iopub.status.idle":"2024-09-02T20:24:15.521189Z","shell.execute_reply.started":"2024-09-02T20:24:12.609320Z","shell.execute_reply":"2024-09-02T20:24:15.520245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  Entrainement du modèle","metadata":{}},{"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])\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:15.522368Z","iopub.execute_input":"2024-09-02T20:24:15.522682Z","iopub.status.idle":"2024-09-02T20:24:16.233717Z","shell.execute_reply.started":"2024-09-02T20:24:15.522655Z","shell.execute_reply":"2024-09-02T20:24:16.232839Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam',\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:16.234787Z","iopub.execute_input":"2024-09-02T20:24:16.235065Z","iopub.status.idle":"2024-09-02T20:24:16.247308Z","shell.execute_reply.started":"2024-09-02T20:24:16.235040Z","shell.execute_reply":"2024-09-02T20:24:16.246494Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n    train_generator,\n    steps_per_epoch=len(raw_train_df) // 32,  # Assurez-vous que cela correspond à la taille de votre batch\n    epochs=2,\n    validation_data=valid_generator,\n    validation_steps=len(valid_df) // 32\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:24:16.248606Z","iopub.execute_input":"2024-09-02T20:24:16.249240Z","iopub.status.idle":"2024-09-02T20:32:34.132664Z","shell.execute_reply.started":"2024-09-02T20:24:16.249205Z","shell.execute_reply":"2024-09-02T20:32:34.131814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluation","metadata":{}},{"cell_type":"code","source":"validation_steps = len(valid_df) // 32\n\nloss, accuracy = model.evaluate(valid_generator, steps=validation_steps)\nprint(\"Perte sur l'ensemble de validation:\", loss)\nprint(\"Précision sur l'ensemble de validation:\", accuracy)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:34.134012Z","iopub.execute_input":"2024-09-02T20:32:34.134300Z","iopub.status.idle":"2024-09-02T20:32:38.717782Z","shell.execute_reply.started":"2024-09-02T20:32:34.134274Z","shell.execute_reply":"2024-09-02T20:32:38.716882Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.metrics import Precision, Recall\n\nmodel.compile(optimizer='adam',\n              loss='categorical_crossentropy',\n              metrics=['accuracy', Precision(), Recall()])\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:38.718907Z","iopub.execute_input":"2024-09-02T20:32:38.719190Z","iopub.status.idle":"2024-09-02T20:32:38.737828Z","shell.execute_reply.started":"2024-09-02T20:32:38.719164Z","shell.execute_reply":"2024-09-02T20:32:38.737113Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"metrics = model.evaluate(valid_generator, steps=validation_steps)\nprint(\"Métriques sur l'ensemble de validation:\", metrics)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:38.738788Z","iopub.execute_input":"2024-09-02T20:32:38.739063Z","iopub.status.idle":"2024-09-02T20:32:44.441023Z","shell.execute_reply.started":"2024-09-02T20:32:38.739038Z","shell.execute_reply":"2024-09-02T20:32:44.440011Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Transfer learning","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.applications.inception_v3 import InceptionV3\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D\n\n# Charger InceptionV3 pré-entraîné sur ImageNet sans la dernière couche fully-connected\nbase_model = InceptionV3(weights='imagenet', include_top=False)\n\n# Ajouter de nouvelles couches\nx = base_model.output\nx = GlobalAveragePooling2D()(x)\nx = Dense(1024, activation='relu')(x)\npredictions = Dense(5, activation='softmax')(x)  # num_classes est le nombre de vos classes\n\n# Définir le nouveau modèle\nmodel = Model(inputs=base_model.input, outputs=predictions)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:44.442390Z","iopub.execute_input":"2024-09-02T20:32:44.442771Z","iopub.status.idle":"2024-09-02T20:32:46.939225Z","shell.execute_reply.started":"2024-09-02T20:32:44.442736Z","shell.execute_reply":"2024-09-02T20:32:46.938246Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Geler toutes les couches du modèle de base InceptionV3\nfor layer in base_model.layers:\n    layer.trainable = False\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:46.940540Z","iopub.execute_input":"2024-09-02T20:32:46.940899Z","iopub.status.idle":"2024-09-02T20:32:46.953295Z","shell.execute_reply.started":"2024-09-02T20:32:46.940867Z","shell.execute_reply":"2024-09-02T20:32:46.952395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:46.954653Z","iopub.execute_input":"2024-09-02T20:32:46.955308Z","iopub.status.idle":"2024-09-02T20:32:46.969470Z","shell.execute_reply.started":"2024-09-02T20:32:46.955272Z","shell.execute_reply":"2024-09-02T20:32:46.968588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(\n    train_generator,\n    steps_per_epoch=len(raw_train_df) // 32,\n    epochs=5,  \n    validation_data=valid_generator,\n    validation_steps=len(valid_df) // 32\n)\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:32:46.970583Z","iopub.execute_input":"2024-09-02T20:32:46.970908Z","iopub.status.idle":"2024-09-02T20:54:29.051980Z","shell.execute_reply.started":"2024-09-02T20:32:46.970881Z","shell.execute_reply":"2024-09-02T20:54:29.051029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for layer in base_model.layers:\n    layer.trainable = True\n\n# Recompiler le modèle pour que les modifications prennent effet\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\n\n# Continuer l'entraînement\nhistory_fine = model.fit(\n    train_generator,\n    steps_per_epoch=len(raw_train_df) // 32,\n    epochs=3,\n    validation_data=valid_generator,\n    validation_steps=len(valid_df) // 32\n)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T20:54:29.053655Z","iopub.execute_input":"2024-09-02T20:54:29.053962Z","iopub.status.idle":"2024-09-02T21:08:55.998372Z","shell.execute_reply.started":"2024-09-02T20:54:29.053932Z","shell.execute_reply":"2024-09-02T21:08:55.997577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"validation_steps = len(valid_df) // 32\nloss, accuracy = model.evaluate(valid_generator, steps=validation_steps)\nprint(\"Perte sur l'ensemble de validation:\", loss)\nprint(\"Précision sur l'ensemble de validation:\", accuracy)","metadata":{"execution":{"iopub.status.busy":"2024-09-02T21:08:56.000280Z","iopub.execute_input":"2024-09-02T21:08:56.000935Z","iopub.status.idle":"2024-09-02T21:09:09.804513Z","shell.execute_reply.started":"2024-09-02T21:08:56.000899Z","shell.execute_reply":"2024-09-02T21:09:09.803621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nfrom sklearn.metrics import classification_report, confusion_matrix\n\n# Initialiser les listes pour stocker les prédictions et les vraies classes\nall_predictions = []\nall_true_labels = []\n\n# Itérer sur le générateur de validation pour collecter les prédictions\nfor x_batch, y_batch in valid_generator:\n    predictions = model.predict(x_batch)\n    predicted_classes = np.argmax(predictions, axis=1)\n    true_classes = np.argmax(y_batch, axis=1)\n    \n    # Ajouter les résultats dans les listes\n    all_predictions.extend(predicted_classes)\n    all_true_labels.extend(true_classes)\n    \n    # Stopper une fois que vous avez suffisamment de données (sinon cela continue indéfiniment)\n    if len(all_true_labels) >= len(valid_df):\n        break\n\n# Convertir les listes en array pour facilité d'usage avec scikit-learn\nall_predictions = np.array(all_predictions)\nall_true_labels = np.array(all_true_labels)\n\n# Calculer la matrice de confusion et le rapport de classification\nprint(\"Matrice de confusion :\")\nprint(confusion_matrix(all_true_labels, all_predictions))\nprint(\"\\nRapport de classification :\")\nprint(classification_report(all_true_labels, all_predictions))\n","metadata":{"execution":{"iopub.status.busy":"2024-09-02T21:09:09.805739Z","iopub.execute_input":"2024-09-02T21:09:09.805998Z","iopub.status.idle":"2024-09-02T21:09:51.569649Z","shell.execute_reply.started":"2024-09-02T21:09:09.805975Z","shell.execute_reply":"2024-09-02T21:09:51.568643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('mon_modele.h5')","metadata":{"execution":{"iopub.status.busy":"2024-09-02T21:14:04.323341Z","iopub.execute_input":"2024-09-02T21:14:04.324198Z","iopub.status.idle":"2024-09-02T21:14:05.392320Z","shell.execute_reply.started":"2024-09-02T21:14:04.324166Z","shell.execute_reply":"2024-09-02T21:14:05.391415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('transfer_model.h5')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}