{ "cells": [ { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# Convolution Nets for MNIST" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "Deep Learning models can take quite a bit of time to run, particularly if GPU isn't used. \n", "\n", "In the interest of time, you could sample a subset of observations (e.g. $1000$) that are a particular number of your choice (e.g. $6$) and $1000$ observations that aren't that particular number (i.e. $\\neq 6$). \n", "\n", "We will build a model using that and see how it performs on the test dataset" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "#Import the required libraries\n", "import numpy as np\n", "np.random.seed(1338)\n", "\n", "from keras.datasets import mnist" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from keras.models import Sequential\n", "from keras.layers.core import Dense, Dropout, Activation, Flatten" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from keras.layers.convolutional import Conv2D\n", "from keras.layers.pooling import MaxPooling2D" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "from keras.utils import np_utils\n", "from keras.optimizers import SGD" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "## Loading Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "#Load the training and testing data\n", "(X_train, y_train), (X_test, y_test) = mnist.load_data()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "X_test_orig = X_test" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "## Data Preparation" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "from keras import backend as K" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Very Important: \n", "When dealing with images & convolutions, it is paramount to handle `image_data_format` properly" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "img_rows, img_cols = 28, 28\n", "\n", "if K.image_data_format() == 'channels_first':\n", " shape_ord = (1, img_rows, img_cols)\n", "else: # channel_last\n", " shape_ord = (img_rows, img_cols, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Preprocess and Normalise Data" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "X_train = X_train.reshape((X_train.shape[0],) + shape_ord)\n", "X_test = X_test.reshape((X_test.shape[0],) + shape_ord)\n", "\n", "X_train = X_train.astype('float32')\n", "X_test = X_test.astype('float32')\n", "\n", "X_train /= 255\n", "X_test /= 255" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "np.random.seed(1338) # for reproducibilty!!\n", "\n", "# Test data\n", "X_test = X_test.copy()\n", "Y = y_test.copy()\n", "\n", "# Converting the output to binary classification(Six=1,Not Six=0)\n", "Y_test = Y == 6\n", "Y_test = Y_test.astype(int)\n", "\n", "# Selecting the 5918 examples where the output is 6\n", "X_six = X_train[y_train == 6].copy()\n", "Y_six = y_train[y_train == 6].copy()\n", "\n", "# Selecting the examples where the output is not 6\n", "X_not_six = X_train[y_train != 6].copy()\n", "Y_not_six = y_train[y_train != 6].copy()\n", "\n", "# Selecting 6000 random examples from the data that \n", "# only contains the data where the output is not 6\n", "random_rows = np.random.randint(0,X_six.shape[0],6000)\n", "X_not_six = X_not_six[random_rows]\n", "Y_not_six = Y_not_six[random_rows]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# Appending the data with output as 6 and data with output as <> 6\n", "X_train = np.append(X_six,X_not_six)\n", "\n", "# Reshaping the appended data to appropraite form\n", "X_train = X_train.reshape((X_six.shape[0] + X_not_six.shape[0],) + shape_ord)\n", "\n", "# Appending the labels and converting the labels to \n", "# binary classification(Six=1,Not Six=0)\n", "Y_labels = np.append(Y_six,Y_not_six)\n", "Y_train = Y_labels == 6 \n", "Y_train = Y_train.astype(int)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "print(X_train.shape, Y_labels.shape, X_test.shape, Y_test.shape)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "fragment" } }, "outputs": [], "source": [ "# Converting the classes to its binary categorical form\n", "nb_classes = 2\n", "Y_train = np_utils.to_categorical(Y_train, nb_classes)\n", "Y_test = np_utils.to_categorical(Y_test, nb_classes)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# A simple CNN" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "# -- Initializing the values for the convolution neural network\n", "\n", "nb_epoch = 2 # kept very low! Please increase if you have GPU\n", "\n", "batch_size = 64\n", "# number of convolutional filters to use\n", "nb_filters = 32\n", "# size of pooling area for max pooling\n", "nb_pool = 2\n", "# convolution kernel size\n", "nb_conv = 3\n", "\n", "sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Step 1: Model Definition" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "model = Sequential()\n", "\n", "model.add(Conv2D(nb_filters, (nb_conv, nb_conv), padding='valid', \n", " input_shape=shape_ord)) # note: the very first layer **must** always specify the input_shape\n", "model.add(Activation('relu'))\n", "\n", "model.add(Flatten())\n", "model.add(Dense(nb_classes))\n", "model.add(Activation('softmax'))" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Step 2: Compile" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true }, "outputs": [], "source": [ "model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "#### Step 3: Fit" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "hist = model.fit(X_train, Y_train, batch_size=batch_size, \n", " epochs=nb_epoch, verbose=1, \n", " validation_data=(X_test, Y_test))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "%matplotlib inline\n", "\n", "plt.figure()\n", "plt.xlabel('Epochs')\n", "plt.ylabel('Loss')\n", "plt.plot(hist.history['loss'])\n", "plt.plot(hist.history['val_loss'])\n", "plt.legend(['Training', 'Validation'])\n", "\n", "plt.figure()\n", "plt.xlabel('Epochs')\n", "plt.ylabel('Accuracy')\n", "plt.plot(hist.history['acc'])\n", "plt.plot(hist.history['val_acc'])\n", "plt.legend(['Training', 'Validation'], loc='lower right')" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "### Step 4: Evaluate" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "print('Available Metrics in Model: {}'.format(model.metrics_names))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "# Evaluating the model on the test data \n", "loss, accuracy = model.evaluate(X_test, Y_test, verbose=0)\n", "print('Test Loss:', loss)\n", "print('Test Accuracy:', accuracy)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "### Let's plot our model Predictions!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "import matplotlib.pyplot as plt\n", "\n", "%matplotlib inline" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "slice = 15\n", "predicted = model.predict(X_test[:slice]).argmax(-1)\n", "\n", "plt.figure(figsize=(16,8))\n", "for i in range(slice):\n", " plt.subplot(1, slice, i+1)\n", " plt.imshow(X_test_orig[i], interpolation='nearest')\n", " plt.text(0, 0, predicted[i], color='black', \n", " bbox=dict(facecolor='white', alpha=1))\n", " plt.axis('off')" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# Adding more Dense Layers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model = Sequential()\n", "model.add(Conv2D(nb_filters, (nb_conv, nb_conv),\n", " padding='valid', input_shape=shape_ord))\n", "model.add(Activation('relu'))\n", "\n", "model.add(Flatten())\n", "model.add(Dense(128))\n", "model.add(Activation('relu'))\n", "\n", "model.add(Dense(nb_classes))\n", "model.add(Activation('softmax'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", "model.fit(X_train, Y_train, batch_size=batch_size, \n", " epochs=nb_epoch,verbose=1,\n", " validation_data=(X_test, Y_test))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "#Evaluating the model on the test data \n", "score, accuracy = model.evaluate(X_test, Y_test, verbose=0)\n", "print('Test score:', score)\n", "print('Test accuracy:', accuracy)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# Adding Dropout" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model = Sequential()\n", "\n", "model.add(Conv2D(nb_filters, (nb_conv, nb_conv),\n", " padding='valid',\n", " input_shape=shape_ord))\n", "model.add(Activation('relu'))\n", "\n", "model.add(Flatten())\n", "model.add(Dense(128))\n", "model.add(Activation('relu'))\n", "model.add(Dropout(0.5))\n", "model.add(Dense(nb_classes))\n", "model.add(Activation('softmax'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", "model.fit(X_train, Y_train, batch_size=batch_size, \n", " epochs=nb_epoch,verbose=1,\n", " validation_data=(X_test, Y_test))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "#Evaluating the model on the test data \n", "score, accuracy = model.evaluate(X_test, Y_test, verbose=0)\n", "print('Test score:', score)\n", "print('Test accuracy:', accuracy)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# Adding more Convolution Layers" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model = Sequential()\n", "model.add(Conv2D(nb_filters, (nb_conv, nb_conv),\n", " padding='valid', input_shape=shape_ord))\n", "model.add(Activation('relu'))\n", "model.add(Convolution2D(nb_filters, (nb_conv, nb_conv)))\n", "model.add(Activation('relu'))\n", "model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))\n", "model.add(Dropout(0.25))\n", " \n", "model.add(Flatten())\n", "model.add(Dense(128))\n", "model.add(Activation('relu'))\n", "model.add(Dropout(0.5))\n", "model.add(Dense(nb_classes))\n", "model.add(Activation('softmax'))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "outputs": [], "source": [ "model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", "model.fit(X_train, Y_train, batch_size=batch_size, \n", " epochs=nb_epoch,verbose=1,\n", " validation_data=(X_test, Y_test))" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "#Evaluating the model on the test data \n", "score, accuracy = model.evaluate(X_test, Y_test, verbose=0)\n", "print('Test score:', score)\n", "print('Test accuracy:', accuracy)" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "# Exercise\n", "\n", "The above code has been written as a function. \n", "\n", "Change some of the **hyperparameters** and see what happens. " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true, "deletable": true, "editable": true, "slideshow": { "slide_type": "skip" } }, "outputs": [], "source": [ "# Function for constructing the convolution neural network\n", "# Feel free to add parameters, if you want\n", "\n", "def build_model():\n", " \"\"\"\"\"\"\n", " model = Sequential()\n", " model.add(Conv2D(nb_filters, (nb_conv, nb_conv), \n", " padding='valid',\n", " input_shape=shape_ord))\n", " model.add(Activation('relu'))\n", " model.add(Conv2D(nb_filters, (nb_conv, nb_conv)))\n", " model.add(Activation('relu'))\n", " model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))\n", " model.add(Dropout(0.25))\n", " \n", " model.add(Flatten())\n", " model.add(Dense(128))\n", " model.add(Activation('relu'))\n", " model.add(Dropout(0.5))\n", " model.add(Dense(nb_classes))\n", " model.add(Activation('softmax'))\n", " \n", " model.compile(loss='categorical_crossentropy',\n", " optimizer='sgd',\n", " metrics=['accuracy'])\n", "\n", " model.fit(X_train, Y_train, batch_size=batch_size, \n", " epochs=nb_epoch,verbose=1,\n", " validation_data=(X_test, Y_test))\n", " \n", "\n", " #Evaluating the model on the test data \n", " score, accuracy = model.evaluate(X_test, Y_test, verbose=0)\n", " print('Test score:', score)\n", " print('Test accuracy:', accuracy)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false, "deletable": true, "editable": true }, "outputs": [], "source": [ "#Timing how long it takes to build the model and test it.\n", "%timeit -n1 -r1 build_model()" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "slide" } }, "source": [ "# Batch Normalisation" ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true }, "source": [ "Normalize the activations of the previous layer at each batch, i.e. applies a transformation that maintains the mean activation close to 0 and the activation standard deviation close to 1." ] }, { "cell_type": "markdown", "metadata": { "deletable": true, "editable": true, "slideshow": { "slide_type": "subslide" } }, "source": [ "## How to BatchNorm in Keras" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "from keras.layers.normalization import BatchNormalization\n", "\n", "BatchNormalization(axis=-1, momentum=0.99, epsilon=0.001, center=True, scale=True, \n", " beta_initializer='zeros', gamma_initializer='ones', moving_mean_initializer='zeros',\n", " moving_variance_initializer='ones', beta_regularizer=None, gamma_regularizer=None,\n", " beta_constraint=None, gamma_constraint=None)\n", "```\n", "\n", "#### Arguments\n", "\n", "
Conv2D layer with\n",
" data_format=\"channels_first\",\n",
" set axis=1 in BatchNormalization.beta to normalized tensor.\n",
" If False, beta is ignored.gamma.\n",
" If False, gamma is not used.\n",
" When the next layer is linear (also e.g. nn.relu),\n",
" this can be disabled since the scaling\n",
" will be done by the next layer.