{"cells":[{"metadata":{"_uuid":"f2156d1dd26a1243e18512002e10872c5bd7271e","_cell_guid":"d4c08f48-fe23-4ddb-ac46-d97f05397514"},"cell_type":"markdown","source":"# Reconnaissance de caractères numériques\n\n\n*   1. Introduction\n*   2. Préparation des données\n  * 2.1 Chargement des données\n  * 2.2 Recherche de valeurs malformées\n  * 2.3 Normalisation\n  * 2.4 Reshape d'images\n  * 2.5 Encodage de label\n  * 2.6 Séparation du set d'entraînement et de validation\n* 3. Réseau de neurones convolutifs\n  * 3.1 Définition du modèle\n  * 3.2 Mise en place de l'optimisateur\n  * 3.3 Augmentation des données\n* 4. Évaluation du modèle\n  * 4.1 Entraînement et courbes\n  * 4.2 Matrice de confusion\n* 5. Prédiction et envoi\n  * 5.1 Prédiction et soumission des résultats"},{"metadata":{"_uuid":"e9aff3cf1bb8daa73bec67b970d12195677679f3","_cell_guid":"eb88b372-a6e5-40c8-a1c6-c03799165490"},"cell_type":"markdown","source":"# 1. Introduction\n\nDans ce jupyter, nous allons construire un CNN à 5 couches que nous allons entraîner sur le jeu de données **MNIST**. Pour ce faire, nous allons utiliser l'API *Keras* (avec backend Tensorflow). Dans un premier, il s'agira de préparer les données. Il faudra ensuite construire le modèle et effectuer son évaluation.\n\nPour des raisons de rapidité, le nombre de pas (epoch) est mis à 2. Pour avoir des résultats plus concluants, il est possible de mettre ce nombre à 30.\n\nCe notebook suit 3 étapes principales:\n- La préparation des données\n- Mise en place du modèle et évaluation\n- Résultats"},{"metadata":{"_execution_state":"idle","_uuid":"72334cb006d02a4bcfc2a2fe622524eba824c6f8","_cell_guid":"f67b9393-8ea1-4e23-b856-2ce149cfe421","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport seaborn as sns\n%matplotlib inline\n\nnp.random.seed(2)\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix\nimport itertools\n\nfrom keras.utils.np_utils import to_categorical # convert to one-hot-encoding\nfrom keras.models import Sequential\nfrom keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPool2D\nfrom keras.optimizers import RMSprop\nfrom keras.preprocessing.image import ImageDataGenerator\nfrom keras.callbacks import ReduceLROnPlateau\n\n\nsns.set(style='white', context='notebook', palette='deep')","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"86061d98eccaa02efe0dab0fa3884e71fcf4c310","_cell_guid":"6d2fb3e6-ab71-4974-b5a2-4af1ebdb99f4"},"cell_type":"markdown","source":"## 2. Préparation des données\n### 2.1 Chargement des données"},{"metadata":{"_execution_state":"idle","_uuid":"84bbd5ab8d7895bd430d5ecfe2f7ddf77baa7b74","_cell_guid":"5e51d00e-62fd-4141-bf73-50ac4f2da7d0","trusted":true},"cell_type":"code","source":"train = pd.read_csv(\"../input/train.csv\")\ntest = pd.read_csv(\"../input/test.csv\")","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"1213b979d5ed3e0d13824d17d694c79d2ece92fa","_cell_guid":"86570a36-5c20-460a-9dfd-2070548532a7","trusted":true},"cell_type":"code","source":"Y_train = train[\"label\"]\n\n# On enlève la colonne 'label'\nX_train = train.drop(labels = [\"label\"],axis = 1) \n\n# On fait de l'espace\ndel train \n\n# On affiche le nombre de chiffres dans le jeu de données\ng = sns.countplot(Y_train)\n\nY_train.value_counts()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b7b1b1d36243c885e57374c8b60c5a7e10abe922","_cell_guid":"5aea4062-1790-4987-b739-c4bebd79030f"},"cell_type":"markdown","source":"Les quantités d'images pour chaque nombre sont similaires."},{"metadata":{"_uuid":"5d77934302869925c19128c77e247b3c8ca84d71","_cell_guid":"5b7d4b66-a140-4fcc-a889-bcef007c880a"},"cell_type":"markdown","source":"### 2.2 Recherche de valeurs malformées"},{"metadata":{"_execution_state":"idle","_uuid":"cdf27c27e2a5b15e6d7bfc70de7a18c08f3feb7a","_cell_guid":"ececaa00-2ae3-4d13-b631-438df085b030","trusted":true},"cell_type":"code","source":"X_train.isnull().any().describe()","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"a0089bb7ec9aec76373db475399aea24699ae989","_cell_guid":"92572e80-8543-4e72-8767-5c9be8381b04","trusted":true},"cell_type":"code","source":"test.isnull().any().describe()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0ecf4b52510ab7957d0d4eb646c0aa1ba5986273","_cell_guid":"159d5854-437a-4d0f-bc1e-fc3f7e43d178"},"cell_type":"markdown","source":"### 2.3 Normalisation\n\n\nOn effectue une normalisation en niveau de gris pour réduire les effets de différences d'illuminations. Par ailleurs, le CNN converge plus facilement sur des données normalisées que des données sur [0,255]"},{"metadata":{"_execution_state":"idle","_uuid":"b5d4f8fcf2a967e2c7d57daedf95aa8c5ab7f8cb","_cell_guid":"cdc4340b-6e24-4e12-be99-ac806098ff17","trusted":true},"cell_type":"code","source":"X_train = X_train / 255.0\ntest = test / 255.0","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a66741bf1ac597094f3a3166877008feef27c519","_cell_guid":"7413df94-bcb9-4f75-b174-c127d4445766"},"cell_type":"markdown","source":"## 2.3 Reshape d'images"},{"metadata":{"_execution_state":"idle","_uuid":"f0a6ad80dab8e0f2c2e46165ccd9cd82dd162bc3","_cell_guid":"34b6a5f7-8fd2-4387-8ef4-c9dc19584fed","trusted":true},"cell_type":"code","source":"X_train = X_train.values.reshape(-1,28,28,1)\ntest = test.values.reshape(-1,28,28,1)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f4fb5553e188d9956f5d8b3a5d275ab00ea667ce","_cell_guid":"8decd1ce-7b7e-431d-8458-eaca18e0e1f7"},"cell_type":"markdown","source":"Les images d'entraînement et de test (28px x 28px) sont stockées dans une dataframe *Pandas* comme un vecteur de 1D avec 784 valeurs. On restructure toutes les données.\n\nKeras a besoin d'une dimension supplémentaire à la fin qui correspond aux canaux. Les images **MNIST** sont en niveau de gris donc elles utilisent qu'un seul canal. Pour le RGB, on se retrouve avec 3 canaux, ce qui nous donne 28\\*28\\*3 matrices 3D."},{"metadata":{"_uuid":"39b7a31e843bac6b705461bcce89da216b91799e","_cell_guid":"bdb422e2-bdec-444f-97a5-283a1e54bf2c"},"cell_type":"markdown","source":"### 2.5 Encodage de labels"},{"metadata":{"_execution_state":"idle","_uuid":"cabefd1478d5c1bdfe57fd6a34395340916a854c","_cell_guid":"4b7f3e78-44dc-4561-b1f0-9429ee024cf4","trusted":true},"cell_type":"code","source":"# Encodage des labels en one-hot vectors (ex : 2 -> [0,0,1,0,0,0,0,0,0,0], 9 -> [0,0,0,0,0,0,0,0,0,1])\nY_train = to_categorical(Y_train, num_classes = 10)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d8abbbf31483b94e1b29d07c4c8253d1311648a7","_cell_guid":"32152fc3-a570-4d64-8a7d-6c689a4acd33"},"cell_type":"markdown","source":"### 2.6 Séparation du set d'entraînement et de validation"},{"metadata":{"_execution_state":"idle","_uuid":"6e51c925c6e0f1b936679c9649fef345c853555f","_cell_guid":"3a698301-9759-4279-ae48-fd980f89ea53","trusted":true},"cell_type":"code","source":"random_seed = 2","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"b779ac76d8317647db92d5a88b4098d212d72884","_cell_guid":"dcd25ebb-d845-4d32-9867-082e352b1396","trusted":true},"cell_type":"code","source":"X_train, X_val, Y_train, Y_val = train_test_split(X_train, Y_train, test_size = 0.1, random_state=random_seed)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"72ed54a305eebf80e8b8b0f7eabde1332a5a85a3","_cell_guid":"3c99964f-4500-4f1c-947d-c67e644e34db"},"cell_type":"markdown","source":"Nous avons choisi de séparer le set en deux parties : une petite fraction (10%) qui est devenue le set de validation et le reste est devenue le set d'entraînement.\n\nComme il y a 42 000 images d'entraînement de labels uniformément répartis, une séparation au hasard du set d'entraînement ne cause pas de sur-représentation.\n\nIl est possible de voir à quoi ressemble une de ces images en regardant l'image ainsi que son label."},{"metadata":{"_execution_state":"idle","_uuid":"e0dae8943d3d35f075dba3d7ba31bde1d4bf2ff4","_cell_guid":"5f76131b-4ba0-45f1-a98c-bd4e7d561793","trusted":true},"cell_type":"code","source":"g = plt.imshow(X_train[0][:,:,0])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7697570491420f957f6e4d3569d51410b5277250","_cell_guid":"504fa00e-148c-4364-9b68-218b3aaedfdb"},"cell_type":"markdown","source":"## 3. Réseau de neurones convolutifs\n\n### 3.1 Définition du modèle\n\nNous avons utilisé l'API *Keras Sequential*, avec laquelle il suffit juste d'ajouter les couches une à une, en commençant par les entrées.\n\nLa première couche correspond à une couche convolutive (Conv2D). C'est comme un ensemble de filtres qui changent en apprenant de ces erreurs. Les deux premières couches sont composées de 32 filtres et les deux dernières de 64. Chaque filtre transforme une partie de l'image en utilisant le filtre noyau. La matrice du filtre noyau est appliquée à toute l'image. Les filtres peuvent être considérés comme une transformation de l'image.\n\nLe CNN peut isoler des caractéristiques utilisables pour toutes les images.\n\nLa deuxième partie du CNN correspond au pooling. Cette couche agit comme un filtre de sous-echantillonage. Elle regarde 2 pixels avoisinants et choisit le maximum.\n\nEn combinant les couches de pooling et de convolution, le CNN est capable de combiner des caractéristiques locales avec des caractéristiques globales.\n\n*Dropout* est une méthode de régularisation, dans laquelle les proportions des noeuds de chaque couche sont ignorées de manière aléatoire pour chaque échantillon de test. Cela permet d'oublier aléatoirement une partie du réseau et force ce dernier à apprendre des caractéristiques de manière distribuée. Cette méthode évite les généralisations et réduit la possibilité de sur-aprentissage.\n\n*Relu* correspond au rectificateur. Cette fonction permet d'ajouter de la non linéarité au réseau.\n\nLa couche *Flatten* est utilisée pour convertir les caractéristiques en un vecteur 1D. Cette étape \"d'applatissement\" est nécessaire car elle permet de connecter toutes les couches. Elle combine toutes les caractéristiques locales des couches convolutives précédentes.\n\n"},{"metadata":{"_execution_state":"idle","_uuid":"f7991ef6871a26f9fa57acdcd460a69bab53e804","_cell_guid":"1e0f3f88-2ad7-459e-8e02-aecc5f3511ae","trusted":true},"cell_type":"code","source":"# In -> [[Conv2D->relu]*2 -> MaxPool2D -> Dropout]*2 -> Flatten -> Dense -> Dropout -> Out\n\nmodel = Sequential()\n\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu', input_shape = (28,28,1)))\nmodel.add(Conv2D(filters = 32, kernel_size = (5,5),padding = 'Same', \n                 activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2)))\nmodel.add(Dropout(0.25))\n\n\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(Conv2D(filters = 64, kernel_size = (3,3),padding = 'Same', \n                 activation ='relu'))\nmodel.add(MaxPool2D(pool_size=(2,2), strides=(2,2)))\nmodel.add(Dropout(0.25))\n\n\nmodel.add(Flatten())\nmodel.add(Dense(256, activation = \"relu\"))\nmodel.add(Dropout(0.5))\nmodel.add(Dense(10, activation = \"softmax\"))","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7065512cf892ba49f0c06e239e3a20ff13667ef2","_cell_guid":"0e26b6a3-ef9d-4ae5-9d79-d5e4b073251a"},"cell_type":"markdown","source":"### 3.2 Mise en place de l'optimisateur\n\nUne fois les couches ajoutées au modèle, il nous faut mettre en place une fonction de score, une fonction de perte et enfin un algo d'optimisation.\n\n\nOn définit la fonction de perte afin de mesurer comment performe notre modèle sur les images dont les labels sont connus. C'est le taux d'erreur entre le label observé et celui qui a été prédit. On utilise une forme spécifique de classification catégorique nommée '*categorical_entropy*'.\n\nLa fonction la plus importante est l'optimisateur. De manière itérative, cette fonction va améliorer les paramètres du réseau afin de minimiser la perte.\n\nNous avons choisi *RMSprop* car il s'agit d'un optimisateur très efficace. \n\nLa fonction métrique de *précision* est utilisée pour évaluer la performance de notre modèle. Cette fonction est similaire à la fonction de perte, sauf que les données récupérées par la fonction ne sont pas utilisées lors de l'entraînement du modèle.\n\n"},{"metadata":{"_execution_state":"idle","_uuid":"420c704367b397b8255fefe9d882b35ac8929b95","_cell_guid":"a4c55409-6a65-400a-b5e8-a1dc535429c0","trusted":true},"cell_type":"code","source":"optimizer = RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"b4c0288622227a3cd05479aa765e324dbb852f34","_cell_guid":"0bd89b79-1a74-40da-af9a-7a76a8b96ff2","trusted":true},"cell_type":"code","source":"model.compile(optimizer = optimizer , loss = \"categorical_crossentropy\", metrics=[\"accuracy\"])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"bb90d48f4426d1baeb0404f2431e04e3cade59df","_cell_guid":"35b826b6-c516-47d0-8469-f8d04a102118"},"cell_type":"markdown","source":"Afin que l'optimisateur converge plus rapidement au minimum global de la fonction d'évaluation, nous avons utilisé une méthode de températion pour le taux d'apprentissage (T.A).\n\nLe T.A est l'étape par laquelle l'optimisateur traverse le \"paysage de perte\". Plus le T.A est important, plus les pas sont grands et convergent rapidement. Cependant, si l'échantillonage est trop faible et que le T.A est trop important, l'optimisateur pourrait tomber sur des minimas locaux.\n\nIl est plus important d'avoir un T.A qui baisse durant la phase d'entraînement dans le but d'atteindre le minimum globale de manière efficiente.\n\nPour garder les avantages d'un calcul rapide avec un T.A elevé, nous avons baissé le T.A dynamiquement tous les 'x' pas (epochs) si c'est nécessaire.\n\nAvec la fonction *ReduceLROnPlateau*, nous avons choisi de réduire le T.A de moitié si la précision n'augmente pas après trois epochs consécutifs.\n"},{"metadata":{"_execution_state":"idle","_uuid":"c4a5b4e462ec5362c47eef4fcc7956fd4e203307","_cell_guid":"b5987a18-6bbe-42a2-9d31-333ebc4f7af1","trusted":true},"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor=\"val_loss\", \n                                            patience=3, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.00001)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"26b0647c46efdb6b1096cf7335a7bf2a3417543a","_cell_guid":"970db455-b393-4b25-806d-92c6766c12c0","trusted":true},"cell_type":"code","source":"epochs = 1\nbatch_size = 86","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9e498b91419439f0fa791e595f202d9a0d56ad6b","_cell_guid":"e2d41e30-0724-40fb-a901-750e514ba9f9"},"cell_type":"markdown","source":"### 3.3 Augmentation des données\n\nAfin d'éviter un problème de surapprentissage, il nous faut étendre artificiellement le dataset. Il est possible de rendre notre dataset original encore plus grand. L'idée est la suivante : il faut altérer les données d'entraînement avec des petites transformations pour reproduire les variations qui interviennent lorsque quelqu'un écrit un chiffre.\n\nPar exemple, le nombre n'est pas centré. L'échelle de l'image est différente et l'orientation aussi.\n\nLes approches qui altèrent les données d'entraînement en gardant le même label sont connus comme des techniques d'augmentation de données. Le niveau de gris, la rotation, la translation... sont des techniques populaires d'augmentation.\n\nEn appliquant quelques techniques d'augmentation, il est possible d'agrandir notre jeu de données d'entraînement et de créer un modèle robuste.\n\nCette étape est importante car sans cette 'augmentation de données', la précision du modèle est moins bonne.\n\n\n"},{"metadata":{"_execution_state":"idle","_uuid":"d4e9e1ade3c04f9ca4d8cd44e799f9e09524d5a1","_cell_guid":"ade93d2d-90c6-4401-af95-f7d65f8c0a20","collapsed":true,"trusted":false},"cell_type":"code","source":"# Sans augmentation de données\n#history = model.fit(X_train, Y_train, batch_size = batch_size, epochs = epochs, \n#          validation_data = (X_val, Y_val), verbose = 2)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"21d6192c87d92d497c797656474bccd9cefc5647","_cell_guid":"b342befe-1a6f-44bf-8dab-28033a729122","trusted":true},"cell_type":"code","source":"# Avec augmentation de données\n\ndatagen = ImageDataGenerator(\n        featurewise_center=False,  \n        samplewise_center=False, \n        featurewise_std_normalization=False,  \n        samplewise_std_normalization=False, \n        zca_whitening=False,  \n        rotation_range=10,  \n        zoom_range = 0.1, \n        width_shift_range=0.1,  \n        height_shift_range=0.1,  \n        horizontal_flip=False, \n        vertical_flip=False)  \n\n\ndatagen.fit(X_train)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"51f16d0a5b9d9373438474e7defa7348359d7c18","_cell_guid":"22f80b8a-d4f6-4a34-b33d-ff7334f45d94"},"cell_type":"markdown","source":"Pour cette augmentation des données, nous avons choisi : \n- de faire des rotations\n- de faire des zooms\n- de faire des translations verticales\n- de faire des translations horizontales\n\nNous n'avons pas effectué d'inversions verticales/horizontales pour afin d'éviter que des chiffres se transforment en d'autres chiffres \n(ex: 6 --> 9)\n\n"},{"metadata":{"_execution_state":"idle","_uuid":"cf36b3d029f95b553be02d612e097a9769ee8252","_cell_guid":"b453af8d-9736-43e3-b486-7a1cd7dd8909","trusted":true},"cell_type":"code","source":"history = model.fit(datagen.flow(X_train,Y_train, batch_size=batch_size),\n                              epochs = epochs, \n                              validation_data = (X_val,Y_val),\n                              verbose = 2, \n                              steps_per_epoch=X_train.shape[0] // batch_size, \n                              callbacks=[learning_rate_reduction])","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"0a1834f2a9f2db15dcaba4a84004b9627d714469","_cell_guid":"e758621d-b27b-40ff-a93f-bebd2e0e5243"},"cell_type":"markdown","source":"## 4. Evaluer le modèle\n\n### 4.1 Entraînement et courbes\n"},{"metadata":{"_execution_state":"idle","_uuid":"3a831860dd5bb65c8ead1ddcf4ae18ae20dd7f3e","_cell_guid":"eb4b1b73-cbd4-40e8-9790-066fcef4c4c0","trusted":true},"cell_type":"code","source":"fig, ax = plt.subplots(2,1)\nax[0].plot(history.history['loss'], color='b', label=\"Training loss\")\nax[0].plot(history.history['val_loss'], color='r', label=\"validation loss\",axes =ax[0])\nlegend = ax[0].legend(loc='best', shadow=True)\n\nax[1].plot(history.history['accuracy'], color='b', label=\"Training accuracy\")\nax[1].plot(history.history['val_accuracy'], color='r',label=\"Validation accuracy\")\nlegend = ax[1].legend(loc='best', shadow=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"63698d7d51381b33892ce164b0f21930abb3e937","_cell_guid":"de1c65bd-4a88-4351-9f4b-562e72e7e0fd"},"cell_type":"markdown","source":"### 4.2 Matrice de confusion"},{"metadata":{"_uuid":"3306d29b732341663e50866140dc569360701a81","_cell_guid":"5688faa0-b33b-4e92-b125-7fa0b37e7df3"},"cell_type":"markdown","source":"La matrice de confusion est très utile car elle permet de voir les problèmes que le modèle rencontre.\n\nNous affichons la matrice de confusion des résultats de validation"},{"metadata":{"_execution_state":"idle","_uuid":"16e161179bf1b51ba66c39b2cead883f1db3a9c7","_cell_guid":"11361e73-8250-4bf5-a353-b0f8ea83e659","trusted":true},"cell_type":"code","source":"def plot_confusion_matrix(cm, classes,\n                          normalize=False,\n                          title='Confusion matrix',\n                          cmap=plt.cm.Blues):\n\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=45)\n    plt.yticks(tick_marks, classes)\n\n    if normalize:\n        cm = cm.astype('float') / cm.sum(axis=1)[:, np.newaxis]\n\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, cm[i, j],\n                 horizontalalignment=\"center\",\n                 color=\"white\" if cm[i, j] > thresh else \"black\")\n\n    plt.tight_layout()\n    plt.ylabel('True label')\n    plt.xlabel('Predicted label')\n\nY_pred = model.predict(X_val)\nY_pred_classes = np.argmax(Y_pred,axis = 1) \nY_true = np.argmax(Y_val,axis = 1) \nconfusion_mtx = confusion_matrix(Y_true, Y_pred_classes) \nplot_confusion_matrix(confusion_mtx, classes = range(10)) ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ecb928433299b163ecc1f6c4e66d4ddcf38fe898","_cell_guid":"1b8a5cdc-9122-4e31-b9fa-0f6b57d33fc8"},"cell_type":"markdown","source":"Il est possible de voir sur la matrice que le CNN performe très bien sur tous les nombres avec très peu d'erreurs si l'on prend en considération l'ensemble de données de validation (4 200 images).\n\nCependant, il semble que le CNN a un problème avec le chiffre 4 qu'il prend parfois pour le chiffre 9.\n\nInvestiguons les quelques erreurs obtenues. Nous voulons voir quels sont les erreurs les plus importantes. Pour ce faire, il nous faut la probabilité entre la valeur réelle et la valeur que le modèle a prédit."},{"metadata":{"_execution_state":"idle","_uuid":"e7a3d6449b499a29db224e42e950f21ca1ec4e36","_cell_guid":"7b0f31b8-c18b-4529-b0d8-eb4c31e30bbf","trusted":true},"cell_type":"code","source":"\nerrors = (Y_pred_classes - Y_true != 0)\n\nY_pred_classes_errors = Y_pred_classes[errors]\nY_pred_errors = Y_pred[errors]\nY_true_errors = Y_true[errors]\nX_val_errors = X_val[errors]\n\ndef display_errors(errors_index,img_errors,pred_errors, obs_errors):\n    \"\"\" Cette fonction montre 6 nombres avec leur prédiction et le vrai label\"\"\"\n    n = 0\n    nrows = 2\n    ncols = 3\n    fig, ax = plt.subplots(nrows,ncols,sharex=True,sharey=True)\n    for row in range(nrows):\n        for col in range(ncols):\n            error = errors_index[n]\n            ax[row,col].imshow((img_errors[error]).reshape((28,28)))\n            ax[row,col].set_title(\"Predicted label :{}\\nTrue label :{}\".format(pred_errors[error],obs_errors[error]))\n            n += 1\n\nY_pred_errors_prob = np.max(Y_pred_errors,axis = 1)\n\ntrue_prob_errors = np.diagonal(np.take(Y_pred_errors, Y_true_errors, axis=1))\n\ndelta_pred_true_errors = Y_pred_errors_prob - true_prob_errors\n\nsorted_dela_errors = np.argsort(delta_pred_true_errors)\n\nmost_important_errors = sorted_dela_errors[-6:]\n\ndisplay_errors(most_important_errors, X_val_errors, Y_pred_classes_errors, Y_true_errors)","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"afc408bd5545a6a2b2d4e04989890546263cb642","_cell_guid":"d21c4caf-e699-4647-8ef4-e60e868607ae"},"cell_type":"markdown","source":"Comme on peut le voir sur l'affichage, les erreurs les plus importantes sont les erreurs les plus intrigantes.\n\nPour les six cas affichés, le modèle n'est pas si ridicule que ça. Ces erreurs pourraient même être commises par un être humain."},{"metadata":{"_execution_state":"idle","_uuid":"7f17e7bf0a54a01a52fef2d554780f6bc6580dc6","_cell_guid":"05ff3b9f-c3bb-4cec-a8c2-2c128e8f15b3","trusted":true},"cell_type":"code","source":"results = model.predict(test)\n\nresults = np.argmax(results,axis = 1)\n\nresults = pd.Series(results,name=\"Label\")","execution_count":null,"outputs":[]},{"metadata":{"_execution_state":"idle","_uuid":"369dfaab09240f3f12bcff91953ffd315ab84985","_cell_guid":"b5f1f39f-13b8-439a-8913-0f120e3d47a9","trusted":true},"cell_type":"code","source":"submission = pd.concat([pd.Series(range(1,28001),name = \"ImageId\"),results],axis = 1)\n\nsubmission.to_csv(\"cnn_mnist_datagen.csv\",index=False)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}