{
  "cells": [
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "3e2930a8-1461-ee70-674f-206276c1a668"
      },
      "outputs": [],
      "source": [
        "import os, cv2, random\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "from matplotlib import ticker\n",
        "import seaborn as sns\n",
        "%matplotlib inline \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",
        "TRAIN_DIR = '../input/train/'\n",
        "TEST_DIR = '../input/test/'\n",
        "\n",
        "ROWS = 32\n",
        "COLS = 32\n",
        "CHANNELS = 3\n",
        "\n",
        "train_images = [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR)] # use this for full dataset\n",
        "train_dogs =   [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR) if 'dog' in i]\n",
        "train_cats =   [TRAIN_DIR+i for i in os.listdir(TRAIN_DIR) if 'cat' in i]\n",
        "\n",
        "test_images =  [TEST_DIR+i for i in os.listdir(TEST_DIR)]\n",
        "\n",
        "\n",
        "# slice datasets for memory efficiency on Kaggle Kernels, delete if using full dataset\n",
        "train_images = train_dogs[:1000] + train_cats[:1000]\n",
        "random.shuffle(train_images)\n",
        "test_images =  test_images[:25]\n",
        "\n",
        "def read_image(file_path):\n",
        "    img = cv2.imread(file_path, cv2.IMREAD_COLOR) #cv2.IMREAD_GRAYSCALE\n",
        "    return cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n",
        "\n",
        "\n",
        "def 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",
        "        if i%250 == 0: print('Processed {} of {}'.format(i, count))\n",
        "    \n",
        "    return data\n",
        "\n",
        "train = prep_data(train_images)\n",
        "test = prep_data(test_images)\n",
        "\n",
        "print(\"Train shape: {}\".format(train.shape))\n",
        "print(\"Test shape: {}\".format(test.shape))\n",
        "\n",
        "labels = []\n",
        "for i in train_images:\n",
        "    if 'dog' in i:\n",
        "        labels.append(1)\n",
        "    else:\n",
        "        labels.append(0)\n",
        "\n",
        "sns.countplot(labels)\n",
        "sns.plt.title('Cats and Dogs')\n",
        "\n",
        "def 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,5))\n",
        "    plt.imshow(pair)\n",
        "    plt.show()\n",
        "    \n",
        "for idx in range(0,5):\n",
        "    show_cats_and_dogs(idx)\n",
        "    \n",
        "optimizer = RMSprop(lr=1e-4)\n",
        "objective = 'binary_crossentropy'\n",
        "\n",
        "\n",
        "def catdog():\n",
        "    \n",
        "    model = Sequential()\n",
        "\n",
        "    model.add(Convolution2D(32, 3, 3, border_mode='same', input_shape=(3, ROWS, COLS), activation='relu'))\n",
        "    model.add(Convolution2D(32, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(MaxPooling2D(pool_size=(1, 1)))\n",
        "\n",
        "    model.add(Convolution2D(64, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(Convolution2D(64, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(MaxPooling2D(pool_size=(1, 1)))\n",
        "    \n",
        "    model.add(Convolution2D(128, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(Convolution2D(128, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(MaxPooling2D(pool_size=(1, 1)))\n",
        "    \n",
        "    model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "#     model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "    model.add(MaxPooling2D(pool_size=(1, 1)))\n",
        "\n",
        "#     model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "#     model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "#     model.add(Convolution2D(256, 3, 3, border_mode='same', activation='relu'))\n",
        "#     model.add(MaxPooling2D(pool_size=(2, 2)))\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",
        "\n",
        "    model.add(Dense(1))\n",
        "    model.add(Activation('sigmoid'))\n",
        "\n",
        "    model.compile(loss=objective, optimizer=optimizer, metrics=['accuracy'])\n",
        "    return model\n",
        "\n",
        "\n",
        "model = catdog()\n",
        "\n",
        "nb_epoch = 10\n",
        "batch_size = 16\n",
        "\n",
        "## Callback for loss logging per epoch\n",
        "class 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",
        "        self.val_losses.append(logs.get('val_loss'))\n",
        "\n",
        "early_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto')        \n",
        "        \n",
        "def run_catdog():\n",
        "    \n",
        "    history = LossHistory()\n",
        "    model.fit(train, labels, batch_size=batch_size, nb_epoch=nb_epoch,\n",
        "              validation_split=0.25, verbose=0, shuffle=True, callbacks=[history, early_stopping])\n",
        "    \n",
        "\n",
        "    predictions = model.predict(test, verbose=0)\n",
        "    return predictions, history\n",
        "\n",
        "predictions, history = run_catdog()\n",
        "\n",
        "loss = history.losses\n",
        "val_loss = history.val_losses\n",
        "\n",
        "plt.xlabel('Epochs')\n",
        "plt.ylabel('Loss')\n",
        "plt.title('VGG-16 Loss Trend')\n",
        "plt.plot(loss, 'blue', label='Training Loss')\n",
        "plt.plot(val_loss, 'green', label='Validation Loss')\n",
        "plt.xticks(range(0,nb_epoch)[0::2])\n",
        "plt.legend()\n",
        "plt.show()\n",
        "\n",
        "for i in range(0,10):\n",
        "    if predictions[i, 0] >= 0.5: \n",
        "        print('I am {:.2%} sure this is a Dog'.format(predictions[i][0]))\n",
        "    else: \n",
        "        print('I am {:.2%} sure this is a Cat'.format(1-predictions[i][0]))\n",
        "        \n",
        "    plt.imshow(test[i].T)\n",
        "    plt.show()"
      ]
    }
  ],
  "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
}