{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"#**Projet Optimisation**\nPar Driss Rahmani et Alexis Guyonvarch","metadata":{"id":"L-Quy8vpEnXM"}},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##**0. Introduction**\n\nDans le cadre du projet du Module *Deep Learning*, nous avons choisi de travailler sur un projet de reconnaissance d'images à partir du *dataset* `Skin Cancer: Malignant vs. Benign` publié sur le portail  **_[Kaggle](https://www.kaggle.com/fanconic/skin-cancer-malignant-vs-benign)_**.\n\nLe cancer de la peau est la tumeur maligne humaine la plus courante. Elle est principalement diagnostiquée à l'issue d'un examen visuel en commençant par un dépistage clinique, éventuellement suivi d'une analyse dermoscopique, d'une biopsie et d'un examen histopathologique. La classification automatisée des lésions cutanées à l'aide d'images est une tâche difficile en raison de la variabilité fine de l'apparence des lésions cutanées.\n\nL'ensemble de données est extrait des archives ISIC (International Skin Image Collaboration). Il se compose de 224 images de grains de beauté bénins et de 264 images de grains de beauté malins classés. Les images ont toutes été redimensionnées en RVB basse résolution (224x224x3). L'objectif est de créer un modèle, qui peut classer visuellement un grain de beauté en bénin et malin.\n\n\n\nIl a 2 classes différentes de cancer de la peau qui sont énumérées ci-dessous:\n\nBénin\nMalin\nDans ce étude , on va essayer de détecter 2 classes différentes de grains de beauté en utilisant le réseau neuronal de convolution avec keras tensorflow , puis analyser le résultat pour voir comment le modèle peut être utile dans un scénario pratique.\n\n\n\n###*Contenu*\nCe *dataset* contient 2 dossiers, `train` et `test` de près de 3300 images en couleurs. La dimension de chacune d'entre elles, mesurée en pixels, est de 224 x 244.\n###*Classification d'images*\nLes images sont des clichés de tumeurs bénignes ou malignes de la peau. Celles-ci sont classées dans chacun des dossiers en fonction du caractère malin ou bénin (labels `benign` et `malignant`) de la tumeur. Comme indiqué plus haut, le *dataset* est équilibré, chaque dossier contenant 1800 images.\n###*Plan*\nLa première partie du projet sera consacrée aux pré traitements. Nous construirons ensuite différentes architectures appliquées au jeu de données. Nous terminerons par une synthèse des résultats en guise de conclusion.\n","metadata":{"id":"Zo8jv-wFE92r"}},{"cell_type":"markdown","source":"**Import des packages**","metadata":{"id":"fJw2xudMdGQk"}},{"cell_type":"code","source":"%matplotlib inline\n#%load_ext autoreload\n#%autoreload 2\n%config IPCompleter.greedy=True\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nimport seaborn as sns\nimport math\nimport os\nimport warnings\nimport cv2\nfrom glob import glob\nfrom PIL import Image\n#from google.colab.patches import cv2_imshow\nimport matplotlib.pyplot as plt\nimport itertools\nimport matplotlib.image as mpimg\nfrom keras.applications import  VGG19\nfrom sklearn.model_selection import train_test_split\nfrom skimage.io import imread\nfrom skimage.transform import resize\nfrom tqdm import tqdm\nfrom keras.utils.np_utils import to_categorical\nfrom keras import backend as K\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom matplotlib import rcParams\nfrom keras import layers\nfrom keras import models\nfrom keras import optimizers\nfrom sklearn.metrics import confusion_matrix\nfrom sklearn.metrics import roc_auc_score, auc\nfrom sklearn.metrics import roc_curve\n#from tensorflow.keras.applications import EfficientNetB0\nfrom keras.applications.resnet50 import ResNet50","metadata":{"id":"Ak_6t0CuFQD3","outputId":"616b2950-75fc-4239-925f-2a117a1f3345","execution":{"iopub.status.busy":"2023-10-27T17:28:09.206385Z","iopub.execute_input":"2023-10-27T17:28:09.206722Z","iopub.status.idle":"2023-10-27T17:28:11.693903Z","shell.execute_reply.started":"2023-10-27T17:28:09.206671Z","shell.execute_reply":"2023-10-27T17:28:11.692555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##**1. Images**","metadata":{"id":"5XKQsbwEH18R"}},{"cell_type":"markdown","source":"Le code est ici adapté à l'environnement ipython offert par `google colab` que nous avons privilégié car nous permettant d'entraîner le réseau de neurones sur un GPU.","metadata":{"id":"_s-XR2lAYJVa"}},{"cell_type":"markdown","source":"Nous avons déposé sur le Drive de Google les fichiers téléchargés.","metadata":{"id":"axdmH0xpZR3A"}},{"cell_type":"markdown","source":"Comme indiqué ci-dessus, les images sont étiquetées des labels `benign` et `malignant`.","metadata":{"id":"Za0pz6IMZi5p"}},{"cell_type":"code","source":"print(\"Répertoire train - Nombre d'images de tumeurs bénignes:\",len(os.listdir(\"/kaggle/input/skin-cancer-malignant-vs-benign/train/benign\")),\n          \"Répertoire train - Nombre d'images de tumeurs malignes:\", len(os.listdir(\"/kaggle/input/skin-cancer-malignant-vs-benign/train/malignant\")),sep='\\n')","metadata":{"id":"I90Ii2z_bNSn","outputId":"17f6ec16-fb79-4463-b33c-ea2ff6b2c841","execution":{"iopub.status.busy":"2023-10-27T17:28:27.850743Z","iopub.execute_input":"2023-10-27T17:28:27.851078Z","iopub.status.idle":"2023-10-27T17:28:28.665223Z","shell.execute_reply.started":"2023-10-27T17:28:27.851026Z","shell.execute_reply":"2023-10-27T17:28:28.664491Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Répertoire test - Nombre d'images de tumeurs bénignes:\",len(os.listdir(\"/kaggle/input/skin-cancer-malignant-vs-benign/test/benign\")),\n          \"Répertoire test - Nombre d'images de tumeurs malignes:\", len(os.listdir(\"/kaggle/input/skin-cancer-malignant-vs-benign/test/malignant\")),sep='\\n')","metadata":{"id":"VZ3PrhN9ibFj","outputId":"38e7a287-d270-415f-a80f-8d6ee055f21c","execution":{"iopub.status.busy":"2023-10-27T17:28:41.819205Z","iopub.execute_input":"2023-10-27T17:28:41.819552Z","iopub.status.idle":"2023-10-27T17:28:42.148108Z","shell.execute_reply.started":"2023-10-27T17:28:41.819505Z","shell.execute_reply":"2023-10-27T17:28:42.146808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Le répertoire train contient près de 2300 images, le répertoire test presque 700 clichés. La répartition entre labels est suffisamment équilibrée (55% pour le label `benign` *vs* 45% pour le label `malignant`) pour retenir comme métrique l'*accuracy* des résultats lors de la phase d'entraînement de l'algorithme, soit le ratio :\n> $accuracy={\\text{vrais positifs + vrais négatifs }\\over\\text{ensemble des observations}}$.\n\n","metadata":{"id":"NYexhb9AlJ-K"}},{"cell_type":"markdown","source":"Ci-dessous un échantillon des 5 premières images pour les répertoires `train` et `test`.","metadata":{"id":"gyXZhQzsTJG_"}},{"cell_type":"code","source":"malign_images = glob(\"/kaggle/input/skin-cancer-malignant-vs-benigntrain/malignant/*\")\nbenign_images = glob(\"/kaggle/input/skin-cancer-malignant-vs-benign/train/benign/*\")\n\ndef plot_any(arr, title = ''):\n  plt.figure(figsize = (15, 15))\n  for i in range(len(arr)):\n    img_A = mpimg.imread(arr[i])\n    plt.subplot(1,len(arr),i + 1)\n    plt.title(title)\n    plt.imshow(img_A);","metadata":{"id":"mSnzhdstcUH0","execution":{"iopub.status.busy":"2023-10-27T17:29:00.907419Z","iopub.execute_input":"2023-10-27T17:29:00.907802Z","iopub.status.idle":"2023-10-27T17:29:00.927434Z","shell.execute_reply.started":"2023-10-27T17:29:00.907732Z","shell.execute_reply":"2023-10-27T17:29:00.926187Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_any(malign_images[:5],'Images tumeurs malignes')","metadata":{"id":"2anpC9Nfc0sk","outputId":"67f7b027-df07-4472-9387-00c68bd592ac","execution":{"iopub.status.busy":"2023-10-27T17:29:07.070633Z","iopub.execute_input":"2023-10-27T17:29:07.070999Z","iopub.status.idle":"2023-10-27T17:29:07.088785Z","shell.execute_reply.started":"2023-10-27T17:29:07.070931Z","shell.execute_reply":"2023-10-27T17:29:07.087506Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_any(benign_images[:5],'Images tumeurs bénignes')","metadata":{"id":"h7WqHE69dgIL","outputId":"f78ab141-d30f-43d0-b817-f5b8484f0964","execution":{"iopub.status.busy":"2023-10-27T17:29:11.084805Z","iopub.execute_input":"2023-10-27T17:29:11.085325Z","iopub.status.idle":"2023-10-27T17:29:12.467853Z","shell.execute_reply.started":"2023-10-27T17:29:11.085199Z","shell.execute_reply":"2023-10-27T17:29:12.466912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##**1.2 Pre processing**","metadata":{"id":"dIyQDRCfd-o5"}},{"cell_type":"markdown","source":"Les réseaux de neurones ne traitent pas les données brutes issues de fichiers texte, de fichiers image `JPEG` ou de fichiers au format CSV mais traitent des représentations vectorisées et standardisées. Les images doivent être donc importées et décodées en tenseurs entiers, puis converties en virgule flottante et normalisées en valeurs généralement comprises entre 0 et 1.","metadata":{"id":"-_yz9FH_VN-r"}},{"cell_type":"markdown","source":"*Création des tenseurs*","metadata":{"id":"4RhWNzQaU-E2"}},{"cell_type":"markdown","source":"Nous créons vecteurs et tenseurs contenant respectivement les valeurs numériques des labels et des images contenues dans les répertoires `train` et `test`. Ces jeux de données seront utilisées section 3.","metadata":{"id":"ATG_bhT3-K4Y"}},{"cell_type":"code","source":"train_chemin  = glob('/kaggle/input/skin-cancer-malignant-vs-benign/train/*')\ntest_chemin   = glob('/kaggle/input/skin-cancer-malignant-vs-benign/test/*')\n\nmalign_images = glob(\"/kaggle/input/skin-cancer-malignant-vs-benign/train/malignant/*\")\nbenign_images = glob(\"/kaggle/input/skin-cancer-malignant-vs-benign/train/benign/*\")\n\nfolder_benign_train = \"/kaggle/input/skin-cancer-malignant-vs-benign/train/benign\"\nfolder_malignant_train = \"/kaggle/input/skin-cancer-malignant-vs-benign/train/malignant\"\n\nfolder_benign_test = \"/kaggle/input/skin-cancer-malignant-vs-benign/test/benign\"\nfolder_malignant_test = \"/kaggle/input/skin-cancer-malignant-vs-benign/test/malignant\"\n","metadata":{"id":"zUajsy710Wfa","execution":{"iopub.status.busy":"2023-10-27T17:30:08.229473Z","iopub.execute_input":"2023-10-27T17:30:08.229846Z","iopub.status.idle":"2023-10-27T17:30:08.261129Z","shell.execute_reply.started":"2023-10-27T17:30:08.2298Z","shell.execute_reply":"2023-10-27T17:30:08.260051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"read = lambda imname: np.asarray(Image.open(imname).convert(\"RGB\"))\n\n# Lecture des images\n# répertoire train\nims_benign = [read(os.path.join(folder_benign_train, filename)) for filename in os.listdir(folder_benign_train)]\ntrain_images_benign = np.array(ims_benign, dtype='float32')\nims_malignant = [read(os.path.join(folder_malignant_train, filename)) for filename in os.listdir(folder_malignant_train)]\ntrain_images_malign = np.array(ims_malignant, dtype='float32')\n\n# répertoire test\nims_benign = [read(os.path.join(folder_benign_test, filename)) for filename in os.listdir(folder_benign_test)]\ntest_images_benign = np.array(ims_benign, dtype='float32')\nims_malignant = [read(os.path.join(folder_malignant_test, filename)) for filename in os.listdir(folder_malignant_test)]\ntest_images_malign = np.array(ims_malignant, dtype='float32')\n\n# Création des labels\ny_train_benign = np.zeros(train_images_benign.shape[0])\ny_train_malignant = np.ones(train_images_malign.shape[0])\ny_test_benign = np.zeros(test_images_benign.shape[0])\ny_test_malignant = np.ones(test_images_malign.shape[0])\n\n# Fusion des datasets \ntrain_images = np.concatenate((train_images_benign, train_images_malign), axis = 0)\ntrain_labels = np.concatenate((y_train_benign, y_train_malignant), axis = 0)\ntest_images = np.concatenate((test_images_benign, test_images_malign), axis = 0)\ntest_labels = np.concatenate((y_test_benign, y_test_malignant), axis = 0)","metadata":{"id":"XeE_ihBMqsYO","execution":{"iopub.status.busy":"2023-10-27T17:30:13.698471Z","iopub.execute_input":"2023-10-27T17:30:13.698814Z","iopub.status.idle":"2023-10-27T17:30:50.617451Z","shell.execute_reply.started":"2023-10-27T17:30:13.698761Z","shell.execute_reply":"2023-10-27T17:30:50.616028Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nous mélangeons aléatoirement vecteurs des prédicteurs et des labels et normalisons les valeurs RGB.","metadata":{"id":"CcIly9P2sqOX"}},{"cell_type":"code","source":"s = np.arange(train_images.shape[0])\nnp.random.shuffle(s)\ntrain_images = train_images[s]\ntrain_labels = train_labels[s]\n\n\ns = np.arange(test_images.shape[0])\nnp.random.shuffle(s)\ntest_images = test_images[s]\ntest_labels = test_labels[s]\n \ntrain_images = train_images/255.\ntest_images = test_images/255.\n","metadata":{"id":"cKsuwww-rIBM","execution":{"iopub.status.busy":"2023-10-27T17:30:50.619241Z","iopub.execute_input":"2023-10-27T17:30:50.619536Z","iopub.status.idle":"2023-10-27T17:30:54.138825Z","shell.execute_reply.started":"2023-10-27T17:30:50.619494Z","shell.execute_reply":"2023-10-27T17:30:54.137962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"##**2 Modélisation - réseaux convolutifs**","metadata":{"id":"t5aEoTNf9JEV"}},{"cell_type":"markdown","source":"###**2.1 Réseau entraîné sur le dataset**\n","metadata":{"id":"GgHqVOjVo6CU"}},{"cell_type":"markdown","source":"*Encodage des images au moyen de la classe ImageDataGenerator*\n\nA ce stade, plutôt que d'utiliser les vecteurs précédemment créés, nous privilégions la classe `ImageDataGenerator` du module preprocessing de Keras qui nous permet de de générer, à partir des images, des lots de tenseurs (ici batche_size = 20).\nIci à nouveau les valeurs RGB sont divisées par 255. Nous procédons de la sorte car cette classe nous permettra de mettre en oeuvre, au cours de la section suivante, la méthode dite de *data augmentation*.\n\nLes vecteurs crées section *1.2* seront lues en entrée des modèles mis en oeuvre à compter de la section *2.3*.","metadata":{"id":"i-wnzpd2eC3X"}},{"cell_type":"code","source":"batch_train = 50\nbatch_test  = 20","metadata":{"id":"9LjyfgYMp7Zh","execution":{"iopub.status.busy":"2023-10-27T17:30:54.140759Z","iopub.execute_input":"2023-10-27T17:30:54.141026Z","iopub.status.idle":"2023-10-27T17:30:54.145027Z","shell.execute_reply.started":"2023-10-27T17:30:54.140979Z","shell.execute_reply":"2023-10-27T17:30:54.144112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_datagen = ImageDataGenerator(rescale=1./255)\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_generator = train_datagen.flow_from_directory( \n    '/kaggle/input/skin-cancer-malignant-vs-benign/train/',\n    target_size=(224, 224),\n    batch_size=batch_train,\n    class_mode='binary')\n\nvalidation_generator = test_datagen.flow_from_directory(\n    '/kaggle/input/skin-cancer-malignant-vs-benign/test/',\n    target_size=(224, 224),\n    batch_size=batch_test,\n    class_mode='binary')","metadata":{"id":"p4772QvCrIzm","outputId":"2b461356-2030-409d-e8c7-a108bcfda19b","execution":{"iopub.status.busy":"2023-10-27T17:30:56.324967Z","iopub.execute_input":"2023-10-27T17:30:56.325751Z","iopub.status.idle":"2023-10-27T17:30:56.761756Z","shell.execute_reply.started":"2023-10-27T17:30:56.325679Z","shell.execute_reply":"2023-10-27T17:30:56.760832Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Modèle*\n\nNous allons mettre en oeuvre des réseaux neuronaux convolutifs pour notre jeu de données. La première structure sera en fait un empilement de couche de réseau de traitement ou filtre (ici `Conv2D`, dotée de la fonction `relu`comme fonction d'activation) et de couches de neurones dits de regroupement (ici `MaxPooling` avec la fonction argMax comme fonction de mise en commun).\n\nUne couche convolutive (Conv2D) peut être appréhendée comme un ensemble de filtres appliquées aux inputs. Nous passons donc progressivement de 32 à 128 filtres. Chaque filtre transforme une partie de l'image, la matrice de filtre du noyau étant appliquée à toute l'image. \n\nLa deuxième couche est la couche de pooling (MaxPool2D) qui consiste à réduire la taille des informations en entrée tout en en préservant les plus saillantes. Concrètement, il s'agit d'une fenêtre glissante appliquées à toutes les parties de l’image. Ici, la valeur maximum de la fenêtre est conservées à chaque pas. En pratique, on utilise souvent une fenêtre de 2 ou 3 pixels de côté et une valeur de 2 pixels pour la valeur d’un pas. \n\nLa fonction ReLU renvoie à une concept mathématique assez simples. Chaque valeur négative du pixel est remplacée par un 0 garantissant la stabilité du modèle.\n\nLa couche Aplatir est utilisée pour convertir les cartes d'entités finales en un seul vecteur unidimensionnel. Cette étape d'aplatissement est nécessaire pour que utiliser enusuite des couches entièrement connectées. \n\nAu final, on  utilise  une couche entièrement connectée (Dense) qui est un classificateur artificiel de réseaux de neurones (ANN)","metadata":{"id":"ggY5gquRepS1"}},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(layers.Conv2D(32, (3, 3), activation='relu',input_shape=(224, 224, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"5BwRQIafpGa5","execution":{"iopub.status.busy":"2023-10-27T17:31:01.792384Z","iopub.execute_input":"2023-10-27T17:31:01.792744Z","iopub.status.idle":"2023-10-27T17:31:01.973734Z","shell.execute_reply.started":"2023-10-27T17:31:01.792679Z","shell.execute_reply":"2023-10-27T17:31:01.972651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['acc'])\n","metadata":{"id":"Tt4Drn8a5wT9","execution":{"iopub.status.busy":"2023-10-27T17:31:06.144265Z","iopub.execute_input":"2023-10-27T17:31:06.144685Z","iopub.status.idle":"2023-10-27T17:31:06.204115Z","shell.execute_reply.started":"2023-10-27T17:31:06.144614Z","shell.execute_reply":"2023-10-27T17:31:06.202733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"id":"reDjBjTbn0G7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Pour l'étape de compilation, , nous utilisons le `RMSprop` pour optimiseur et la `binary crossentropy` pour fonction de coût.","metadata":{"id":"bPEm8OpPzpu0"}},{"cell_type":"code","source":"model.summary()","metadata":{"id":"u_NKR_CM58dz","outputId":"5b7f0a88-7151-43b1-a149-cc1ab3e5a53e","execution":{"iopub.status.busy":"2023-10-27T17:31:12.278469Z","iopub.execute_input":"2023-10-27T17:31:12.279214Z","iopub.status.idle":"2023-10-27T17:31:12.290426Z","shell.execute_reply.started":"2023-10-27T17:31:12.279159Z","shell.execute_reply":"2023-10-27T17:31:12.289456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*In fine* notre modèle comporte près de 10 millions de paramètres à optimiser.","metadata":{"id":"FYM79WsoO1kg"}},{"cell_type":"markdown","source":"S'agissant des réseaux convolutifs, nous commencons ici par des *inputs* de dimension 224 × 224 pour extraire des *feature maps* de dimension 7 × 7 avant la réduction du tenseur. Parallèlement, pour gagner en complexité la profondeur des *feature maps* augmente progressivement passant de 32 à 138.\n\nEtant en présence d'un problème de classification binaire, nous finissons avec une réseau dense de taille 1 doté de la fonction sigmoïde pour fonction d'activation.","metadata":{"id":"-oTGWO7e5iMo"}},{"cell_type":"code","source":"history = model.fit_generator(\n    train_generator,\n    steps_per_epoch = len(train_images) // batch_train,\n    epochs=30,\n    validation_data = validation_generator,\n    validation_steps= len(test_images) // batch_test)","metadata":{"id":"8uVJtF4IpWwV","outputId":"e95b0bc3-3f51-449f-88a1-7ebb6083c173","execution":{"iopub.status.busy":"2023-10-27T17:31:18.150358Z","iopub.execute_input":"2023-10-27T17:31:18.150679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Courbes de la fonction de coût et de l'acccuracy*","metadata":{"id":"ohWKCgGoQv_G"}},{"cell_type":"markdown","source":"L'overfitting du modèle s'observe à compter du 15ème passage sur l'ensemble du dataset. *In fine*, l'*accuracy* sur le jeu de validation n'excède jamais 85%.","metadata":{"id":"Nyx6wHWrRsIu"}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'r-', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'r-', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"id":"Ewk_wfpZxozQ","outputId":"309a14f8-128e-42a7-f921-d8837e60e8e7","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"###**2.2 Data augmentation**","metadata":{"id":"uYh_JjTTT3vR"}},{"cell_type":"markdown","source":"Pour pallier les surajustements des modèles, nous allons emprunter l'approche dite de \"Data augmentation*. Celle-ci consiste à générer de nouvelles images à travers un nombre de transformations aléatoires sur l'échantillon d'origine, l'objectif poursuivi étant d'entraîner le modèle sur un nombre plus conséquent de représentations.\n\nComme évoqué plus haut, Keras nous offre la possibilité de configurer un nombre de transformations aléatoires avec la classe `ImageDataGenerator` du module `preprocessing`.","metadata":{"id":"wYDzLxMrLJvO"}},{"cell_type":"code","source":"K.clear_session()\ndel model\ndel history","metadata":{"id":"BiEv3GffOoYX","execution":{"iopub.status.busy":"2023-10-27T17:22:47.908799Z","iopub.status.idle":"2023-10-27T17:22:47.909232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_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\ntest_datagen = ImageDataGenerator(rescale=1./255)\n\ntrain_generator = train_datagen.flow_from_directory( \n    '/content/drive/My Drive/DATA CANCER SKIN/train/',\n    target_size=(224, 224),\n    batch_size=batch_train,\n    class_mode='binary')\n\nvalidation_generator = test_datagen.flow_from_directory(\n    '/content/drive/My Drive/DATA CANCER SKIN/test/',\n    target_size=(224, 224),\n    batch_size=batch_test,\n    class_mode='binary')","metadata":{"id":"dQj0Yw38MiKH","outputId":"f28b56a4-a3f9-4bb1-9a79-9644a8dd16b7","execution":{"iopub.status.busy":"2023-10-27T17:22:47.909895Z","iopub.status.idle":"2023-10-27T17:22:47.910329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(layers.Conv2D(32, (3, 3), activation='relu',input_shape=(224, 224, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"2dHd3wztkXqB","execution":{"iopub.status.busy":"2023-10-27T17:22:47.911032Z","iopub.status.idle":"2023-10-27T17:22:47.911487Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy', optimizer=optimizers.RMSprop(lr=1e-4), metrics=['acc'])","metadata":{"id":"qFlht5pPky8I","execution":{"iopub.status.busy":"2023-10-27T17:22:47.912131Z","iopub.status.idle":"2023-10-27T17:22:47.912581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit_generator(\n    train_generator,\n    steps_per_epoch = len(train_images) // batch_train,\n    epochs=30,\n    validation_data = validation_generator,\n    validation_steps= len(test_images) // batch_test)","metadata":{"id":"Y5ZcIazbPwpi","outputId":"4437f8bc-f209-4346-e7da-9de3ac6e68bb","execution":{"iopub.status.busy":"2023-10-27T17:22:47.913147Z","iopub.status.idle":"2023-10-27T17:22:47.913613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Courbes de la fonction de coût et de l'acccuracy*","metadata":{"id":"ElgZRtHtOMco"}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'r-', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'r-', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"id":"Do8BNEBaOM3m","outputId":"d5d66f82-e2eb-4fcc-fbb0-20cda1b829e7","execution":{"iopub.status.busy":"2023-10-27T17:22:47.914178Z","iopub.status.idle":"2023-10-27T17:22:47.914546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Les techniques de *data augmentation* ne semblent pas offrir d'amélioration sensible des performances du modèle.\n\nNous allons désormais privilégier de nouvelles architectures.","metadata":{"id":"n57YMMC7g5AD"}},{"cell_type":"markdown","source":"###**2.3 Modèles pré-entraînés**","metadata":{"id":"1YgZz0y5W4OK"}},{"cell_type":"markdown","source":"Une approche particulièrement efficace du *deep learning* sur données non massives, de l'ordre de quelques centaines à quelques milliers d'observations, consiste à implémenter des réseaux pré-entraînés. Un réseau pré-entraîné est un réseau sauvegardé qui a précédemment été mis en oeuvre sur une large base de données, à des fins de classification d'image notamment.\n\nSi le dataset initial est suffisamment important, les différents filtres et leur architecture des modèmles pré-entrâinés peuvent effectivement être considérés comme génériques pour l'appréhension du monde visuel. Ces possibles transpositions offertes par le *deep learning* constituent un avantage comparativement aux autres méthodes de type *machine learning*.","metadata":{"id":"UxcsuF_ZhI8m"}},{"cell_type":"markdown","source":"####**2.3.1 Echantillonnage**","metadata":{"id":"V9E_fRJXdxZh"}},{"cell_type":"markdown","source":"Pour évaluer désormais les performances des différents modèles, nous ré-échantillonnons les images du répertoire `train`. 70% des images seront employées à entraîner le modèle, les 30% restantes étant dévolues à sa validation. ","metadata":{"id":"vUTQuNd4fhHA"}},{"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(\n    train_images, \n    train_labels,\n    test_size = 0.3)","metadata":{"id":"d5IZZb-1c1xd","execution":{"iopub.status.busy":"2023-10-27T17:22:47.915089Z","iopub.status.idle":"2023-10-27T17:22:47.915442Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A compter de cette section, nous importerons en entrée des modèles les vecteurs et tenseurs créés section *1.2*.","metadata":{"id":"jLh5LtMUkkwl"}},{"cell_type":"markdown","source":"####**2.3.2 Réseau VGG19**","metadata":{"id":"3sDEFTr0iFnR"}},{"cell_type":"markdown","source":"Le VGG-19 est une amélioration du VGG-16 qui passe de 16 couches de convolutions à 19 couches. VGG16 a été élaboré au cours d’une compétition mise en place par l’organisation `ImageNet` avec pour but de classifier le contenu d’images en 1000 objets de la vie courante (mouton, poule, fourchette, chateau, lampadaire, diverses races de chiens, …). Mis au point en 2014, ce réseau a atteint des scores de précision remarquables compte tenu de son architecture très légère : **_[VGG19 avec Keras](https://keras.io/api/applications/vgg/)_**","metadata":{"id":"cuz7n0glfPHD"}},{"cell_type":"code","source":"img_VGG19 = mpimg.imread(\"/content/drive/My Drive/DATA CANCER SKIN/VGG19.png\")\nplt.figure(figsize = (15, 15))\nplt.title(\"Structure VGG19\")\nplt.imshow(img_VGG19)","metadata":{"id":"t6Md_P9yIug_","outputId":"b4ca47b5-57da-47c4-e90d-95a738280f5f","execution":{"iopub.status.busy":"2023-10-27T17:22:47.915986Z","iopub.status.idle":"2023-10-27T17:22:47.91633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"K.clear_session()\ndel model\ndel history","metadata":{"id":"B6vM37iUo3cr","execution":{"iopub.status.busy":"2023-10-27T17:22:47.916895Z","iopub.status.idle":"2023-10-27T17:22:47.917236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_train = 50\nbatch_test  = 20","metadata":{"id":"1VAyVt5Jhgch","execution":{"iopub.status.busy":"2023-10-27T17:22:47.917802Z","iopub.status.idle":"2023-10-27T17:22:47.918139Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(VGG19(include_top=False, weights='imagenet', input_shape=(224, 224, 3)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(256, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"XERQGKrSUyoQ","outputId":"6a85a84c-8cea-4ee2-f6a6-7dcd9e8ae388","execution":{"iopub.status.busy":"2023-10-27T17:22:47.918694Z","iopub.status.idle":"2023-10-27T17:22:47.919029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-5),metrics=['acc'])","metadata":{"id":"2uuyz8xiWaBS","execution":{"iopub.status.busy":"2023-10-27T17:22:47.919578Z","iopub.status.idle":"2023-10-27T17:22:47.919911Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"id":"XBdw_QHgGlLJ","outputId":"46a743c2-8178-4b31-ae9c-2124ce4c8ca7","execution":{"iopub.status.busy":"2023-10-27T17:22:47.920444Z","iopub.status.idle":"2023-10-27T17:22:47.920795Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nous pouvons constater que ce modèle propose plus de 26 millions de paramètres contre moins de 10 millions pour le modèle implémenté section *1.2*. Nous devons nous attendre à des performances améliorées mais au détriment d'un *overfitting* plus rapidement atteint.","metadata":{"id":"frDeAOSnJHuA"}},{"cell_type":"code","source":"history = model.fit(X_train, y_train,\n                    epochs=30,\n                    batch_size= X_train.shape[0]// batch_train,\n                    validation_data=(X_val, y_val))","metadata":{"id":"YBlyYuOmWe6y","outputId":"a8b2ab90-4b46-4e79-a2ba-2df79493f059","execution":{"iopub.status.busy":"2023-10-27T17:22:47.921311Z","iopub.status.idle":"2023-10-27T17:22:47.921673Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Courbes de la fonction de coût et de l'acccuracy*","metadata":{"id":"39ldkj5Y_y-x"}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'r-', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'r-', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"id":"Xg4fSntr_z4w","outputId":"cb17eb33-6116-4fde-faf4-dd5b4701fa63","execution":{"iopub.status.busy":"2023-10-27T17:22:47.922195Z","iopub.status.idle":"2023-10-27T17:22:47.922547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss, accu = model.evaluate(test_images, test_labels)\nprint(\"%s: %.2f%%\" % ('Accuracy...', accu*100))\nprint(\"%s: %.2f\" % ('loss.......', loss))","metadata":{"id":"ENm2l0xTySot","outputId":"b5b041d5-5ac2-4f92-eb2f-38c6e2d2c78a","execution":{"iopub.status.busy":"2023-10-27T17:22:47.923073Z","iopub.status.idle":"2023-10-27T17:22:47.923415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Sur le jeu de test, l'*accuracy* atteint près de 87%. Intéressons-nous maintenant à la matrice de confusion.","metadata":{"id":"byKWjpRIJ_wz"}},{"cell_type":"markdown","source":"#####*Matrice de confusion*","metadata":{"id":"Q4Rp4-zoLcyl"}},{"cell_type":"code","source":"test_predicts=[]\npredictions = model.predict(test_images)\nfor i in range(len(predictions)):\n    if predictions[i][0]>0.5:\n        test_predicts.append(1)\n    else:\n        test_predicts.append(0)","metadata":{"id":"cQu0j6xFLhod","execution":{"iopub.status.busy":"2023-10-27T17:22:47.923951Z","iopub.status.idle":"2023-10-27T17:22:47.924281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_confusion_matrix(cm, classes,title='Matrice de confusion', cmap=plt.cm.Blues):\n    plt.imshow(cm, interpolation='nearest', cmap=cmap)\n    plt.title(title)\n    plt.colorbar()\n    tick_marks = np.arange(len(classes))\n    plt.xticks(tick_marks, classes, rotation=55)\n    plt.yticks(tick_marks, classes)\n    fmt = 'd'\n    thresh = cm.max() / 2.\n    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):\n        plt.text(j, i, format(cm[i, j], fmt),\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.ylabel('Observé')\n    plt.xlabel('Prédit')\n    plt.tight_layout()","metadata":{"id":"GA67AEEnR4Yn","execution":{"iopub.status.busy":"2023-10-27T17:22:47.925024Z","iopub.status.idle":"2023-10-27T17:22:47.925554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cm = confusion_matrix(test_labels, test_predicts)\n\ncm_plot_label =['bénin','malin']\nplot_confusion_matrix(cm, cm_plot_label)","metadata":{"id":"uGfihNElaO-e","outputId":"48c100fa-0569-49ce-da21-1bdc8d26ab88","execution":{"iopub.status.busy":"2023-10-27T17:22:47.9262Z","iopub.status.idle":"2023-10-27T17:22:47.926761Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Au-delà de la métrique *accuracy*, l'examen de la matrice de confusion nous montre des performances moindres en terme de précision, défini comme le ratio ${\\text{vrais positifs}\\over\\text{vrais positifs + faux positifs}}$, qu'en terme de rappel, défini comme le ${\\text{vrais positifs}\\over\\text{vrais positifs + faux négatifs}}$. Autrement dit, si notre prédiction est juste dans 82%, nous parvenons même à identifier plus de 90% des tumeurs malignes. Du point de vue du praticien, ces resultats peuvent sembler satisfaisants.","metadata":{"id":"BWP_P0qgM5JB"}},{"cell_type":"markdown","source":"*Courbe de ROC et AUC*","metadata":{"id":"i8kuU2VdgKFq"}},{"cell_type":"code","source":"roc_log = roc_auc_score(test_labels, test_predicts)\nfalse_positive_rate, true_positive_rate, threshold = roc_curve(test_labels, test_predicts)\narea_under_curve = auc(false_positive_rate, true_positive_rate)\n\nplt.plot([0, 1], [0, 1], 'r--')\nplt.plot(false_positive_rate, true_positive_rate, label='AUC = {:.3f}'.format(area_under_curve))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.close()","metadata":{"id":"lS4piIlVgLvT","outputId":"81a97239-b179-491e-a8ce-ab93c39f9038","execution":{"iopub.status.busy":"2023-10-27T17:22:47.92738Z","iopub.status.idle":"2023-10-27T17:22:47.92771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"####**2.3.3 Réseau EfficientNetB0**","metadata":{"id":"j-5ZeBJHi05O"}},{"cell_type":"markdown","source":"Les modèles EfficientNet appartiennent à une famille de modèles de classification d'images atteignant des précisions inégalées, tout en étant relativement rapides et moins volumineux que d'autres modèles de classification.\nNous allons ici implémenter le modèle de base nommé `EfficientNetB0`.","metadata":{"id":"57BI82TmP-GO"}},{"cell_type":"code","source":"K.clear_session()\ndel model\ndel history","metadata":{"id":"Z63wR5rbo6Xk","execution":{"iopub.status.busy":"2023-10-27T17:22:47.928266Z","iopub.status.idle":"2023-10-27T17:22:47.928623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(EfficientNetB0(include_top=False, weights='imagenet',input_shape=(224,224,3)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(256, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"v2re30hCi0gF","execution":{"iopub.status.busy":"2023-10-27T17:22:47.929189Z","iopub.status.idle":"2023-10-27T17:22:47.929545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-5),metrics=['acc'])","metadata":{"id":"fF8OnVliowZE","execution":{"iopub.status.busy":"2023-10-27T17:22:47.930099Z","iopub.status.idle":"2023-10-27T17:22:47.93044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"id":"h6mCfZEwRHY_","outputId":"cd5c6e8c-fcd6-4e0c-f38b-bd976bcb7596","execution":{"iopub.status.busy":"2023-10-27T17:22:47.930999Z","iopub.status.idle":"2023-10-27T17:22:47.931338Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train,\n                    epochs=30,\n                    batch_size= X_train.shape[0]// batch_train,\n                    validation_data=(X_val, y_val))","metadata":{"id":"pmBGRgaSp1J_","outputId":"4dcd4a29-dbd6-4875-8aa8-c1fb84f12b9a","execution":{"iopub.status.busy":"2023-10-27T17:22:47.931918Z","iopub.status.idle":"2023-10-27T17:22:47.932253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Performances sur le dataset de test*","metadata":{"id":"ZauuzeMfVRYu"}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'r-', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'r-', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"id":"qMazQ_7UsTNX","outputId":"abebeb0d-9b00-453e-c7ce-5abf301dd55d","execution":{"iopub.status.busy":"2023-10-27T17:22:47.932842Z","iopub.status.idle":"2023-10-27T17:22:47.933186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss, accu = model.evaluate(test_images, test_labels)\nprint(\"%s: %.2f%%\" % ('Accuracy...', accu*100))\nprint(\"%s: %.2f\" % ('loss.......', loss))","metadata":{"id":"9Tu1P3ZzzwCD","outputId":"19c12dee-e0d4-4b7e-cf6a-49a76bad6c8d","execution":{"iopub.status.busy":"2023-10-27T17:22:47.933749Z","iopub.status.idle":"2023-10-27T17:22:47.934073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predicts=[]\npredictions = model.predict(test_images)\nfor i in range(len(predictions)):\n    if predictions[i][0]>0.5:\n        test_predicts.append(1)\n    else:\n        test_predicts.append(0)\n        \ncm = confusion_matrix(test_labels, test_predicts)\n\ncm_plot_label =['bénin','malin']\nplot_confusion_matrix(cm, cm_plot_label)","metadata":{"id":"USMuQuADz8hQ","outputId":"f7325d51-4a1a-432c-c181-104f868297df","execution":{"iopub.status.busy":"2023-10-27T17:22:47.934665Z","iopub.status.idle":"2023-10-27T17:22:47.934988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"roc_log = roc_auc_score(test_labels, test_predicts)\nfalse_positive_rate, true_positive_rate, threshold = roc_curve(test_labels, test_predicts)\narea_under_curve = auc(false_positive_rate, true_positive_rate)\n\nplt.plot([0, 1], [0, 1], 'r--')\nplt.plot(false_positive_rate, true_positive_rate, label='AUC = {:.3f}'.format(area_under_curve))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.close()","metadata":{"id":"h6GdGkpu0MgG","outputId":"dfc30de2-c2e4-4d36-b73f-561221b6d84e","execution":{"iopub.status.busy":"2023-10-27T17:22:47.935657Z","iopub.status.idle":"2023-10-27T17:22:47.936Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Avec les mêmes paramétrages, la structure ne parvient pas à bien appréhender les caractéristiques de nos images. Quelques soient les métriques examinées (*accuracy*, précision, rappel, AUC) les performances ressortent au final nettement dégradées avec cette architecture.","metadata":{"id":"fp1msr3fVfkc"}},{"cell_type":"markdown","source":"####**2.3.4 Réseau ResNet50**","metadata":{"id":"GmY0Hx7sTiHA"}},{"cell_type":"markdown","source":"Le modèle Resnet50 pour \"Residual Network\" se base sur le papier de recherche **_[\"Deep Residual Learning For Image Recognition\"](https://arxiv.org/pdf/1512.03385.pdf)_**. Ce modèle a été entraîné sur la base de données `Imagenet` contenant plus de 14 millions d'images classées en plus de 20 000 groupes. La base de données est mise à disposition de la communauté de l'analyse d'images par le laboratoire Stanford Vision Lab.\n\nComposé de 50 couches, ce modèle a la particularité d'introduire des connexions résiduelles. Contrairement aux réseaux de neurones convolutifs à l'architecture linéaire, dans un réseau résiduel, les sorties des couches précédentes sont reliées à la sortie des nouvelles couches pour les transmettre toutes les deux à la couche suivante.","metadata":{"id":"UeVdMLftWjaO"}},{"cell_type":"code","source":"K.clear_session()\ndel model\ndel history","metadata":{"id":"etSIMA_15p4e","execution":{"iopub.status.busy":"2023-10-27T17:22:47.936718Z","iopub.status.idle":"2023-10-27T17:22:47.937063Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(ResNet50(include_top=False,  weights=\"imagenet\", input_shape=(224,224,3)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(256, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"fj45jaih5Egs","outputId":"8d08a016-4b7f-48b6-ddef-993729fb1ff5","execution":{"iopub.status.busy":"2023-10-27T17:22:47.937649Z","iopub.status.idle":"2023-10-27T17:22:47.937981Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.summary()","metadata":{"id":"HB-oxorkX0Kf","outputId":"cf21b1ff-39a3-4e73-c0dd-d5d249228019","execution":{"iopub.status.busy":"2023-10-27T17:22:47.938562Z","iopub.status.idle":"2023-10-27T17:22:47.938956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Avec cette architecture, nous passons à un modèle de près de 50 millions de paramètres.","metadata":{"id":"xTqBVIvyX4F4"}},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-5),metrics=['acc'])","metadata":{"id":"A_krK_th6iWK","execution":{"iopub.status.busy":"2023-10-27T17:22:47.9396Z","iopub.status.idle":"2023-10-27T17:22:47.939965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Une première phase dite de `burning` ou d'échauffement est nécessaire pour que le modèle converge. C'est pourquoi nous augmentons le paramètre `epoch` (nombre de passages sur le *dataset* exhaustif) qui passe de 30 à 60. ","metadata":{"id":"abPGaI7idzQV"}},{"cell_type":"code","source":"history = model.fit(X_train, y_train,\n                    epochs=60,\n                    batch_size= X_train.shape[0]// batch_train,\n                    validation_data=(X_val, y_val))","metadata":{"id":"05DUpvfF6nNw","outputId":"a6a349fa-02af-4305-fdf8-9f1d171c7f1c","execution":{"iopub.status.busy":"2023-10-27T17:22:47.940613Z","iopub.status.idle":"2023-10-27T17:22:47.94098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Courbes de la fonction de coût et de l'acccuracy*","metadata":{"id":"bgORrY2YnOU-"}},{"cell_type":"code","source":"acc = history.history['acc']\nval_acc = history.history['val_acc']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1, len(acc) + 1)\nplt.plot(epochs, acc, 'bo', label='Training acc')\nplt.plot(epochs, val_acc, 'r-', label='Validation acc')\nplt.title('Training and validation accuracy')\nplt.legend()\nplt.figure()\nplt.plot(epochs, loss, 'bo', label='Training loss')\nplt.plot(epochs, val_loss, 'r-', label='Validation loss')\nplt.title('Training and validation loss')\nplt.legend()\nplt.show()","metadata":{"id":"efIW6yLt-BH1","outputId":"5946e75a-f71c-4773-843a-0bffa8d646ca","execution":{"iopub.status.busy":"2023-10-27T17:22:47.941595Z","iopub.status.idle":"2023-10-27T17:22:47.941938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss, accu = model.evaluate(test_images, test_labels)\nprint(\"%s: %.2f%%\" % ('Accuracy...', accu*100))\nprint(\"%s: %.2f\" % ('loss.......', loss))","metadata":{"id":"jbY592z2-IEO","outputId":"7060aa28-4fa0-49a0-dd6e-59f215a99e44","execution":{"iopub.status.busy":"2023-10-27T17:22:47.942534Z","iopub.status.idle":"2023-10-27T17:22:47.942879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"A nouveau, nous parvenons à une *accuracy* proche de 87% sur le jeu de test.","metadata":{"id":"tuSQhUCoRnm8"}},{"cell_type":"markdown","source":"*Matrice de confusion*","metadata":{"id":"urDwxMJvRr7A"}},{"cell_type":"code","source":"test_predicts=[]\npredictions = model.predict(test_images)\nfor i in range(len(predictions)):\n    if predictions[i][0]>0.5:\n        test_predicts.append(1)\n    else:\n        test_predicts.append(0)\n        \ncm = confusion_matrix(test_labels, test_predicts)\n\ncm_plot_label =['bénin','malin']\nplot_confusion_matrix(cm, cm_plot_label)","metadata":{"id":"ghAQbPF--O2H","outputId":"1c85cf77-b251-4ac7-dac5-5e555da4473d","execution":{"iopub.status.busy":"2023-10-27T17:22:47.943493Z","iopub.status.idle":"2023-10-27T17:22:47.943828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"L'examen de la matrice de confusion nous indique des performances proches du modèle VGG19 tant en terme de précision, de l'ordre de 84%, que de rappel proche des 89%.","metadata":{"id":"yf1ul3H3SPSL"}},{"cell_type":"markdown","source":"*Courbe de ROC et AUC*","metadata":{"id":"RBNgd-koTb0j"}},{"cell_type":"code","source":"roc_log = roc_auc_score(test_labels, test_predicts)\nfalse_positive_rate, true_positive_rate, threshold = roc_curve(test_labels, test_predicts)\narea_under_curve = auc(false_positive_rate, true_positive_rate)\n\nplt.plot([0, 1], [0, 1], 'r--')\nplt.plot(false_positive_rate, true_positive_rate, label='AUC = {:.3f}'.format(area_under_curve))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.close()","metadata":{"id":"bqtlAAblTgDk","outputId":"e180df1f-7d13-4f6b-d73e-1fd546a741c5","execution":{"iopub.status.busy":"2023-10-27T17:22:47.944415Z","iopub.status.idle":"2023-10-27T17:22:47.944752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"L'AUC est comparable à celle obtenue avec le réseau VGG19.","metadata":{"id":"x8r4ZMHH8I1m"}},{"cell_type":"markdown","source":"####**2.4 Fine tuning du réseau VGG19**","metadata":{"id":"WQ8qGZfcUMjF"}},{"cell_type":"code","source":"K.clear_session()\ndel model\ndel history","metadata":{"id":"f2-g5FOzCAJK","execution":{"iopub.status.busy":"2023-10-27T17:22:47.945311Z","iopub.status.idle":"2023-10-27T17:22:47.945668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nous allons, au cours de cette ultime étape, régler plus finement le réseau pré_entraîné VGG19 qui offrait, eu égard aux temps d'execution nécessaires pour son implémentation, les meilleures performances.","metadata":{"id":"JgeoIcHjTum2"}},{"cell_type":"code","source":"VGG19_base = VGG19(weights='imagenet', include_top=False,input_shape=(224, 224, 3))\nVGG19_base.summary()","metadata":{"id":"L37a2v2lkyaU","outputId":"1cfdf9e0-d181-4930-eaf2-da8007c79d26","execution":{"iopub.status.busy":"2023-10-27T17:22:47.946232Z","iopub.status.idle":"2023-10-27T17:22:47.946768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Nous réglons les trois dernières couches du réseau, c'est à dire celles à partir du *layer* dénommé `block5_conv1`. En procédant ainsi, nous obtiendrons un modèle plus adapté aux caractéristiques de nos données sans avoir à ré-entraîner la totalité des paramètres du réseau (plus de 20 millions de paramètres).\nLes étapes pour le *fine tuning* sont les suivantes : \n*   ajouter les couches adaptées à nos données au sommet du réseau pré-entraîné,\n*   entraîner ce réseau,\n*   adapter les couches supérieures du réseau pré-entraîné (*unfreeze*),\n*   entraîner de nouveau ce réseau.","metadata":{"id":"41RfT7xR6TRt"}},{"cell_type":"code","source":"model = models.Sequential()\nmodel.add(VGG19_base)\nmodel.add(layers.Flatten())\nmodel.add(layers.Dropout(0.5))\nmodel.add(layers.Dense(256, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))","metadata":{"id":"-rTolwTc53rj","execution":{"iopub.status.busy":"2023-10-27T17:22:47.947336Z","iopub.status.idle":"2023-10-27T17:22:47.947678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.compile(loss='binary_crossentropy',optimizer=optimizers.RMSprop(lr=1e-5),metrics=['acc'])","metadata":{"id":"Sb_zyP6N5y_m","execution":{"iopub.status.busy":"2023-10-27T17:22:47.948226Z","iopub.status.idle":"2023-10-27T17:22:47.948578Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train,\n                    epochs=30,\n                    batch_size= X_train.shape[0]// batch_train,\n                    validation_data=(X_val, y_val))","metadata":{"id":"ZW4FYSopAhth","outputId":"d065e6c5-5de6-4979-d1ff-89e154041634","execution":{"iopub.status.busy":"2023-10-27T17:22:47.949209Z","iopub.status.idle":"2023-10-27T17:22:47.94956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Désormais, nous donnons la possibilité d'entraîner les couches supérieures du modèle sur nos propres données et ainsi calculer de nouveaux poids aux paramètres du réseau VGG19. ","metadata":{"id":"AuZLvStzfzTm"}},{"cell_type":"code","source":"VGG19_base.trainable = True\nset_trainable = False\nfor layer in VGG19_base.layers:\n  if layer.name == 'block5_conv1':\n    set_trainable = True\n  if set_trainable:\n    layer.trainable = True\n  else:\n    layer.trainable = False","metadata":{"id":"vYybUkomlHfD","execution":{"iopub.status.busy":"2023-10-27T17:22:47.950126Z","iopub.status.idle":"2023-10-27T17:22:47.950472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(X_train, y_train,\n                    epochs=30,\n                    batch_size= X_train.shape[0]// batch_train,\n                    validation_data=(X_val, y_val))","metadata":{"id":"ecdXhcn7el9y","outputId":"0060a54f-885b-41b0-fc63-8f40db93654d","execution":{"iopub.status.busy":"2023-10-27T17:22:47.951037Z","iopub.status.idle":"2023-10-27T17:22:47.951383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"*Accuracy sur le jeu de test*","metadata":{"id":"_vFc8V7iC3Lr"}},{"cell_type":"code","source":"loss, accu = model.evaluate(test_images, test_labels)\nprint(\"%s: %.2f%%\" % ('Accuracy...', accu*100))\nprint(\"%s: %.2f\" % ('loss.......', loss))","metadata":{"id":"R5HSAtpsC1v5","outputId":"037d8404-0ce9-4451-bf99-1c35e7ee7f64","execution":{"iopub.status.busy":"2023-10-27T17:22:47.951934Z","iopub.status.idle":"2023-10-27T17:22:47.952264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Avec cette étape, nous sommes parvenus à améliorer l'*accuracy* de près de 2 points sur nos données.","metadata":{"id":"Mgn8jwFPorkW"}},{"cell_type":"markdown","source":"*Matrice de confusion*","metadata":{"id":"w9nxwTmCDEsc"}},{"cell_type":"markdown","source":"","metadata":{"id":"A_elcPqf_Vus"}},{"cell_type":"code","source":"test_predicts=[]\npredictions = model.predict(test_images)\nfor i in range(len(predictions)):\n    if predictions[i][0]>0.5:\n        test_predicts.append(1)\n    else:\n        test_predicts.append(0)\n        \ncm = confusion_matrix(test_labels, test_predicts)\n\ncm_plot_label =['bénin','malin']\nplot_confusion_matrix(cm, cm_plot_label)","metadata":{"id":"zNFsC4SQF7_F","outputId":"43fa2ee1-c547-47e9-a880-faa2ab11ef08","execution":{"iopub.status.busy":"2023-10-27T17:22:47.952853Z","iopub.status.idle":"2023-10-27T17:22:47.953198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Au final, la précision ressort augmentée pour s'élever désormais à près de 85% (contre 82 % initialement) pour un rappel quasiment inchangé (91% contre 90%). Nous pourrions donc retenir ce dernier modèle.","metadata":{"id":"z7w9rTwmpMiU"}},{"cell_type":"markdown","source":"*Courbe de ROC et AUC*","metadata":{"id":"PqMyx4GwF9L4"}},{"cell_type":"code","source":"roc_log = roc_auc_score(test_labels, test_predicts)\nfalse_positive_rate, true_positive_rate, threshold = roc_curve(test_labels, test_predicts)\narea_under_curve = auc(false_positive_rate, true_positive_rate)\n\nplt.plot([0, 1], [0, 1], 'r--')\nplt.plot(false_positive_rate, true_positive_rate, label='AUC = {:.3f}'.format(area_under_curve))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.close()","metadata":{"id":"1XEQEoW5GBwf","outputId":"8ddab5ec-88eb-4b65-ec4a-84bfc5041ac1","execution":{"iopub.status.busy":"2023-10-27T17:22:47.953882Z","iopub.status.idle":"2023-10-27T17:22:47.954235Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"L'aire sous la courbe de ROC (ou AUC) atteint à présent près de 0,89.","metadata":{"id":"UdSWaRLYprEZ"}},{"cell_type":"markdown","source":"###Conclusion","metadata":{"id":"QyxXiHhiUP5Q"}},{"cell_type":"code","source":"i=0\nprop_class=[]\nmis_class=[]\n\nfor i in range(len(test_labels)):\n    if(test_labels[i]==test_predicts[i]):\n        prop_class.append(i)\n    if(len(prop_class)==8):\n        break\ni=0\nfor i in range(len(test_labels)):\n    if(not test_labels[i]==test_predicts[i]):\n        mis_class.append(i)\n    if(len(mis_class)==8):\n        break\nw=60\nh=40\nfig=plt.figure(figsize=(14, 12))\ncolumns = 4\nrows = 2\ndef Transfername(namecode):\n    if namecode==0:\n        return \"Benign\"\n    else:\n        return \"Malignant\"\nfor i in range(len(prop_class)):\n    ax = fig.add_subplot(rows, columns, i+1)\n    ax.set_title(\"Predicted result:\"+ Transfername(test_predicts[prop_class[i]])\n                       +\"\\n\"+\"Actual result: \"+ Transfername(test_labels[prop_class[i]]))\n    plt.imshow(test_images[prop_class[i]], interpolation='nearest')\nplt.show()","metadata":{"id":"O3TLxXdUp-In","outputId":"e46e1c2d-3223-465f-e297-cf5ed98e495e","execution":{"iopub.status.busy":"2023-10-27T17:22:47.954836Z","iopub.status.idle":"2023-10-27T17:22:47.955169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"w=60\nh=40\nfig=plt.figure(figsize=(14, 12))\ncolumns = 4\nrows = 2\nfor i in range(len(mis_class)):\n    ax = fig.add_subplot(rows, columns, i+1)\n    ax.set_title(\"Predicted result:\"+ Transfername(test_predicts[mis_class[i]])\n                   +\"\\n\"+\"  Actual result: \"+ Transfername(test_labels[mis_class[i]]))\n    plt.imshow(test_images[mis_class[i]], interpolation='nearest')\nplt.show()","metadata":{"id":"Tl0NiLgdra0u","outputId":"929476b2-fb28-4709-9786-e28e4859e694","execution":{"iopub.status.busy":"2023-10-27T17:22:47.955845Z","iopub.status.idle":"2023-10-27T17:22:47.956196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"La classification des tumeurs est chose ardue pour certains grains de beauté ou mélanome. L'examen clinique visuel est souvent complété d'une biopsie pour conforter le premier diagnostic.\nEn l'état, notre modèle peut sembler satisfaisant au regard de la quantité d'images mises à disposition.","metadata":{"id":"tvmh8OGqsdix"}},{"cell_type":"markdown","source":"## Optimizer Adam\n","metadata":{"id":"ZKy9C3JEdeev"}},{"cell_type":"code","source":"\nmodel = models.Sequential()\nmodel.add(layers.Conv2D(32, (3, 3), activation='relu',input_shape=(224, 224, 3)))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(64, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Conv2D(128, (3, 3), activation='relu'))\nmodel.add(layers.MaxPooling2D((2, 2)))\nmodel.add(layers.Flatten())\nmodel.add(layers.Dense(512, activation='relu'))\nmodel.add(layers.Dense(1, activation='sigmoid'))\nmodel.summary()","metadata":{"id":"4slPPFkqqJ94","outputId":"6b0c47d0-30ce-4e92-f55c-1268308288b5","execution":{"iopub.status.busy":"2023-10-27T17:22:48.008565Z","iopub.execute_input":"2023-10-27T17:22:48.008896Z","iopub.status.idle":"2023-10-27T17:22:48.067375Z","shell.execute_reply.started":"2023-10-27T17:22:48.00885Z","shell.execute_reply":"2023-10-27T17:22:48.066054Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\nfrom keras.callbacks import ReduceLROnPlateau\nfrom keras.optimizers import RMSprop, Adam\nlr = 1e-4\noptimizer = Adam(lr=lr)\nepochs = 30\nbatch_size = 64\nmodel.compile(optimizer = optimizer ,loss = \"binary_crossentropy\", metrics=[\"accuracy\"])\n\n# Set a learning rate annealer\nlearning_rate_reduction = ReduceLROnPlateau(monitor='accuracy', \n                                            patience=5, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=1e-7)\n\n","metadata":{"id":"OoqMCaqwqTmx","execution":{"iopub.status.busy":"2023-10-27T17:22:48.068244Z","iopub.status.idle":"2023-10-27T17:22:48.068709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n\n\nhistory = model.fit(train_generator,\n                    validation_data = validation_generator,\n                    epochs= epochs, batch_size= batch_size, verbose=1, \n                    callbacks=[learning_rate_reduction]\n                   )","metadata":{"id":"HqPeYefnqs-W","outputId":"09218f0f-4e4c-4d00-fb54-fcc10268e3d0","execution":{"iopub.status.busy":"2023-10-27T17:22:48.069472Z","iopub.status.idle":"2023-10-27T17:22:48.069886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n# summarize history for accuracy\nplt.plot(history.history['accuracy'])\nplt.plot(history.history['val_accuracy'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()\n# summarize history for loss\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","metadata":{"id":"nwX3p1Jtq88q","outputId":"865aefb9-59b4-47d9-c44d-674da98e39ab","execution":{"iopub.status.busy":"2023-10-27T17:22:48.070632Z","iopub.status.idle":"2023-10-27T17:22:48.071183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"loss, accu = model.evaluate(test_images, test_labels)\nprint(\"%s: %.2f%%\" % ('Accuracy...', accu*100))\nprint(\"%s: %.2f\" % ('loss.......', loss))","metadata":{"id":"Dt55Mm2lu2dA","outputId":"d6413d77-9d8a-4b75-cd21-48379a255da7","execution":{"iopub.status.busy":"2023-10-27T17:22:48.07196Z","iopub.status.idle":"2023-10-27T17:22:48.072363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{"id":"Yk5Ycm-S_mVa"}},{"cell_type":"markdown","source":"*Matrice de confusion*","metadata":{"id":"eQgwqYy1_rnN"}},{"cell_type":"code","source":"\ntest_predicts=[]\npredictions = model.predict(test_images)\nfor i in range(len(predictions)):\n    if predictions[i][0]>0.5:\n        test_predicts.append(1)\n    else:\n        test_predicts.append(0)\n        \ncm = confusion_matrix(test_labels, test_predicts)\n\ncm_plot_label =['bénin','malin']\nplot_confusion_matrix(cm, cm_plot_label)","metadata":{"id":"4zrVO4kUu66z","outputId":"bfe1f344-b446-4fe1-910e-4a74afe03566","execution":{"iopub.status.busy":"2023-10-27T17:22:48.073108Z","iopub.status.idle":"2023-10-27T17:22:48.073496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Courbe de ROC et AUC","metadata":{"id":"YDWYaTio_uxb"}},{"cell_type":"code","source":"roc_log = roc_auc_score(test_labels, test_predicts)\nfalse_positive_rate, true_positive_rate, threshold = roc_curve(test_labels, test_predicts)\narea_under_curve = auc(false_positive_rate, true_positive_rate)\n\nplt.plot([0, 1], [0, 1], 'r--')\nplt.plot(false_positive_rate, true_positive_rate, label='AUC = {:.3f}'.format(area_under_curve))\nplt.xlabel('False positive rate')\nplt.ylabel('True positive rate')\nplt.title('ROC curve')\nplt.legend(loc='best')\nplt.show()\nplt.close()","metadata":{"id":"f14siLYOu-6T","outputId":"324241a0-052f-4c85-9efe-612a7b7fc57e","execution":{"iopub.status.busy":"2023-10-27T17:22:48.0742Z","iopub.status.idle":"2023-10-27T17:22:48.074659Z"},"trusted":true},"execution_count":null,"outputs":[]}]}