{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "fe395a74-1bc5-609b-f6b6-63240b20c871"
      },
      "source": [
        "Kernel that learns to distinguish between cats and dogs and makes predictions on a set of images, outputting those predictions to a CSV file that can submitted in the competition:"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "7ed1191c-9c08-0eeb-c26b-3426ead4fec6"
      },
      "outputs": [],
      "source": [
        "# Joseph Wessel\n",
        "# Last Modified: March 3, 2017\n",
        "# Data Science\n",
        "\n",
        "# NOTE: This code is heavily based on, and consists almost exclusively of, modified code provided\n",
        "#       in George Mohler's kernel found here:\n",
        "#       https://www.kaggle.com/george04/dogs-vs-cats-redux-kernels-edition/cnn-cat-dog/code\n",
        "\n",
        "import numpy as numpy\n",
        "import pandas as pandas\n",
        "\n",
        "from subprocess import check_output\n",
        "\n",
        "import os,cv2,random\n",
        "\n",
        "from keras.models import Sequential\n",
        "from keras.layers import Input,Dropout,Flatten,Convolution2D,MaxPooling2D,Dense,Activation\n",
        "from keras.optimizers import RMSprop\n",
        "from keras.callbacks import ModelCheckpoint,Callback,EarlyStopping\n",
        "from keras.utils import np_utils\n",
        "\n",
        "# Add references to test and training file directories:\n",
        "\n",
        "trainDir = '../input/train/'\n",
        "testDir = '../input/test/'\n",
        "\n",
        "# Specify 32 rows and columns, and only one channel, which simplifies the \n",
        "# processing (vs. 64 rows and columns, and 3 channels):\n",
        "\n",
        "rows = 32\n",
        "cols = 32\n",
        "channels = 1\n",
        "\n",
        "# Create arrays of training and testing images:\n",
        "\n",
        "trainImages = [trainDir+i for i in os.listdir(trainDir)]\n",
        "testImages = [testDir+i for i in os.listdir(testDir)]\n",
        "\n",
        "# Define functions for reading in the image and preparing the image for processing:\n",
        "\n",
        "def readImage(filePath):\n",
        "    img = cv2.imread(filePath,cv2.IMREAD_GRAYSCALE)\n",
        "    return cv2.resize(img,(rows,cols),interpolation=cv2.INTER_CUBIC)\n",
        "\n",
        "def prepData(images):\n",
        "    count = len(images)\n",
        "    data = numpy.ndarray((count,channels,rows,cols),dtype=numpy.uint8)\n",
        "    \n",
        "    for i,imageFile in enumerate(images):\n",
        "        image = readImage(imageFile)\n",
        "        data[i] = image.T\n",
        "        if i%250 == 0: print('Processed {} of {}'.format(i,count))\n",
        "    \n",
        "    return data\n",
        "\n",
        "# Implement training and data sets, and append labels for submission:\n",
        "\n",
        "train = prepData(trainImages)\n",
        "test = prepData(testImages)\n",
        "\n",
        "print(\"Train shape: {}\".format(train.shape))\n",
        "print(\"Test shape: {}\".format(test.shape))\n",
        "\n",
        "labels = []\n",
        "for i in trainImages:\n",
        "\tif 'dog' in i:\n",
        "\t\tlabels.append(1)\n",
        "\telse:\n",
        "\t\tlabels.append(0)\n",
        "\n",
        "# Train on image shape:        \n",
        "        \n",
        "train = train.reshape(-1,32,32,1)\n",
        "test = test.reshape(-1,32,32,1)\n",
        "xTrain = train.astype('float32')\n",
        "xTest = test.astype('float32')\n",
        "xTrain /= 255\n",
        "xTest /= 255\n",
        "yTrain = labels\n",
        "\n",
        "xValid = xTrain[:5000,:,:,:]\n",
        "yValid = yTrain[:5000]\n",
        "xTrain = xTrain[5001:25000,:,:,:]\n",
        "yTrain = yTrain[5001:25000]\n",
        "\n",
        "print(\"Training matrix shape\",xTrain.shape)\n",
        "print(\"Training matrix shape\",xTest.shape)\n",
        "\n",
        "# Fit to model:\n",
        "\n",
        "model = Sequential()\n",
        "model.add(Convolution2D(16,3,3,border_mode='same',input_shape=(rows,cols,channels),activation='relu'))\n",
        "model.add(MaxPooling2D(pool_size=(2, 2)))\n",
        "model.add(Convolution2D(32,3,3,border_mode='same',activation='relu'))\n",
        "model.add(MaxPooling2D(pool_size=(2,2)))\n",
        "model.add(Flatten())\n",
        "model.add(Dense(100,activation='relu'))\n",
        "model.add(Dropout(0.5))\n",
        "model.add(Dense(100,activation='relu'))\n",
        "model.add(Dropout(0.5))\n",
        "model.add(Dense(1))\n",
        "model.add(Activation('sigmoid'))\n",
        "\n",
        "model.compile(loss='binary_crossentropy',optimizer='adam',metrics=['accuracy'])\n",
        "\n",
        "model.fit(xTrain,yTrain,\n",
        "\t\t  batch_size = 128, nb_epoch = 8,\n",
        "\t\t  show_accuracy = True, verbose = 1,\n",
        "\t\t  validation_data = (xValid,yValid))\n",
        "\n",
        "# Prepare submission CSV file:\n",
        "\n",
        "submission = model.predict_proba(xTest, verbose = 1)\n",
        "testID = range(1,12501)\n",
        "predictionsDF = pandas.DataFrame({'id': testID, 'label': submission[:,0]})\n",
        "\n",
        "predictionsDF.to_csv(\"JoeWessel_Submissions.csv\", index = False)"
      ]
    }
  ],
  "metadata": {
    "_change_revision": 0,
    "_is_fork": false,
    "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": 0
}