{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Keras tutorial - Emotion Detection in Images of Faces\n",
    "\n",
    "Welcome to the first assignment of week 2. In this assignment, you will:\n",
    "1. Learn to use Keras, a high-level neural networks API (programming framework), written in Python and capable of running on top of several lower-level frameworks including TensorFlow and CNTK. \n",
    "2. See how you can in a couple of hours build a deep learning algorithm.\n",
    "\n",
    "#### Why are we using Keras? \n",
    "\n",
    "* Keras was developed to enable deep learning engineers to build and experiment with different models very quickly. \n",
    "* Just as TensorFlow is a higher-level framework than Python, Keras is an even higher-level framework and provides additional abstractions. \n",
    "* Being able to go from idea to result with the least possible delay is key to finding good models. \n",
    "* However, Keras is more restrictive than the lower-level frameworks, so there are some very complex models that you would still implement in TensorFlow rather than in Keras. \n",
    "* That being said, Keras will work fine for many common models. "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## <font color='darkblue'>Updates</font>\n",
    "\n",
    "#### If you were working on the notebook before this update...\n",
    "* The current notebook is version \"v2a\".\n",
    "* You can find your original work saved in the notebook with the previous version name (\"v2\").\n",
    "* To view the file directory, go to the menu \"File->Open\", and this will open a new tab that shows the file directory.\n",
    "\n",
    "#### List of updates\n",
    "* Changed back-story of model to \"emotion detection\" from \"happy house.\"\n",
    "* Cleaned/organized wording of instructions and commentary.\n",
    "* Added instructions on how to set `input_shape`\n",
    "* Added explanation of \"objects as functions\" syntax.\n",
    "* Clarified explanation of variable naming convention.\n",
    "* Added hints for steps 1,2,3,4"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load packages\n",
    "* In this exercise, you'll work on the \"Emotion detection\" model, which we'll explain below. \n",
    "* Let's load the required packages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "Using TensorFlow backend.\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "from keras import layers\n",
    "from keras.layers import Input, Dense, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D\n",
    "from keras.layers import AveragePooling2D, MaxPooling2D, Dropout, GlobalMaxPooling2D, GlobalAveragePooling2D\n",
    "from keras.models import Model\n",
    "from keras.preprocessing import image\n",
    "from keras.utils import layer_utils\n",
    "from keras.utils.data_utils import get_file\n",
    "from keras.applications.imagenet_utils import preprocess_input\n",
    "import pydot\n",
    "from IPython.display import SVG\n",
    "from keras.utils.vis_utils import model_to_dot\n",
    "from keras.utils import plot_model\n",
    "from kt_utils import *\n",
    "\n",
    "import keras.backend as K\n",
    "K.set_image_data_format('channels_last')\n",
    "import matplotlib.pyplot as plt\n",
    "from matplotlib.pyplot import imshow\n",
    "\n",
    "%matplotlib inline"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Note**: As you can see, we've imported a lot of functions from Keras. You can use them by calling them directly in your code. Ex: `X = Input(...)` or `X = ZeroPadding2D(...)`. \n",
    "\n",
    "In other words, unlike TensorFlow, you don't have to create the graph and then make a separate `sess.run()` call to evaluate those variables."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1 - Emotion Tracking\n",
    "\n",
    "* A nearby community health clinic is helping the local residents monitor their mental health.  \n",
    "* As part of their study, they are asking volunteers to record their emotions throughout the day.\n",
    "* To help the participants more easily track their emotions, you are asked to create an app that will classify their emotions based on some pictures that the volunteers will take of their facial expressions.\n",
    "* As a proof-of-concept, you first train your model to detect if someone's emotion is classified as \"happy\" or \"not happy.\"\n",
    "\n",
    "To build and train this model, you have gathered pictures of some volunteers in a nearby neighborhood. The dataset is labeled.\n",
    "<img src=\"images/face_images.png\" style=\"width:550px;height:250px;\">\n",
    "\n",
    "Run the following code to normalize the dataset and learn about its shapes."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of training examples = 600\n",
      "number of test examples = 150\n",
      "X_train shape: (600, 64, 64, 3)\n",
      "Y_train shape: (600, 1)\n",
      "X_test shape: (150, 64, 64, 3)\n",
      "Y_test shape: (150, 1)\n"
     ]
    }
   ],
   "source": [
    "X_train_orig, Y_train_orig, X_test_orig, Y_test_orig, classes = load_dataset()\n",
    "\n",
    "# Normalize image vectors\n",
    "X_train = X_train_orig/255.\n",
    "X_test = X_test_orig/255.\n",
    "\n",
    "# Reshape\n",
    "Y_train = Y_train_orig.T\n",
    "Y_test = Y_test_orig.T\n",
    "\n",
    "print (\"number of training examples = \" + str(X_train.shape[0]))\n",
    "print (\"number of test examples = \" + str(X_test.shape[0]))\n",
    "print (\"X_train shape: \" + str(X_train.shape))\n",
    "print (\"Y_train shape: \" + str(Y_train.shape))\n",
    "print (\"X_test shape: \" + str(X_test.shape))\n",
    "print (\"Y_test shape: \" + str(Y_test.shape))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Details of the \"Face\" dataset**:\n",
    "- Images are of shape (64,64,3)\n",
    "- Training: 600 pictures\n",
    "- Test: 150 pictures"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2 - Building a model in Keras\n",
    "\n",
    "Keras is very good for rapid prototyping. In just a short time you will be able to build a model that achieves outstanding results.\n",
    "\n",
    "Here is an example of a model in Keras:\n",
    "\n",
    "```python\n",
    "def model(input_shape):\n",
    "    \"\"\"\n",
    "    input_shape: The height, width and channels as a tuple.  \n",
    "        Note that this does not include the 'batch' as a dimension.\n",
    "        If you have a batch like 'X_train', \n",
    "        then you can provide the input_shape using\n",
    "        X_train.shape[1:]\n",
    "    \"\"\"\n",
    "    \n",
    "    # Define the input placeholder as a tensor with shape input_shape. Think of this as your input image!\n",
    "    X_input = Input(input_shape)\n",
    "\n",
    "    # Zero-Padding: pads the border of X_input with zeroes\n",
    "    X = ZeroPadding2D((3, 3))(X_input)\n",
    "\n",
    "    # CONV -> BN -> RELU Block applied to X\n",
    "    X = Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0')(X)\n",
    "    X = BatchNormalization(axis = 3, name = 'bn0')(X)\n",
    "    X = Activation('relu')(X)\n",
    "\n",
    "    # MAXPOOL\n",
    "    X = MaxPooling2D((2, 2), name='max_pool')(X)\n",
    "\n",
    "    # FLATTEN X (means convert it to a vector) + FULLYCONNECTED\n",
    "    X = Flatten()(X)\n",
    "    X = Dense(1, activation='sigmoid', name='fc')(X)\n",
    "\n",
    "    # Create model. This creates your Keras model instance, you'll use this instance to train/test the model.\n",
    "    model = Model(inputs = X_input, outputs = X, name='HappyModel')\n",
    "    \n",
    "    return model\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Variable naming convention\n",
    "\n",
    "* Note that Keras uses a different convention with variable names than we've previously used with numpy and TensorFlow. \n",
    "* Instead of creating unique variable names for each step and each layer, such as \n",
    "```\n",
    "X = ...\n",
    "Z1 = ...\n",
    "A1 = ...\n",
    "```\n",
    "* Keras re-uses and overwrites the same variable at each step:\n",
    "```\n",
    "X = ...\n",
    "X = ...\n",
    "X = ...\n",
    "```\n",
    "* The exception is `X_input`, which we kept separate since it's needed later."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Objects as functions\n",
    "* Notice how there are two pairs of parentheses in each statement.  For example:\n",
    "```\n",
    "X = ZeroPadding2D((3, 3))(X_input)\n",
    "```\n",
    "* The first is a constructor call which creates an object (ZeroPadding2D).\n",
    "* In Python, objects can be called as functions. Search for 'python object as function and you can read this blog post [Python Pandemonium](https://medium.com/python-pandemonium/function-as-objects-in-python-d5215e6d1b0d).  See the section titled \"Objects as functions.\"\n",
    "* The single line is equivalent to this:\n",
    "```\n",
    "ZP = ZeroPadding2D((3, 3)) # ZP is an object that can be called as a function\n",
    "X = ZP(X_input) \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**Exercise**: Implement a `HappyModel()`.  \n",
    "* This assignment is more open-ended than most. \n",
    "* Start by implementing a model using the architecture we suggest, and run through the rest of this assignment using that as your initial model. * Later, come back and try out other model architectures. \n",
    "* For example, you might take inspiration from the model above, but then vary the network architecture and hyperparameters however you wish. \n",
    "* You can also use other functions such as `AveragePooling2D()`, `GlobalMaxPooling2D()`, `Dropout()`. \n",
    "\n",
    "**Note**: Be careful with your data's shapes. Use what you've learned in the videos to make sure your convolutional, pooling and fully-connected layers are adapted to the volumes you're applying it to."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# GRADED FUNCTION: HappyModel\n",
    "\n",
    "def HappyModel(input_shape):\n",
    "    \"\"\"\n",
    "    Implementation of the HappyModel.\n",
    "    \n",
    "    Arguments:\n",
    "    input_shape -- shape of the images of the dataset\n",
    "        (height, width, channels) as a tuple.  \n",
    "        Note that this does not include the 'batch' as a dimension.\n",
    "        If you have a batch like 'X_train', \n",
    "        then you can provide the input_shape using\n",
    "        X_train.shape[1:]\n",
    "\n",
    "    Returns:\n",
    "    model -- a Model() instance in Keras\n",
    "    \"\"\"\n",
    "    \n",
    "    ### START CODE HERE ###\n",
    "    # Feel free to use the suggested outline in the text above to get started, and run through the whole\n",
    "    # exercise (including the later portions of this notebook) once. The come back also try out other\n",
    "    # network architectures as well. \n",
    "    \n",
    "    # Define the input placeholder as a tensor with shape input_shape. Think of this as your input image!\n",
    "    X_input = Input(input_shape)\n",
    "\n",
    "    # Zero-Padding: pads the border of X_input with zeroes\n",
    "    X = ZeroPadding2D((3, 3))(X_input)\n",
    "\n",
    "    # CONV -> BN -> RELU Block applied to X\n",
    "    X = Conv2D(32, (7, 7), strides = (1, 1), name = 'conv0')(X)\n",
    "    X = BatchNormalization(axis = 3, name = 'bn0')(X)\n",
    "    X = Activation('relu')(X)\n",
    "\n",
    "    # MAXPOOL\n",
    "    X = MaxPooling2D((2, 2), name='max_pool')(X)\n",
    "\n",
    "    # FLATTEN X (means convert it to a vector) + FULLYCONNECTED\n",
    "    X = Flatten()(X)\n",
    "    X = Dense(1, activation='sigmoid', name='fc')(X)\n",
    "\n",
    "    # Create model. This creates your Keras model instance, you'll use this instance to train/test the model.\n",
    "    model = Model(inputs = X_input, outputs = X, name='HappyModel')\n",
    "\n",
    "    ### END CODE HERE ###\n",
    "    \n",
    "    return model"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "You have now built a function to describe your model. To train and test this model, there are four steps in Keras:\n",
    "1. Create the model by calling the function above  \n",
    "\n",
    "2. Compile the model by calling `model.compile(optimizer = \"...\", loss = \"...\", metrics = [\"accuracy\"])`  \n",
    "\n",
    "3. Train the model on train data by calling `model.fit(x = ..., y = ..., epochs = ..., batch_size = ...)`  \n",
    "\n",
    "4. Test the model on test data by calling `model.evaluate(x = ..., y = ...)`  \n",
    "\n",
    "If you want to know more about `model.compile()`, `model.fit()`, `model.evaluate()` and their arguments, refer to the official [Keras documentation](https://keras.io/models/model/)."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 1: create the model.  \n",
    "**Hint**:  \n",
    "The `input_shape` parameter is a tuple (height, width, channels).  It excludes the batch number.  \n",
    "Try `X_train.shape[1:]` as the `input_shape`."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "### START CODE HERE ### (1 line)\n",
    "happyModel = HappyModel(X_train.shape[1:])\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 2: compile the model\n",
    "\n",
    "**Hint**:  \n",
    "Optimizers you can try include `'adam'`, `'sgd'` or others.  See the documentation for [optimizers](https://keras.io/optimizers/)  \n",
    "The \"happiness detection\" is a binary classification problem.  The loss function that you can use is `'binary_cross_entropy'`.  Note that `'categorical_cross_entropy'` won't work with your data set as its formatted, because the data is an array of 0 or 1 rather than two arrays (one for each category).  Documentation for [losses](https://keras.io/losses/)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": [
    "### START CODE HERE ### (1 line)\n",
    "happyModel.compile(optimizer=\"adam\", loss=\"binary_crossentropy\", metrics=[\"accuracy\"])\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 3: train the model\n",
    "\n",
    "**Hint**:  \n",
    "Use the `'X_train'`, `'Y_train'` variables.  Use integers for the epochs and batch_size\n",
    "\n",
    "**Note**: If you run `fit()` again, the `model` will continue to train with the parameters it has already learned instead of reinitializing them."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/40\n",
      "600/600 [==============================] - 13s - loss: 1.0135 - acc: 0.7167    \n",
      "Epoch 2/40\n",
      "600/600 [==============================] - 14s - loss: 0.2618 - acc: 0.8933    \n",
      "Epoch 3/40\n",
      "600/600 [==============================] - 15s - loss: 0.1645 - acc: 0.9267    \n",
      "Epoch 4/40\n",
      "600/600 [==============================] - 15s - loss: 0.2936 - acc: 0.8900    \n",
      "Epoch 5/40\n",
      "600/600 [==============================] - 15s - loss: 0.1807 - acc: 0.9400    \n",
      "Epoch 6/40\n",
      "600/600 [==============================] - 12s - loss: 0.0837 - acc: 0.9733    \n",
      "Epoch 7/40\n",
      "600/600 [==============================] - 12s - loss: 0.1091 - acc: 0.9600    \n",
      "Epoch 8/40\n",
      "600/600 [==============================] - 12s - loss: 0.0626 - acc: 0.9800    \n",
      "Epoch 9/40\n",
      "600/600 [==============================] - 12s - loss: 0.0862 - acc: 0.9733    \n",
      "Epoch 10/40\n",
      "600/600 [==============================] - 12s - loss: 0.0622 - acc: 0.9833    \n",
      "Epoch 11/40\n",
      "600/600 [==============================] - 12s - loss: 0.1605 - acc: 0.9467    \n",
      "Epoch 12/40\n",
      "600/600 [==============================] - 12s - loss: 0.0742 - acc: 0.9700    \n",
      "Epoch 13/40\n",
      "600/600 [==============================] - 12s - loss: 0.1780 - acc: 0.9333    \n",
      "Epoch 14/40\n",
      "600/600 [==============================] - 12s - loss: 0.1964 - acc: 0.9417    \n",
      "Epoch 15/40\n",
      "600/600 [==============================] - 12s - loss: 0.1130 - acc: 0.9600    \n",
      "Epoch 16/40\n",
      "600/600 [==============================] - 12s - loss: 0.1369 - acc: 0.9517    \n",
      "Epoch 17/40\n",
      "600/600 [==============================] - 12s - loss: 0.1024 - acc: 0.9683    \n",
      "Epoch 18/40\n",
      "600/600 [==============================] - 12s - loss: 0.0844 - acc: 0.9700    \n",
      "Epoch 19/40\n",
      "600/600 [==============================] - 12s - loss: 0.0534 - acc: 0.9867    \n",
      "Epoch 20/40\n",
      "600/600 [==============================] - 12s - loss: 0.0500 - acc: 0.9817    \n",
      "Epoch 21/40\n",
      "600/600 [==============================] - 12s - loss: 0.0974 - acc: 0.9767    \n",
      "Epoch 22/40\n",
      "600/600 [==============================] - 12s - loss: 0.0916 - acc: 0.9667    \n",
      "Epoch 23/40\n",
      "600/600 [==============================] - 12s - loss: 0.0773 - acc: 0.9767    \n",
      "Epoch 24/40\n",
      "600/600 [==============================] - 12s - loss: 0.0758 - acc: 0.9767    \n",
      "Epoch 25/40\n",
      "600/600 [==============================] - 12s - loss: 0.0370 - acc: 0.9900    \n",
      "Epoch 26/40\n",
      "600/600 [==============================] - 12s - loss: 0.0383 - acc: 0.9833    \n",
      "Epoch 27/40\n",
      "600/600 [==============================] - 12s - loss: 0.0366 - acc: 0.9867    \n",
      "Epoch 28/40\n",
      "600/600 [==============================] - 12s - loss: 0.0338 - acc: 0.9900    \n",
      "Epoch 29/40\n",
      "600/600 [==============================] - 12s - loss: 0.0330 - acc: 0.9917    \n",
      "Epoch 30/40\n",
      "600/600 [==============================] - 12s - loss: 0.0949 - acc: 0.9683    \n",
      "Epoch 31/40\n",
      "600/600 [==============================] - 12s - loss: 0.0303 - acc: 0.9900    \n",
      "Epoch 32/40\n",
      "600/600 [==============================] - 12s - loss: 0.0433 - acc: 0.9883    \n",
      "Epoch 33/40\n",
      "600/600 [==============================] - 12s - loss: 0.0421 - acc: 0.9867    \n",
      "Epoch 34/40\n",
      "600/600 [==============================] - 12s - loss: 0.0431 - acc: 0.9850    \n",
      "Epoch 35/40\n",
      "600/600 [==============================] - 12s - loss: 0.0555 - acc: 0.9817    \n",
      "Epoch 36/40\n",
      "600/600 [==============================] - 12s - loss: 0.0772 - acc: 0.9800    \n",
      "Epoch 37/40\n",
      "600/600 [==============================] - 12s - loss: 0.0163 - acc: 0.9933    \n",
      "Epoch 38/40\n",
      "600/600 [==============================] - 12s - loss: 0.1446 - acc: 0.9633    \n",
      "Epoch 39/40\n",
      "600/600 [==============================] - 12s - loss: 0.0614 - acc: 0.9783    \n",
      "Epoch 40/40\n",
      "600/600 [==============================] - 12s - loss: 0.0907 - acc: 0.9783    \n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<keras.callbacks.History at 0x7f1f417b3710>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "### START CODE HERE ### (1 line)\n",
    "happyModel.fit(X_train, Y_train, epochs=40, batch_size=16)\n",
    "### END CODE HERE ###"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Step 4: evaluate model  \n",
    "**Hint**:  \n",
    "Use the `'X_test'` and `'Y_test'` variables to evaluate the model's performance."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "150/150 [==============================] - 1s     \n",
      "\n",
      "Loss = 0.217553080916\n",
      "Test Accuracy = 0.919999997616\n"
     ]
    }
   ],
   "source": [
    "### START CODE HERE ### (1 line)\n",
    "preds = happyModel.evaluate(X_test, Y_test)\n",
    "### END CODE HERE ###\n",
    "print()\n",
    "print (\"Loss = \" + str(preds[0]))\n",
    "print (\"Test Accuracy = \" + str(preds[1]))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Expected performance   \n",
    "If your `happyModel()` function worked, its accuracy should be better than random guessing (50% accuracy).\n",
    "\n",
    "To give you a point of comparison, our model gets around **95% test accuracy in 40 epochs** (and 99% train accuracy) with a mini batch size of 16 and \"adam\" optimizer."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### Tips for improving your model\n",
    "\n",
    "If you have not yet achieved a very good accuracy (>= 80%), here are some things tips:\n",
    "\n",
    "- Use blocks of CONV->BATCHNORM->RELU such as:\n",
    "```python\n",
    "X = Conv2D(32, (3, 3), strides = (1, 1), name = 'conv0')(X)\n",
    "X = BatchNormalization(axis = 3, name = 'bn0')(X)\n",
    "X = Activation('relu')(X)\n",
    "```\n",
    "until your height and width dimensions are quite low and your number of channels quite large (≈32 for example).  \n",
    "You can then flatten the volume and use a fully-connected layer.\n",
    "- Use MAXPOOL after such blocks.  It will help you lower the dimension in height and width.\n",
    "- Change your optimizer. We find 'adam' works well. \n",
    "- If you get memory issues, lower your batch_size (e.g. 12 )\n",
    "- Run more epochs until you see the train accuracy no longer improves. \n",
    "\n",
    "**Note**: If you perform hyperparameter tuning on your model, the test set actually becomes a dev set, and your model might end up overfitting to the test (dev) set. Normally, you'll want separate dev and test sets.  The dev set is used for parameter tuning, and the test set is used once to estimate the model's performance in production."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3 - Conclusion\n",
    "\n",
    "Congratulations, you have created a proof of concept for \"happiness detection\"!"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Key Points to remember\n",
    "- Keras is a tool we recommend for rapid prototyping. It allows you to quickly try out different model architectures.\n",
    "- Remember The four steps in Keras: \n",
    "\n",
    "\n",
    "1. Create  \n",
    "2. Compile  \n",
    "3. Fit/Train  \n",
    "4. Evaluate/Test  "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4 - Test with your own image (Optional)\n",
    "\n",
    "Congratulations on finishing this assignment. You can now take a picture of your face and see if it can classify whether your expression is \"happy\" or \"not happy\". To do that:\n",
    "\n",
    "\n",
    "1. Click on \"File\" in the upper bar of this notebook, then click \"Open\" to go on your Coursera Hub.\n",
    "2. Add your image to this Jupyter Notebook's directory, in the \"images\" folder\n",
    "3. Write your image's name in the following code\n",
    "4. Run the code and check if the algorithm is right (0 is not happy, 1 is happy)!\n",
    "    \n",
    "The training/test sets were quite similar; for example, all the pictures were taken against the same background (since a front door camera is always mounted in the same position). This makes the problem easier, but a model trained on this data may or may not work on your own data. But feel free to give it a try! "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[ 0.]]\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nF7+GRori/wOMhrX8XuEH+AAAAABJRU5ErkJggg==\n",
      "text/plain": [
       "<matplotlib.figure.Figure at 0x7f1f4124a2b0>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "### START CODE HERE ###\n",
    "img_path = 'images/my_image.jpg'\n",
    "### END CODE HERE ###\n",
    "img = image.load_img(img_path, target_size=(64, 64))\n",
    "imshow(img)\n",
    "\n",
    "x = image.img_to_array(img)\n",
    "x = np.expand_dims(x, axis=0)\n",
    "x = preprocess_input(x)\n",
    "\n",
    "print(happyModel.predict(x))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5 - Other useful functions in Keras (Optional)\n",
    "\n",
    "Two other basic features of Keras that you'll find useful are:\n",
    "- `model.summary()`: prints the details of your layers in a table with the sizes of its inputs/outputs\n",
    "- `plot_model()`: plots your graph in a nice layout. You can even save it as \".png\" using SVG() if you'd like to share it on social media ;). It is saved in \"File\" then \"Open...\" in the upper bar of the notebook.\n",
    "\n",
    "Run the following code."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "_________________________________________________________________\n",
      "Layer (type)                 Output Shape              Param #   \n",
      "=================================================================\n",
      "input_1 (InputLayer)         (None, 64, 64, 3)         0         \n",
      "_________________________________________________________________\n",
      "zero_padding2d_1 (ZeroPaddin (None, 70, 70, 3)         0         \n",
      "_________________________________________________________________\n",
      "conv0 (Conv2D)               (None, 64, 64, 32)        4736      \n",
      "_________________________________________________________________\n",
      "bn0 (BatchNormalization)     (None, 64, 64, 32)        128       \n",
      "_________________________________________________________________\n",
      "activation_1 (Activation)    (None, 64, 64, 32)        0         \n",
      "_________________________________________________________________\n",
      "max_pool (MaxPooling2D)      (None, 32, 32, 32)        0         \n",
      "_________________________________________________________________\n",
      "flatten_1 (Flatten)          (None, 32768)             0         \n",
      "_________________________________________________________________\n",
      "fc (Dense)                   (None, 1)                 32769     \n",
      "=================================================================\n",
      "Total params: 37,633\n",
      "Trainable params: 37,569\n",
      "Non-trainable params: 64\n",
      "_________________________________________________________________\n"
     ]
    }
   ],
   "source": [
    "happyModel.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": [
       "<svg height=\"556pt\" viewBox=\"0.00 0.00 219.00 556.00\" width=\"219pt\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n",
       "<g class=\"graph\" id=\"graph0\" transform=\"scale(1 1) rotate(0) translate(4 552)\">\n",
       "<title>G</title>\n",
       "<polygon fill=\"white\" points=\"-4,4 -4,-552 215,-552 215,4 -4,4\" stroke=\"none\"/>\n",
       "<!-- 139772220492208 -->\n",
       "<g class=\"node\" id=\"node1\"><title>139772220492208</title>\n",
       "<polygon fill=\"none\" points=\"43,-511.5 43,-547.5 168,-547.5 168,-511.5 43,-511.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-525.8\">input_1: InputLayer</text>\n",
       "</g>\n",
       "<!-- 139772220492824 -->\n",
       "<g class=\"node\" id=\"node2\"><title>139772220492824</title>\n",
       "<polygon fill=\"none\" points=\"0,-438.5 0,-474.5 211,-474.5 211,-438.5 0,-438.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-452.8\">zero_padding2d_1: ZeroPadding2D</text>\n",
       "</g>\n",
       "<!-- 139772220492208&#45;&gt;139772220492824 -->\n",
       "<g class=\"edge\" id=\"edge1\"><title>139772220492208-&gt;139772220492824</title>\n",
       "<path d=\"M105.5,-511.313C105.5,-503.289 105.5,-493.547 105.5,-484.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-484.529 105.5,-474.529 102,-484.529 109,-484.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772249865744 -->\n",
       "<g class=\"node\" id=\"node3\"><title>139772249865744</title>\n",
       "<polygon fill=\"none\" points=\"54,-365.5 54,-401.5 157,-401.5 157,-365.5 54,-365.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-379.8\">conv0: Conv2D</text>\n",
       "</g>\n",
       "<!-- 139772220492824&#45;&gt;139772249865744 -->\n",
       "<g class=\"edge\" id=\"edge2\"><title>139772220492824-&gt;139772249865744</title>\n",
       "<path d=\"M105.5,-438.313C105.5,-430.289 105.5,-420.547 105.5,-411.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-411.529 105.5,-401.529 102,-411.529 109,-411.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772220355976 -->\n",
       "<g class=\"node\" id=\"node4\"><title>139772220355976</title>\n",
       "<polygon fill=\"none\" points=\"28,-292.5 28,-328.5 183,-328.5 183,-292.5 28,-292.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-306.8\">bn0: BatchNormalization</text>\n",
       "</g>\n",
       "<!-- 139772249865744&#45;&gt;139772220355976 -->\n",
       "<g class=\"edge\" id=\"edge3\"><title>139772249865744-&gt;139772220355976</title>\n",
       "<path d=\"M105.5,-365.313C105.5,-357.289 105.5,-347.547 105.5,-338.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-338.529 105.5,-328.529 102,-338.529 109,-338.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772220358216 -->\n",
       "<g class=\"node\" id=\"node5\"><title>139772220358216</title>\n",
       "<polygon fill=\"none\" points=\"31.5,-219.5 31.5,-255.5 179.5,-255.5 179.5,-219.5 31.5,-219.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-233.8\">activation_1: Activation</text>\n",
       "</g>\n",
       "<!-- 139772220355976&#45;&gt;139772220358216 -->\n",
       "<g class=\"edge\" id=\"edge4\"><title>139772220355976-&gt;139772220358216</title>\n",
       "<path d=\"M105.5,-292.313C105.5,-284.289 105.5,-274.547 105.5,-265.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-265.529 105.5,-255.529 102,-265.529 109,-265.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772220358552 -->\n",
       "<g class=\"node\" id=\"node6\"><title>139772220358552</title>\n",
       "<polygon fill=\"none\" points=\"24,-146.5 24,-182.5 187,-182.5 187,-146.5 24,-146.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-160.8\">max_pool: MaxPooling2D</text>\n",
       "</g>\n",
       "<!-- 139772220358216&#45;&gt;139772220358552 -->\n",
       "<g class=\"edge\" id=\"edge5\"><title>139772220358216-&gt;139772220358552</title>\n",
       "<path d=\"M105.5,-219.313C105.5,-211.289 105.5,-201.547 105.5,-192.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-192.529 105.5,-182.529 102,-192.529 109,-192.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772220215704 -->\n",
       "<g class=\"node\" id=\"node7\"><title>139772220215704</title>\n",
       "<polygon fill=\"none\" points=\"50.5,-73.5 50.5,-109.5 160.5,-109.5 160.5,-73.5 50.5,-73.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-87.8\">flatten_1: Flatten</text>\n",
       "</g>\n",
       "<!-- 139772220358552&#45;&gt;139772220215704 -->\n",
       "<g class=\"edge\" id=\"edge6\"><title>139772220358552-&gt;139772220215704</title>\n",
       "<path d=\"M105.5,-146.313C105.5,-138.289 105.5,-128.547 105.5,-119.569\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-119.529 105.5,-109.529 102,-119.529 109,-119.529\" stroke=\"black\"/>\n",
       "</g>\n",
       "<!-- 139772220216544 -->\n",
       "<g class=\"node\" id=\"node8\"><title>139772220216544</title>\n",
       "<polygon fill=\"none\" points=\"71.5,-0.5 71.5,-36.5 139.5,-36.5 139.5,-0.5 71.5,-0.5\" stroke=\"black\"/>\n",
       "<text font-family=\"Times,serif\" font-size=\"14.00\" text-anchor=\"middle\" x=\"105.5\" y=\"-14.8\">fc: Dense</text>\n",
       "</g>\n",
       "<!-- 139772220215704&#45;&gt;139772220216544 -->\n",
       "<g class=\"edge\" id=\"edge7\"><title>139772220215704-&gt;139772220216544</title>\n",
       "<path d=\"M105.5,-73.3129C105.5,-65.2895 105.5,-55.5475 105.5,-46.5691\" fill=\"none\" stroke=\"black\"/>\n",
       "<polygon fill=\"black\" points=\"109,-46.5288 105.5,-36.5288 102,-46.5289 109,-46.5288\" stroke=\"black\"/>\n",
       "</g>\n",
       "</g>\n",
       "</svg>"
      ],
      "text/plain": [
       "<IPython.core.display.SVG object>"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "plot_model(happyModel, to_file='HappyModel.png')\n",
    "SVG(model_to_dot(happyModel).create(prog='dot', format='svg'))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}