| └── rapport.tex # Fichier source du rapport | └── 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 |
| self.__strides = [2, 1] if down_sample else [1, 1] | self.__strides = [2, 1] if down_sample else [1, 1] | ||||
| KERNEL_SIZE = (3, 3) | 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" | INIT_SCHEME = "he_normal" | ||||
| self.conv_1 = Conv2D(self.__channels, strides=self.__strides[0], | self.conv_1 = Conv2D(self.__channels, strides=self.__strides[0], | ||||
| self.merge = Add() | self.merge = Add() | ||||
| if self.__down_sample: | 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.__channels, strides=2, kernel_size=(1, 1), kernel_initializer=INIT_SCHEME, padding="same") | ||||
| self.res_bn = BatchNormalization() | self.res_bn = BatchNormalization() | ||||
| x = self.conv_1(inputs) | x = self.conv_1(inputs) | ||||
| x = self.bn_1(x) | 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.conv_2(x) | ||||
| x = self.bn_2(x) | x = self.bn_2(x) | ||||
| res = self.res_conv(res) | res = self.res_conv(res) | ||||
| res = self.res_bn(res) | res = self.res_bn(res) | ||||
| # if not perform down sample, then add a shortcut directly | |||||
| x = self.merge([x, res]) | x = self.merge([x, res]) | ||||
| out = tf.nn.relu(x) | |||||
| out = x + tf.sin(x)**2 #tf.nn.relu(x) | |||||
| return out | return out | ||||
| self.res_4_2 = ResnetBlock(512) | self.res_4_2 = ResnetBlock(512) | ||||
| self.avg_pool = GlobalAveragePooling2D() | self.avg_pool = GlobalAveragePooling2D() | ||||
| self.flat = Flatten() | self.flat = Flatten() | ||||
| self.fc = Dense(num_classes, activation="softmax") | |||||
| self.fc = Dense(num_classes, activation="sigmoid") | |||||
| def call(self, inputs): | def call(self, inputs): | ||||
| out = self.conv_1(inputs) | out = self.conv_1(inputs) | ||||
| out = self.init_bn(out) | out = self.init_bn(out) | ||||
| out = tf.nn.relu(out) | |||||
| out += tf.sin(out)**2 #tf.nn.relu(out) | |||||
| out = self.pool_2(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]: | 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) | out = res_block(out) |
| # Réseau inspiré de http://yann.lecun.com/exdb/publis/pdf/lecun-98.pdf | # 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 | from resnet18 import ResNet18 | ||||
| import tensorflow as tf | import tensorflow as tf | ||||
| import numpy as np | import numpy as np | ||||
| import matplotlib.pyplot as plt | 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)): | def displayConvFilers(model, layer_name, num_filter=4, filter_size=(3,3), num_channel=0, fig_size=(2,2)): | ||||
| ## Chargement et normalisation des données | ## Chargement et normalisation des données | ||||
| resnet18 = tf.keras.datasets.cifar10 | resnet18 = tf.keras.datasets.cifar10 | ||||
| (train_images, train_labels), (test_images, test_labels) = resnet18.load_data() | (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_images = train_images[40000:] | ||||
| val_labels = train_labels[40000:] | val_labels = train_labels[40000:] | ||||
| train_images = train_images[:40000] | train_images = train_images[:40000] | ||||
| train_labels = train_labels[:40000] | train_labels = train_labels[:40000] | ||||
| ''' | |||||
| train_images = train_images / 255.0 | train_images = train_images / 255.0 | ||||
| val_images = val_images /255.0 | val_images = val_images /255.0 | ||||
| test_images = test_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 | # 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 | # One hot encoding | ||||
| model = ResNet18(10) | model = ResNet18(10) | ||||
| model.build(input_shape = (None,32,32,3)) | 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 | ## Définition de l'architecture du modèle | ||||
| model = tf.keras.models.Sequential() | model = tf.keras.models.Sequential() | ||||
| # Expliquez à quoi correspondent les valeurs numériques qui définissent les couches du réseau | # Expliquez à quoi correspondent les valeurs numériques qui définissent les couches du réseau | ||||
| history = model.fit(train_images, | history = model.fit(train_images, | ||||
| train_labels, | train_labels, | ||||
| batch_size=64, | |||||
| epochs=4, | |||||
| batch_size=256, | |||||
| epochs=50, | |||||
| validation_data=(val_images, val_labels), | validation_data=(val_images, val_labels), | ||||
| ) | ) | ||||
| { | |||||
| "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": [] | |||||
| } | |||||
| ] | |||||
| } |