{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:51:35.431241Z","iopub.execute_input":"2026-10-09T09:51:35.43211Z","iopub.status.idle":"2026-10-09T09:51:36.653682Z","shell.execute_reply.started":"2026-10-09T09:51:35.43206Z","shell.execute_reply":"2026-10-09T09:51:36.653059Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 1 - Importation et analyse du dataset","metadata":{}},{"cell_type":"code","source":"# Download latest version\npath = kagglehub.competition_download('dogs-vs-cats')\n\nprint(\"Path to competition files:\", path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:51:39.990303Z","iopub.execute_input":"2026-10-09T09:51:39.990694Z","iopub.status.idle":"2026-10-09T09:51:40.502878Z","shell.execute_reply.started":"2026-10-09T09:51:39.990674Z","shell.execute_reply":"2026-10-09T09:51:40.502304Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On importe nos données et on les dézippent dans notre environnement.","metadata":{}},{"cell_type":"code","source":"import zipfile\n\n# Chemin d'accès au fichier zip de Kaggle\nchemin_zip = '/kaggle/input/competitions/dogs-vs-cats/train.zip'\n\n# Extraction dans le dossier de travail modifiable\nwith zipfile.ZipFile(chemin_zip, 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/')\n\n# Chemin d'accès au fichier zip de Kaggle\nchemin_zip = '/kaggle/input/competitions/dogs-vs-cats/test1.zip'\n\n# Extraction dans le dossier de travail modifiable\nwith zipfile.ZipFile(chemin_zip, 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:51:42.612374Z","iopub.execute_input":"2026-10-09T09:51:42.612632Z","iopub.status.idle":"2026-10-09T09:51:55.586974Z","shell.execute_reply.started":"2026-10-09T09:51:42.612613Z","shell.execute_reply":"2026-10-09T09:51:55.586387Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On affiches les premières photos de chiens et de chats pour vérifier le dataset.","metadata":{}},{"cell_type":"code","source":"# plot dog photos from the dogs vs cats dataset\nfrom matplotlib import pyplot\nfrom matplotlib.image import imread\n# define location of dataset\nfolder = '/kaggle/working/train/'\n# plot first few images\nfor i in range(9):\n\t# define subplot\n\tpyplot.subplot(330 + 1 + i)\n\t# define filename\n\tfilename = folder + 'dog.' + str(i) + '.jpg'\n\t# load image pixels\n\timage = imread(filename)\n\t# plot raw pixel data\n\tpyplot.imshow(image)\n# show the figure\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:51:56.254477Z","iopub.execute_input":"2026-10-09T09:51:56.254779Z","iopub.status.idle":"2026-10-09T09:51:56.839525Z","shell.execute_reply.started":"2026-10-09T09:51:56.25476Z","shell.execute_reply":"2026-10-09T09:51:56.838933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot cat photos from the dogs vs cats dataset\n# define location of dataset\nfolder = 'train/'\n# plot first few images\nfor i in range(9):\n\t# define subplot\n\tpyplot.subplot(330 + 1 + i)\n\t# define filename\n\tfilename = folder + 'cat.' + str(i) + '.jpg'\n\t# load image pixels\n\timage = imread(filename)\n\t# plot raw pixel data\n\tpyplot.imshow(image)\n# show the figure\npyplot.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:52:00.591852Z","iopub.execute_input":"2026-10-09T09:52:00.592499Z","iopub.status.idle":"2026-10-09T09:52:01.120748Z","shell.execute_reply.started":"2026-10-09T09:52:00.592468Z","shell.execute_reply":"2026-10-09T09:52:01.119758Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On remarque que les images ne font pas toutes la même taille et que sur certaines le chat est à peine visible.","metadata":{}},{"cell_type":"markdown","source":"# 2 - Pre-Processing et formatage des images\n\nOn utilise ici l'option alternative pour des raisons de performances. On réorganise les données dans deux nouveaux dataset test et train. On récupère les 25 000 données du dossier train et on le sépare en 75% de données pour l'entrainement et 25% pour la validation.","metadata":{}},{"cell_type":"code","source":"# organize dataset into a useful structure\nfrom os import makedirs\nfrom os import listdir\nfrom shutil import copyfile\nfrom random import seed\nfrom random import random\n# create directories\ndataset_home = 'dataset_dogs_vs_cats/'\nsubdirs = ['train/', 'test/']\nfor subdir in subdirs:\n\t# create label subdirectories\n\tlabeldirs = ['dogs/', 'cats/']\n\tfor labldir in labeldirs:\n\t\tnewdir = dataset_home + subdir + labldir\n\t\tmakedirs(newdir, exist_ok=True)\n# seed random number generator\nseed(1)\n# define ratio of pictures to use for validation\nval_ratio = 0.25\n# copy training dataset images into subdirectories\nsrc_directory = 'train/'\nfor file in listdir(src_directory):\n\tsrc = src_directory + '/' + file\n\tdst_dir = 'train/'\n\tif random() < val_ratio:\n\t\tdst_dir = 'test/'\n\tif file.startswith('cat'):\n\t\tdst = dataset_home + dst_dir + 'cats/'  + file\n\t\tcopyfile(src, dst)\n\telif file.startswith('dog'):\n\t\tdst = dataset_home + dst_dir + 'dogs/'  + file\n\t\tcopyfile(src, dst)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T09:52:08.808728Z","iopub.execute_input":"2026-10-09T09:52:08.809493Z","iopub.status.idle":"2026-10-09T09:52:10.777623Z","shell.execute_reply.started":"2026-10-09T09:52:08.809459Z","shell.execute_reply":"2026-10-09T09:52:10.777027Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# 3 - Baseline CNN Model\n\n## 3.1 - One Block VGG Model\n\nOn commence avec un modele qui possede une seule couche convolutive. Ce modele va servir de référence pour comparer les performances avec les modeles suivant.","metadata":{}},{"cell_type":"code","source":"import sys\nimport tensorflow as tf\nfrom matplotlib import pyplot\nfrom keras.models import Sequential\nfrom keras.layers import Input, Conv2D, MaxPooling2D, Dense, Flatten, Rescaling\nfrom keras.optimizers import SGD\n\n# Pour cette partie on défini le nombre d'epochs à 20\nepochs = 20\n\ndef define_model():\n\tmodel = Sequential()\n\tmodel.add(Input(shape=(200, 200, 3)))\n\tmodel.add(Rescaling(1./255))\n\t\n\tmodel.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n\tmodel.add(MaxPooling2D((2, 2)))\n\tmodel.add(Flatten())\n\tmodel.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n\tmodel.add(Dense(1, activation='sigmoid'))\n\t\n\topt = SGD(learning_rate=0.001, momentum=0.9)\n\tmodel.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n\treturn model\n\ndef summarize_diagnostics(history):\n\t# plot loss\n\tpyplot.subplot(211)\n\tpyplot.title('Cross Entropy Loss')\n\tpyplot.plot(history.history['loss'], color='blue', label='train')\n\tpyplot.plot(history.history['val_loss'], color='orange', label='test')\n\tpyplot.legend()\n\n\t# plot accuracy\n\tpyplot.subplot(212)\n\tpyplot.title('Classification Accuracy')\n\tpyplot.plot(history.history['accuracy'], color='blue', label='train')\n\tpyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n\tpyplot.legend()\n    \n\tpyplot.tight_layout()\n\n\t# save plot to file\n\tfilename = sys.argv[0].split('/')[-1]\n\tpyplot.savefig(filename + '_plot.png')\n\tpyplot.show()\n\tpyplot.close()\n\ndef run_test_harness():\n\tmodel = define_model()\n\t\n\ttrain_it = tf.keras.utils.image_dataset_from_directory(\n\t\t'/kaggle/working/dataset_dogs_vs_cats/train/',\n\t\tlabels='inferred',\n\t\tlabel_mode='binary',\n\t\timage_size=(200, 200),\n\t\tbatch_size=64\n\t)\n\n\ttest_it = tf.keras.utils.image_dataset_from_directory(\n\t\t'/kaggle/working/dataset_dogs_vs_cats/test/',\n\t\tlabels='inferred',\n\t\tlabel_mode='binary',\n\t\timage_size=(200, 200),\n\t\tbatch_size=64\n\t)\n\t\n\thistory = model.fit(train_it, validation_data=test_it, epochs=epochs, verbose=1)\n\t_, acc = model.evaluate(test_it, verbose=0)\n\tprint('> %.3f' % (acc * 100.0))\n\tsummarize_diagnostics(history)\n\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T10:08:39.134095Z","iopub.execute_input":"2026-10-07T10:08:39.134903Z","iopub.status.idle":"2026-10-07T10:13:50.342286Z","shell.execute_reply.started":"2026-10-07T10:08:39.134873Z","shell.execute_reply":"2026-10-07T10:13:50.341345Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"A la fin de l'entrainement de notre premier modele on obtient une précision sur le jeu de donnée d'environ 73.5%. On remarque que la précision était de 88% sur le dataset d'entrainement il y a peu être un début d'overfiting. On le remarque aussi sur l'erreur sur le modele de test qui stagne au bout de 5 epochs.","metadata":{}},{"cell_type":"markdown","source":"## 3.2 - Two Block VGG Model\n\nOn rajoute une couche convolutive au modele.","metadata":{}},{"cell_type":"code","source":"# define cnn model\ndef define_model():\n    model = Sequential()\n    model.add(Input(shape=(200, 200, 3)))\n    model.add(Rescaling(1./255))\n    \n    model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Flatten())\n    model.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n    model.add(Dense(1, activation='sigmoid'))\n    \n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    \n    return model\n\n# On relance avec notre nouveau modele\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T10:38:32.238626Z","iopub.execute_input":"2026-10-07T10:38:32.239178Z","iopub.status.idle":"2026-10-07T10:46:28.733376Z","shell.execute_reply.started":"2026-10-07T10:38:32.239149Z","shell.execute_reply":"2026-10-07T10:46:28.732589Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"A la fin de l'entrainement de notre deuxième modele on obtient une précision sur le jeu de donnée d'environ 75.6%. Il y a donc une petite amélioration. Malheuresement on remarque que le modele fait encore plus d'overfiting avec une précision de presque 97% sur les données d'entrainement mais une erreur sur le jeu de test qui augmente au fil des epochs et qui reste aussi élevé à la fin que pour le modele 1.","metadata":{}},{"cell_type":"markdown","source":"## 3.3 - Three Block VGG Model\n\nOn ajoute une troisième couche convolutive au modele comme dans le tutoriel même ça ne va pas arranger notre problème d'overfiting.","metadata":{}},{"cell_type":"code","source":"# define cnn model\ndef define_model():\n    model = Sequential()\n    model.add(Input(shape=(200, 200, 3)))\n    model.add(Rescaling(1./255))\n    \n    model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Flatten())\n    model.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n    model.add(Dense(1, activation='sigmoid'))\n    \n    # compile model\n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    return model\n\n# On relance avec notre nouveau modele\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-07T10:53:17.721437Z","iopub.execute_input":"2026-10-07T10:53:17.721832Z","iopub.status.idle":"2026-10-07T11:03:02.356543Z","shell.execute_reply.started":"2026-10-07T10:53:17.721805Z","shell.execute_reply":"2026-10-07T11:03:02.355553Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"A la fin de l'entrainement de notre troisième modele on obtient une précision sur le jeu de donnée d'environ 78.2%. On observe encore une petite amélioration. Le modele fait toujours de l'overfiting comme on s'y attendait avec une précision trés élevé sur le jeu d'entrainement, et une erreur sur le jeu de test un tout petit peu plus faible mais qui continu de stagner au cours des épochs.","metadata":{}},{"cell_type":"markdown","source":"## 3.4 - Results\n\nEn résumé voici les résultats des 3 modeles différents :\n* VGG 1 : 73.536%\n* VGG 2 : 75.662%\n* VGG 3 : 78.248%\n\nAvec ces tests nous avons réussi à augmenter légérement notre précision en rajoutant des couches convolutives. Mais durant ces 3 tests nous avons eu le même problème récurrent d'overfiting. Dans les modeles suivant nous devrons donc essayer de résoudre ce problème avec des techniques de régularisations comme avec du dropout par exemple.","metadata":{}},{"cell_type":"markdown","source":"# 4 - Develop Model Improvements\n\n## 4.1 - Dropout Regularization\n\nOn garde notre modèle avec les 3 couches convolutives et on va y implémenter des couches de dropout entre les couches existantes pour essayer d'éviter au modèle d'être trop surapprendre notre jeu d'entrainement.\n\nOn implémente donc :\n* Une couche de dropout de 20% entre chaque couches convolutive\n* Une couche de dropout de 50% juste avant la couche finale","metadata":{}},{"cell_type":"markdown","source":"**Tips :** la partie du code suivante est à exécuter seulement si on a pas lancé la partie 3 Baseline CNN Model (si on ne voulait pas réentrainner les 3 modèles de base).","metadata":{}},{"cell_type":"code","source":"# code falcutatif\nimport sys\nimport tensorflow as tf\nfrom matplotlib import pyplot\nfrom keras.models import Sequential\nfrom keras.layers import Input, Conv2D, MaxPooling2D, Dense, Flatten, Rescaling\nfrom keras.optimizers import SGD\n\ndef define_model():\n    return model\n\ndef summarize_diagnostics(history):\n\t# plot loss\n\tpyplot.subplot(211)\n\tpyplot.title('Cross Entropy Loss')\n\tpyplot.plot(history.history['loss'], color='blue', label='train')\n\tpyplot.plot(history.history['val_loss'], color='orange', label='test')\n\tpyplot.legend()\n\n\t# plot accuracy\n\tpyplot.subplot(212)\n\tpyplot.title('Classification Accuracy')\n\tpyplot.plot(history.history['accuracy'], color='blue', label='train')\n\tpyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n\tpyplot.legend()\n    \n\tpyplot.tight_layout()\n\n\t# save plot to file\n\tfilename = sys.argv[0].split('/')[-1]\n\tpyplot.savefig(filename + '_plot.png')\n\tpyplot.show()\n\tpyplot.close()\n\ndef run_test_harness():\n\tmodel = define_model()\n\t\n\ttrain_it = tf.keras.utils.image_dataset_from_directory(\n\t\t'/kaggle/working/dataset_dogs_vs_cats/train/',\n\t\tlabels='inferred',\n\t\tlabel_mode='binary',\n\t\timage_size=(200, 200),\n\t\tbatch_size=64\n\t)\n\n\ttest_it = tf.keras.utils.image_dataset_from_directory(\n\t\t'/kaggle/working/dataset_dogs_vs_cats/test/',\n\t\tlabels='inferred',\n\t\tlabel_mode='binary',\n\t\timage_size=(200, 200),\n\t\tbatch_size=64\n\t)\n\t\n\thistory = model.fit(train_it, validation_data=test_it, epochs=epochs, verbose=1)\n\t_, acc = model.evaluate(test_it, verbose=0)\n\tprint('> %.3f' % (acc * 100.0))\n\tsummarize_diagnostics(history)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T08:23:08.08099Z","iopub.execute_input":"2026-10-09T08:23:08.081768Z","iopub.status.idle":"2026-10-09T08:23:08.089288Z","shell.execute_reply.started":"2026-10-09T08:23:08.081738Z","shell.execute_reply":"2026-10-09T08:23:08.088668Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from keras.layers import Dropout\n\n# On augmente le nombre d'epochs à 50\nepochs = 50\n\n# define cnn model\ndef define_model():\n    model = Sequential()\n    model.add(Input(shape=(200, 200, 3)))\n    model.add(Rescaling(1./255))\n    \n    model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Dropout(0.2))\n    model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Dropout(0.2))\n    model.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Dropout(0.2))\n    model.add(Flatten())\n    model.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n    model.add(Dropout(0.5))\n    model.add(Dense(1, activation='sigmoid'))\n    # compile model\n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    return model\n\n# On relance avec notre nouveau modele\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T10:39:48.893665Z","iopub.execute_input":"2026-10-08T10:39:48.894394Z","iopub.status.idle":"2026-10-08T11:04:09.943992Z","shell.execute_reply.started":"2026-10-08T10:39:48.894368Z","shell.execute_reply":"2026-10-08T11:04:09.943156Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On remarque à la fin de notre entrainement une légère augmentation des performances avec une précision à 81.5%. Mais surtout ce qu'on l'on remarque ici c'est que les courbes sur notre jeu de données de test ont une progression positive au cours des epochs et ne commence à stagner que au bout d'environ 40 epochs.\nMalgrès tout cela reste des suppositions et nécéssite un certains cout d'augmenter le nombre d'epochs. On doit pouvoir essayer ","metadata":{}},{"cell_type":"markdown","source":"## 4.2 - Image Data Augmentation\n\nOn va augmenter notre nombre de données dans le dataset. Pour cela on va dupliquer des photos et leur appliquer un changement comme une symétrie, une rotation etc.\n\nModification par rapport au tutoriel la data augmentation se fait dans le modele suite à un changement de logique de keras.","metadata":{}},{"cell_type":"code","source":"from keras.layers import RandomFlip, RandomTranslation\n\n# run the test harness for evaluating a model\ndef run_test_harness():\n    model = define_model()\n    \n    train_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/train/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(200, 200),\n        batch_size=64\n    )\n    test_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/test/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(200, 200),\n        batch_size=64\n    )    \n    history = model.fit(train_it, validation_data=test_it, epochs=50, verbose=1)\n    \n    _, acc = model.evaluate(test_it, verbose=0)\n    print('> %.3f' % (acc * 100.0))\n    summarize_diagnostics(history)\n\n# define cnn model\ndef define_model():\n    model = Sequential()\n    model.add(Input(shape=(200, 200, 3)))\n    #Data Augmentation\n    model.add(RandomFlip(\"horizontal\"))\n    model.add(RandomTranslation(height_factor=0.1, width_factor=0.1))\n    \n    model.add(Rescaling(1./255))\n    \n    model.add(Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same', input_shape=(200, 200, 3)))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_uniform', padding='same'))\n    model.add(MaxPooling2D((2, 2)))\n    model.add(Flatten())\n    model.add(Dense(128, activation='relu', kernel_initializer='he_uniform'))\n    model.add(Dense(1, activation='sigmoid'))\n    # compile model\n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    return model\n \n# entry point, run the test harness\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T11:34:24.662806Z","iopub.execute_input":"2026-10-08T11:34:24.663341Z","iopub.status.idle":"2026-10-08T11:55:46.077955Z","shell.execute_reply.started":"2026-10-08T11:34:24.663315Z","shell.execute_reply":"2026-10-08T11:55:46.076973Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On obtient une nette amélioration avec un score de 86.15%. De plus on oberserve bien que les courbes pour le set d'entrainement et de test se suivent. C'est très encourgeant et cela laisse penser qu'on peut augmenter les performances du modèle en augmentant le nombre d'epochs.","metadata":{}},{"cell_type":"markdown","source":"## 4.3 - Results\n\nEn résumé voici les résultats des 2 modèles différents :\n* VGG 3 + Dropout : 81.517%\n* VGG 3 + Data Augmentation : 86.149%\n\nCes 2 tests nous ont permis d'améliorer le modèle (en augmentant aussi le nombre d'epochs pour voir une nette amélioration). Nous avons réussi a éliminer l'overfiting ce qui as permis d'améliorer la précision sur notre jeu de test.","metadata":{}},{"cell_type":"markdown","source":"# 5 - Explore Transfer Learning\n\nDans cette partie nous allons utiliser un modèle déjà préfait VGG16 et on va l'adapter à notre classification. Le modèle étant plus long et gourmant à faire tourner nous allons réduire les epochs à 10.\n\n**Tips :** la partie du code suivante est à exécuter seulement si on a pas lancé la partie 3 ou 4  car ces fonctions sont déjà défini.","metadata":{}},{"cell_type":"code","source":"# Facultatif\nimport sys\nimport tensorflow as tf\nfrom matplotlib import pyplot\nfrom keras.models import Sequential\nfrom keras.utils import to_categorical\nfrom keras.layers import Input, Conv2D, MaxPooling2D, Dense, Flatten, Rescaling\nfrom keras.optimizers import SGD\n\ndef define_model():\n    return model\n\n# plot diagnostic learning curves\ndef summarize_diagnostics(history):\n    # plot loss\n    pyplot.subplot(211)\n    pyplot.title('Cross Entropy Loss')\n    pyplot.plot(history.history['loss'], color='blue', label='train')\n    pyplot.plot(history.history['val_loss'], color='orange', label='test')\n    # plot accuracy\n    pyplot.subplot(212)\n    pyplot.title('Classification Accuracy')\n    pyplot.plot(history.history['accuracy'], color='blue', label='train')\n    pyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n    # save plot to file\n    filename = sys.argv[0].split('/')[-1]\n    pyplot.savefig(filename + '_plot.png')\n    pyplot.show()\n    pyplot.close()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T10:01:39.936016Z","iopub.execute_input":"2026-10-09T10:01:39.936527Z","iopub.status.idle":"2026-10-09T10:01:39.943308Z","shell.execute_reply.started":"2026-10-09T10:01:39.9365Z","shell.execute_reply":"2026-10-09T10:01:39.942438Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Notre modèle que nous allons faire tourner et la fonction qui permet de run qui doit aussi être adapté.","metadata":{}},{"cell_type":"code","source":"from keras.applications.vgg16 import VGG16\nfrom keras.models import Model\n\n# On définit les epochs à 10\nepochs = 10\n\n# run the test harness for evaluating a model\ndef run_test_harness():\n    model = define_model()\n    \n    train_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/train/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(224, 224),\n        batch_size=64\n    )\n\n    test_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/test/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(224, 224),\n        batch_size=64\n    )\n    \n    from keras.applications.vgg16 import preprocess_input\n    train_it = train_it.map(lambda x, y: (preprocess_input(x), y))\n    test_it = test_it.map(lambda x, y: (preprocess_input(x), y))\n    \n    history = model.fit(train_it, validation_data=test_it, epochs=epochs, verbose=1)    \n    _, acc = model.evaluate(test_it, verbose=0)\n    print('> %.3f' % (acc * 100.0))\n    summarize_diagnostics(history)\n\n# define cnn model\ndef define_model():\n\t# load model\n    img_input = Input(shape=(224, 224, 3))\n    model = VGG16(include_top=False, input_tensor=img_input)\n\t# mark loaded layers as not trainable\n    for layer in model.layers:\n        layer.trainable = False\n    # add new classifier layers\n    flat1 = Flatten()(model.layers[-1].output)\n    class1 = Dense(128, activation='relu', kernel_initializer='he_uniform')(flat1)\n    output = Dense(1, activation='sigmoid')(class1)\n    # define new model\n    model = Model(inputs=model.inputs, outputs=output)\n    # compile model\n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    return model\n\n# entry point, run the test harness\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T10:01:45.695248Z","iopub.execute_input":"2026-10-09T10:01:45.695529Z","iopub.status.idle":"2026-10-09T10:26:35.238023Z","shell.execute_reply.started":"2026-10-09T10:01:45.69551Z","shell.execute_reply":"2026-10-09T10:26:35.237437Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"On observe un écart massif des performances ici. On obtient une précision de 98.46%. L'utilisation de l'architecture VGG16 a radicalement changé la donne. En réutilisant un modèle déjà entraîné sur des millions d'images (ImageNet), nous avons pu atteindre une précision exceptionnelle de plus de 98,35% dès la toute première époque. \n\nMalgrès tout la courbe de test stagne car le modèle atteint une très bonne performance presque instantanément. Les 10 epochs était peut être un peu trop on pouvait se limiter à moins.","metadata":{}},{"cell_type":"markdown","source":"# 6 - Final Model\n\nNous allons cette fois enregistré notre modele pour pouvoir faire des prédictions. Comme nous avons vu dans les résultats précédent l'entrainement du modèle 10 epochs c'est beaucoup de ressources utilisé pour de maigre améliorations de performances. C'est pour cela qu'ici nous allons réduire à seulement 3 epochs.","metadata":{}},{"cell_type":"code","source":"import sys\nimport tensorflow as tf\nfrom matplotlib import pyplot\nfrom keras.applications.vgg16 import VGG16, preprocess_input\nfrom keras.models import Model\nfrom keras.layers import Input, Flatten, Dense\nfrom keras.optimizers import SGD\n\n# 3 épochs suffisent selon nos anciens résultats\nepochs = 3\n\ndef define_model():\n    img_input = Input(shape=(224, 224, 3))\n    model = VGG16(include_top=False, input_tensor=img_input)\n    \n    for layer in model.layers:\n        layer.trainable = False\n        \n    flat1 = Flatten()(model.layers[-1].output)\n    class1 = Dense(128, activation='relu', kernel_initializer='he_uniform')(flat1)\n    output = Dense(1, activation='sigmoid')(class1)\n    \n    model = Model(inputs=model.inputs, outputs=output)\n    opt = SGD(learning_rate=0.001, momentum=0.9)\n    model.compile(optimizer=opt, loss='binary_crossentropy', metrics=['accuracy'])\n    return model\n\ndef summarize_diagnostics(history):\n    pyplot.subplot(211)\n    pyplot.title('Cross Entropy Loss')\n    pyplot.plot(history.history['loss'], color='blue', label='train')\n    pyplot.plot(history.history['val_loss'], color='orange', label='test')\n    pyplot.legend()\n\n    pyplot.subplot(212)\n    pyplot.title('Classification Accuracy')\n    pyplot.plot(history.history['accuracy'], color='blue', label='train')\n    pyplot.plot(history.history['val_accuracy'], color='orange', label='test')\n    pyplot.legend()\n    \n    pyplot.tight_layout()\n    pyplot.savefig('vgg16_final_plot.png')\n    pyplot.show()\n    pyplot.close()\n\ndef run_test_harness():\n    model = define_model()\n    \n    train_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/train/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(224, 224),\n        batch_size=64\n    )\n\n    test_it = tf.keras.utils.image_dataset_from_directory(\n        '/kaggle/working/dataset_dogs_vs_cats/test/',\n        labels='inferred',\n        label_mode='binary',\n        image_size=(224, 224),\n        batch_size=64\n    )\n    \n    train_it = train_it.map(lambda x, y: (preprocess_input(x), y))\n    test_it = test_it.map(lambda x, y: (preprocess_input(x), y))\n    \n    history = model.fit(train_it, validation_data=test_it, epochs=epochs, verbose=1)\n    \n    _, acc = model.evaluate(test_it, verbose=0)\n    print('> Précision finale : %.3f%%' % (acc * 100.0))\n    \n    summarize_diagnostics(history)\n    \n    # Sauvegarde du modele\n    model.save('/kaggle/working/final_model.keras')\n    print(\"Modèle sauvegardé avec succès dans /kaggle/working/final_model.keras\")\n\n# Lancement\nrun_test_harness()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T10:44:56.873257Z","iopub.execute_input":"2026-10-09T10:44:56.873703Z","iopub.status.idle":"2026-10-09T10:52:40.372898Z","shell.execute_reply.started":"2026-10-09T10:44:56.873678Z","shell.execute_reply":"2026-10-09T10:52:40.372221Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Notre modèle s'est bien entrainé et même avec seulement 3 epochs nous avons une précision de 98.33%.","metadata":{}},{"cell_type":"markdown","source":"# 7 - Prediction\n\nNous allons tester notre modèle avec une photo de chien issu du tutoriel.","metadata":{}},{"cell_type":"code","source":"# make a prediction for a new image.\nfrom keras.preprocessing.image import load_img\nimport matplotlib.pyplot as plt\nfrom keras.preprocessing.image import img_to_array\nfrom keras.models import load_model\n\n# load and prepare the image\ndef load_image(filename):\n\t# load the image\n\timg = load_img(filename, target_size=(224, 224))\n\t# convert to array\n\timg = img_to_array(img)\n\t# reshape into a single sample with 3 channels\n\timg = img.reshape(1, 224, 224, 3)\n\t# center pixel data\n\timg = img.astype('float32')\n\timg = img - [123.68, 116.779, 103.939]\n\treturn img\n\n# load an image and predict the class\ndef run_example():\n    img_path = '/kaggle/input/datasets/nathanpoireault/test-dog/sample_image.jpg'\n    # load the image\n    img = load_image(img_path)\n    # load model\n    model = load_model('/kaggle/working/final_model.keras')\n    # predict the class\n    prediction = model.predict(img)[0][0]\n    \n    # Interprétation (cats = 0, dogs = 1)\n    classe = \"Chien\" if prediction > 0.5 else \"Chat\"\n    confiance = prediction if prediction > 0.5 else (1 - prediction)\n    \n    # Affichage du résultat\n    plt.imshow(load_img(img_path))\n    plt.title(f\"Résultat : {classe} ({confiance * 100:.2f}%)\")\n    plt.axis('off')\n    plt.show()\n\n# entry point, run the example\nrun_example()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-09T11:15:02.494338Z","iopub.execute_input":"2026-10-09T11:15:02.49477Z","iopub.status.idle":"2026-10-09T11:15:03.673227Z","shell.execute_reply.started":"2026-10-09T11:15:02.494743Z","shell.execute_reply":"2026-10-09T11:15:03.672612Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Results\n\nNous avons utilisé notre modèle VGG16 qui as un score de 98.33% pour prédire.\n\nNotre modèle a prédit correctement notre photo de chien. Après nous avons testé notre modèle sur une seule image. De plus l'image est plutot claire, elle n'est pas floue, le chien est en grand en plein milieu de la photo il n'y a pas d'autres objets qui gênant qui pourrait cacher le chien.","metadata":{}}]}