{
  "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.5.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0,
  "cells": [
    {
      "metadata": {
        "_cell_guid": "ff5a5866-6cef-5a63-616c-72e05e10764c",
        "_active": false,
        "collapsed": false
      },
      "source": "## Understanding First CV Script",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "d17a33d6-98ff-f85d-3950-cf7114da6e71",
        "_active": false,
        "collapsed": false
      },
      "source": "# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nfrom subprocess import check_output\nprint(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n\n# Any results you write to the current directory are saved as output.",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "92697216-4302-31a8-6307-b415e8943bc6",
        "_active": false,
        "collapsed": false
      },
      "source": "# Necessary imports\nimport os, cv2, random\nimport numpy as np\nimport pandas as pd\n\nimport matplotlib.pyplot as plt\nfrom matplotlib import ticker\nimport seaborn as sns\n%matplotlib inline\n\n# Each of these imports will be explained when we build the model\nfrom keras.models import Sequential\nfrom keras.layers import Input, Dropout, Flatten, Convolution2D, MaxPooling2D, Dense, Activation\nfrom keras.optimizers import RMSprop\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\nfrom keras.utils import np_utils",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "4404a393-3884-04e9-8b74-33502c86805f",
        "_active": false,
        "collapsed": false
      },
      "source": "## Preparing the Data",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "3093348e-1659-6d68-a258-8382569206ac",
        "_active": false,
        "collapsed": false
      },
      "source": "This function resizes the images to 64x64 and samples 2000 images (8%) of the data to run efficiently as a Kaggle Kernel.  ",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "bebaefa6-d48e-0606-8a58-02c897e8aae9",
        "_active": false,
        "collapsed": false
      },
      "source": "TRAIN_DIR = '../input/train/'\nTEST_DIR = '../input/test/'\n\nROWS = 64\nCOLS = 64\n\n# What are channels?  This is because we are reading the values in as RGB so 3 values/ pixel\nCHANNELS = 3\n\n# We have to do this because each image is in its own file\ntrain_images = [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR)]\ntrain_dogs = [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR) if 'dog' in i]\ntrain_cats = [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR) if 'cat' in i]\n\ntest_images = [TEST_DIR+i for i in os.listdir(TEST_DIR)]\n\n# Only get 1000 of each\ntrain_images = train_dogs[:1000] + train_cats[:1000]\nrandom.shuffle(train_images)\ntest_images = test_images[:25]\n\ndef read_image(file_path):\n    img = cv2.imread(file_path, cv2.IMREAD_COLOR)\n    \n    # What is interpolation? This specifies that when we resize we zoom out\n    return cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n\n# We store all of the data in an array of length count\ndef prep_data(images):\n    count = len(images)\n    data = np.ndarray((count, CHANNELS, ROWS, COLS), dtype=np.uint8)\n    \n    for i, image_file in enumerate(images):\n        image = read_image(image_file)\n        data[i] = image.T\n        \n    return data\n\ntrain = prep_data(train_images)\n\ntest = prep_data(test_images)\nprint(train.shape)",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "1f23caaa-d388-527d-e424-447019239c4b",
        "_active": false,
        "collapsed": false
      },
      "source": "## Checking out Images",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "78d33b42-8ecf-f500-0dfc-e2ea195680c9",
        "_active": false,
        "collapsed": false
      },
      "source": "# We call the read_image function we defined in order to open the file name and display\n# the pixel values of the images\n\ndef show_cats_and_dogs(idx):\n    cat = read_image(train_cats[idx])\n    dog = read_image(train_dogs[idx])\n    pair = np.concatenate((cat, dog), axis=1)\n    plt.figure(figsize=(10,15))\n    plt.imshow(pair)\n    plt.show()\n    \nfor idx in range(0,5):\n    show_cats_and_dogs(idx)",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "56997649-5df9-95d3-c888-87f046f5931c",
        "_active": false,
        "collapsed": false
      },
      "source": "# How do we generate an average cat and dog picture?\n\navg_cat = []",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "1cc9bcc2-5d4d-56e2-a07f-4e646ccc92dd",
        "_active": false,
        "collapsed": false
      },
      "source": "# We will iterate through train and check if it is a dog and sum over that way\n# Train has already been processed through read_image which reads in using\n# cv.imread()\n\n# We want to be able to iterate through and figure out which is a cat and which is \n# a dog so let's create an array of labels\n\nlabels = []\nfor img in train_images:\n    if 'dog' in img:\n        labels.append(1)\n    else:\n        labels.append(0)\n\n# We store 3 channels and thus need to get dog[0], this is the first channel\n\ndog_avg = np.array([dog[0].T for index, dog in enumerate(train) \n                    if labels[index] == 1]).mean(axis=0)\nprint(dog_avg.shape)\n# Now I want to display my avg_dog\nplt.imshow(dog_avg)\nplt.show()\n",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "cf3fc40a-cfb3-7ca6-fe8f-a70a0919b8f0",
        "_active": false,
        "collapsed": false
      },
      "source": "# Now let me create an average cat\ncat_avg = np.array([cat[0].T for i, cat in enumerate(train) \n                    if labels[i] == 0]).mean(axis=0)\nplt.imshow(cat_avg)\nplt.show()",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "2e83fc16-b5d9-8c30-ca74-8c777f2acda4",
        "_active": false,
        "collapsed": false
      },
      "source": "## CatdogNet-16",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "044cfb7a-71c7-cdfe-c3ee-13398223174a",
        "_active": false,
        "collapsed": false
      },
      "source": "**Some notes about Keras models:**\n\n - Keras is a neural network framework with pre-built layers\n - Layers include: Regular dense, Recurrent layers, Noise layers (Gaussian)\n - Each layer has its own activation function\n - Steps to build a neural network\n      - add() - adds layers from left to right to your model\n      - compile() - provides info regarding the loss and activation functions\n      - fit(train, batch, epochs, accuracy) - creates the neural network\n      - predict() - generate predictions\n\n**Other important terms**\n\n - What is a sequential model?  \nA linear stack of layers\n - What is a callback?  \nSaves the weights your model has currently\n\n - What is an epoch?  \nA full pass over all your training data\n\n - What is EarlyStopping? \nStops training model when a specified value has stopped improving\n\n - Optimizer - RMSprop(1r=1e-4)\nRMSprop is an optimization of back- propagation to learn the weights of a neural network\n\n - Objective - 'binary_crossentropy'\nThis is the loss function of our problem: mean-squared error, mean-absolute error\nBinary_crossentropy is the same as log_loss\nLog_loss is used when you have binary outputs 0, 1 but your predictions from the network are probabilities (0,1).  Thus you don't want to just say > 0.5 = 1 and <0.5 = 0.  Instead you weight the probabilities accordingly.  \n\nlogLoss=logLoss=−1N−1N∑Ni=1∑i=1N(yi(logpi)+(1−yi)log(1−pi))\n\n Through this formula we essentially smoothen the hinge classification method",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "76d5ecef-941d-8e6a-4e5c-5fc410222022",
        "_active": false,
        "collapsed": false
      },
      "source": "optimizer = RMSprop (lr=1e-4)\nobjective = 'binary_crossentropy'\n\ndef catdog():\n    # How did you come up with this layer technique?\n    model = Sequential()\n    \n    model.add(Convolution2D(32, 3, 3, border_mode='same', \n                            input_shape=(3, ROWS, COLS), activation='relu'))\n    model.add(Convolution2D(32, 3, 3, border_mode='same', \n                           activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2,2), dim_ordering=\"th\"))\n    \n    model.add(Convolution2D(64, 3, 3, border_mode='same', \n                            input_shape=(3, ROWS, COLS), activation='relu'))\n    model.add(Convolution2D(64, 3, 3, border_mode='same', \n                           activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2,2), dim_ordering=\"th\"))\n    \n    model.add(Convolution2D(128, 3, 3, border_mode='same', \n                            input_shape=(3, ROWS, COLS), activation='relu'))\n    model.add(Convolution2D(128, 3, 3, border_mode='same', \n                           activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2,2), dim_ordering=\"th\"))\n    \n    model.add(Convolution2D(256, 3, 3, border_mode='same', \n                            input_shape=(3, ROWS, COLS), activation='relu'))\n    model.add(Convolution2D(256, 3, 3, border_mode='same', \n                           activation='relu'))\n    model.add(MaxPooling2D(pool_size=(2,2), dim_ordering=\"th\"))\n    \n    model.add(Flatten())\n    model.add(Dense(256, activation='relu'))\n    model.add(Dropout(0.5))\n    \n    model.add(Dense(256, activation='relu'))\n    model.add(Dropout(0.5))\n    model.add(Dense(1))\n    model.add(Activation('sigmoid'))\n    \n    model.compile(loss=objective, optimizer=optimizer, metrics=['accuracy'])\n    return model\n\nmodel = catdog()",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "2043cf2b-f9c6-eb1e-aa6e-8810c7081605",
        "_active": false,
        "collapsed": false
      },
      "source": " What's convolution doing?\n\n - First we have our image represented as a 64x64x3 - dimensions of image with 3 RGB per pixel.  Convolution means that we pass a filter over the image.  We can pass a Guassian blur which will average the pixels with those around it.  \nAs a mathematical function, convolution follows the same properties as a linear time invariant system - additive, time invariant and the superposition principle.  It places a mask over a region of pixels and maps this region to a single point as the output.\n\n What are the parameters for Convolution2D?\n - Convolution2D(number of filters- dimension of output, filter_rows, filter_columns, input_shape, activation)\n\nWhat's MaxPooling2D?\n - The pooling layer will downsample the data to make it smaller and more manageable.  It is run over each activation map separately.",
      "execution_count": null,
      "cell_type": "markdown",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "bc56e5fe-59e6-037e-c45d-7a6c4a6e1839",
        "_active": false,
        "collapsed": false
      },
      "source": "nb_epoch = 10\nbatch_size = 16\n\nclass LossHistory(Callback):\n    def on_train_begin(self, logs={}):\n        self.losses = []\n        self.val_losses = []\n        \n    def on_epoch_end(self, batch, logs={}):\n        self.losses.append(logs.get('loss'))\n\n# This states that the model will stop training when val_loss stops improving\n# for 3 levels. We pass this into the model.fit() call.\nearly_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto')\n\ndef run_catdog():\n    history = LossHistory()\n    model.fit(train, labels, batch_size=batch_size, nb_epoch=nb_epoch,\n             validation_split=0.25, verbose=0, \n              shuffle=True, callbacks=[history, early_stopping])\n    predictions = model.predict(test, verbose=0)\n    return predictions, history\n\npredictions, history = run_catdog()",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "2842358d-a434-810c-7d8e-cf9f153147dc",
        "_active": false,
        "collapsed": false
      },
      "source": "##Visualize our Model's Improvement##",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    },
    {
      "metadata": {
        "_cell_guid": "6268ff8e-989c-c47a-1a61-9a8663027399",
        "_active": false,
        "collapsed": false
      },
      "source": "# How can we visualize how the error decreases over iterations?\n# These are the values we gathered in LossHistory\nloss = history.losses\nval_loss = history.val_losses\n\n\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.plot(loss, 'blue', label='Training loss')\nplt.plot(val_loss, 'green', label='Validation loss')\nplt.show()",
      "execution_count": null,
      "cell_type": "code",
      "outputs": [],
      "execution_state": "idle"
    }
  ]
}