| @@ -21,4 +21,20 @@ | |||
| └── rapport.tex # Fichier source du rapport | |||
| ``` | |||
| ## To do list | |||
| ## Emilien | |||
| Cette partie s'intéresse à l'efficacité de la fonction d'activation snake sur une tâche complexe de machine learning non-périodique. En effet pour que snake soit intéressant il faut qu'elle fasse aussi bien dans la plupart des tâches de ML comme la classification. | |||
| C'est pourquoi conformément à l'article un réseau de CNN ResNet18 est appliqué sur la base de données ciphar-10. | |||
| Pour utiliser : | |||
| Aller dans code/resnet18/ | |||
| ---> le fichier ResNet18.py est le script POO implémentant le réseau, les classes crées sont : | |||
| -- ResnetBlock une superclasse dont hérite la classe ResNet18, créant les resblock faisant apportant l'info résiduelle via la fonction call | |||
| -- ResNet18 qui implémente la structure de couches de convolution, elle prend comme argument le nombre de classe possible. Soit 10 dans le cas de CIPHAR-10 | |||
| Pour faire varier la fonction d'activation --> juste décommenter #tf.nn.relu(x) lignes 44, 54, 84 et commenter x + tf.sin(x)**2 | |||
| --> le fichier resnet_snake.ipynb est le notebook main python a exectuer faisant l'appel de toutes les fonctions ainsi que de la classe Resnet18 | |||
| @@ -20,7 +20,6 @@ class ResnetBlock(Model): | |||
| self.__strides = [2, 1] if down_sample else [1, 1] | |||
| KERNEL_SIZE = (3, 3) | |||
| # use He initialization, instead of Xavier (a.k.a 'glorot_uniform' in Keras), as suggested in [2] | |||
| INIT_SCHEME = "he_normal" | |||
| self.conv_1 = Conv2D(self.__channels, strides=self.__strides[0], | |||
| @@ -32,8 +31,8 @@ class ResnetBlock(Model): | |||
| self.merge = Add() | |||
| if self.__down_sample: | |||
| # perform down sampling using stride of 2, according to [1]. | |||
| self.res_conv = Conv2D( | |||
| self.res_conv = Conv2D( | |||
| self.__channels, strides=2, kernel_size=(1, 1), kernel_initializer=INIT_SCHEME, padding="same") | |||
| self.res_bn = BatchNormalization() | |||
| @@ -42,7 +41,7 @@ class ResnetBlock(Model): | |||
| x = self.conv_1(inputs) | |||
| x = self.bn_1(x) | |||
| x = tf.nn.relu(x) | |||
| x = x + tf.sin(x)**2 #tf.nn.relu(x) | |||
| x = self.conv_2(x) | |||
| x = self.bn_2(x) | |||
| @@ -50,9 +49,9 @@ class ResnetBlock(Model): | |||
| res = self.res_conv(res) | |||
| res = self.res_bn(res) | |||
| # if not perform down sample, then add a shortcut directly | |||
| x = self.merge([x, res]) | |||
| out = tf.nn.relu(x) | |||
| out = x + tf.sin(x)**2 #tf.nn.relu(x) | |||
| return out | |||
| @@ -77,12 +76,12 @@ class ResNet18(Model): | |||
| self.res_4_2 = ResnetBlock(512) | |||
| self.avg_pool = GlobalAveragePooling2D() | |||
| self.flat = Flatten() | |||
| self.fc = Dense(num_classes, activation="softmax") | |||
| self.fc = Dense(num_classes, activation="sigmoid") | |||
| def call(self, inputs): | |||
| out = self.conv_1(inputs) | |||
| out = self.init_bn(out) | |||
| out = tf.nn.relu(out) | |||
| out += tf.sin(out)**2 #tf.nn.relu(out) | |||
| out = self.pool_2(out) | |||
| for res_block in [self.res_1_1, self.res_1_2, self.res_2_1, self.res_2_2, self.res_3_1, self.res_3_2, self.res_4_1, self.res_4_2]: | |||
| out = res_block(out) | |||
| @@ -1,14 +1,12 @@ | |||
| # Réseau inspiré de http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf | |||
| from keras.callbacks import History | |||
| from tensorflow.python.ops.gen_array_ops import tensor_scatter_min_eager_fallback | |||
| from resnet18 import ResNet18 | |||
| import tensorflow as tf | |||
| import numpy as np | |||
| import matplotlib.pyplot as plt | |||
| # Pour les utilisateurs de MacOS (pour utiliser plt & keras en même temps) | |||
| import os | |||
| #os.environ['KMP_DUPLICATE_LIB_OK']='True' | |||
| def displayConvFilers(model, layer_name, num_filter=4, filter_size=(3,3), num_channel=0, fig_size=(2,2)): | |||
| @@ -35,21 +33,30 @@ def snake(x): | |||
| ## Chargement et normalisation des données | |||
| resnet18 = tf.keras.datasets.cifar10 | |||
| (train_images, train_labels), (test_images, test_labels) = resnet18.load_data() | |||
| train_images = train_images.astype('float32') | |||
| test_images = test_images.astype('float32') | |||
| from sklearn.model_selection import train_test_split | |||
| train_images, val_images, train_labels, val_labels = train_test_split(train_images,train_labels, test_size = 0.2,shuffle = True) | |||
| ''' | |||
| val_images = train_images[40000:] | |||
| val_labels = train_labels[40000:] | |||
| train_images = train_images[:40000] | |||
| train_labels = train_labels[:40000] | |||
| ''' | |||
| train_images = train_images / 255.0 | |||
| val_images = val_images /255.0 | |||
| test_images = test_images / 255.0 | |||
| # POUR LES CNN : On rajoute une dimension pour spécifier qu'il s'agit d'imgages en NdG | |||
| train_images = train_images.reshape(40000,32,32,3) | |||
| val_images = val_images.reshape(10000,32,32,3) | |||
| test_images = test_images.reshape(10000,32,32,3) | |||
| train_images = train_images.reshape(max(np.shape(train_images)),32,32,3) | |||
| val_images = val_images.reshape(max(np.shape(val_images)),32,32,3) | |||
| test_images = test_images.reshape(max(np.shape(test_images)),32,32,3) | |||
| # One hot encoding | |||
| @@ -61,9 +68,9 @@ filter_size_conv1 = (3,3) | |||
| model = ResNet18(10) | |||
| model.build(input_shape = (None,32,32,3)) | |||
| filter_size_conv1 = (5,5) | |||
| ''' | |||
| filter_size_conv1 = (5,5) | |||
| ## Définition de l'architecture du modèle | |||
| model = tf.keras.models.Sequential() | |||
| # Expliquez à quoi correspondent les valeurs numériques qui définissent les couches du réseau | |||
| @@ -92,8 +99,8 @@ model.compile(sgd, loss='categorical_crossentropy', metrics=['accuracy']) | |||
| history = model.fit(train_images, | |||
| train_labels, | |||
| batch_size=64, | |||
| epochs=4, | |||
| batch_size=256, | |||
| epochs=50, | |||
| validation_data=(val_images, val_labels), | |||
| ) | |||
| @@ -0,0 +1,151 @@ | |||
| { | |||
| "nbformat": 4, | |||
| "nbformat_minor": 0, | |||
| "metadata": { | |||
| "colab": { | |||
| "name": "Untitled1.ipynb", | |||
| "provenance": [], | |||
| "collapsed_sections": [] | |||
| }, | |||
| "kernelspec": { | |||
| "name": "python3", | |||
| "display_name": "Python 3" | |||
| }, | |||
| "language_info": { | |||
| "name": "python" | |||
| } | |||
| }, | |||
| "cells": [ | |||
| { | |||
| "cell_type": "code", | |||
| "execution_count": null, | |||
| "metadata": { | |||
| "id": "hUYO09lse0Ew" | |||
| }, | |||
| "outputs": [], | |||
| "source": [ | |||
| "from tensorflow.python.ops.gen_array_ops import tensor_scatter_min_eager_fallback\n", | |||
| "from resnet18 import ResNet18\n", | |||
| "import tensorflow as tf\n", | |||
| "import numpy as np\n", | |||
| "import matplotlib.pyplot as plt\n", | |||
| "\n", | |||
| "def snake(x):\n", | |||
| " return x + tf.sin(x)**2\n", | |||
| "\n" | |||
| ] | |||
| }, | |||
| { | |||
| "cell_type": "code", | |||
| "source": [ | |||
| "## Chargement et normalisation des données\n", | |||
| "resnet18 = tf.keras.datasets.cifar10\n", | |||
| "(train_images, train_labels), (test_images, test_labels) = resnet18.load_data()\n", | |||
| "train_images = train_images.astype('float32')\n", | |||
| "test_images = test_images.astype('float32')\n", | |||
| "\n", | |||
| "from sklearn.model_selection import train_test_split\n", | |||
| "train_images, val_images, train_labels, val_labels = train_test_split(train_images,train_labels, test_size = 0.2,shuffle = True)\n", | |||
| "\n", | |||
| "train_images = train_images / 255.0\n", | |||
| "val_images = val_images /255.0\n", | |||
| "test_images = test_images / 255.0\n", | |||
| "\n", | |||
| "# POUR LES CNN : un tenseur d'ordre 3 pour les images en couleurs\n", | |||
| "train_images = train_images.reshape(max(np.shape(train_images)),32,32,3)\n", | |||
| "val_images = val_images.reshape(max(np.shape(val_images)),32,32,3)\n", | |||
| "test_images = test_images.reshape(max(np.shape(test_images)),32,32,3)\n", | |||
| "\n", | |||
| "\n" | |||
| ], | |||
| "metadata": { | |||
| "id": "-iczeI91fEND" | |||
| }, | |||
| "execution_count": null, | |||
| "outputs": [] | |||
| }, | |||
| { | |||
| "cell_type": "code", | |||
| "source": [ | |||
| "# One hot encoding\n", | |||
| "train_labels = tf.keras.utils.to_categorical(train_labels)\n", | |||
| "val_labels = tf.keras.utils.to_categorical(val_labels)\n", | |||
| "test_labels = tf.keras.utils.to_categorical(test_labels)\n", | |||
| "\n", | |||
| "filter_size_conv1 = (3,3)\n", | |||
| "\n", | |||
| "\n", | |||
| "#création du réseau ResNet18\n", | |||
| "\n", | |||
| "model = ResNet18(10)\n", | |||
| "model.build(input_shape = (None,32,32,3))\n", | |||
| "print(model.summary())\n" | |||
| ], | |||
| "metadata": { | |||
| "id": "9UGNJFoRfGTz" | |||
| }, | |||
| "execution_count": null, | |||
| "outputs": [] | |||
| }, | |||
| { | |||
| "cell_type": "code", | |||
| "source": [ | |||
| "#Adam comme optimizer et categorical-crossentropy comme norme\n", | |||
| "sgd = tf.keras.optimizers.Adam()\n", | |||
| "model.compile(sgd, loss='categorical_crossentropy', metrics=['accuracy'])\n", | |||
| "\n", | |||
| "\n", | |||
| "\n", | |||
| "history = model.fit(train_images,\n", | |||
| " train_labels,\n", | |||
| " batch_size=64,\n", | |||
| " epochs=100,\n", | |||
| " validation_data=(val_images, val_labels),\n", | |||
| " )\n" | |||
| ], | |||
| "metadata": { | |||
| "id": "PtY0q1p5fM-p" | |||
| }, | |||
| "execution_count": null, | |||
| "outputs": [] | |||
| }, | |||
| { | |||
| "cell_type": "code", | |||
| "source": [ | |||
| "## Evaluation du modèle \n", | |||
| "test_loss, test_acc = model.evaluate(test_images, test_labels)\n", | |||
| "print('Test accuracy:', test_acc)\n", | |||
| "\n" | |||
| ], | |||
| "metadata": { | |||
| "id": "FcehZmotfPCx" | |||
| }, | |||
| "execution_count": null, | |||
| "outputs": [] | |||
| }, | |||
| { | |||
| "cell_type": "code", | |||
| "source": [ | |||
| "## on affiche et on sauvegarde les images\n", | |||
| "\n", | |||
| "fig, axs = plt.subplots(2, 1, figsize=(15,15))\n", | |||
| "\n", | |||
| "axs[0].plot(history.history['loss'])\n", | |||
| "axs[0].plot(history.history['val_loss'])\n", | |||
| "axs[0].title.set_text('Training Loss vs Validation Loss')\n", | |||
| "axs[0].legend(['Train', 'Val'])\n", | |||
| "\n", | |||
| "axs[1].plot(history.history['accuracy'])\n", | |||
| "axs[1].plot(history.history['val_accuracy'])\n", | |||
| "axs[1].title.set_text('Training Accuracy vs Validation Accuracy')\n", | |||
| "axs[1].legend(['Train', 'Val'])\n", | |||
| "plt.savefig('./resnet18snake.png')" | |||
| ], | |||
| "metadata": { | |||
| "id": "8USwL2YTfRGN" | |||
| }, | |||
| "execution_count": null, | |||
| "outputs": [] | |||
| } | |||
| ] | |||
| } | |||