{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "35dd21b2-17ff-4511-19ca-4ca4f6fea3aa"
      },
      "source": [
        "Jeff Delaney kernel for Cats vs. Dogs redux using skimage instead of cv2"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "3a1f8b9e-f0a1-9b13-8184-4359c3d64b10"
      },
      "outputs": [],
      "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",
        "\n",
        "import numpy as np # linear algebra\n",
        "import 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",
        "\n",
        "from subprocess import check_output\n",
        "print(check_output([\"ls\", \"../input\"]).decode(\"utf8\"))\n",
        "\n",
        "# Any results you write to the current directory are saved as output.\n",
        "\n",
        "#select Theano as backend\n",
        "%env KERAS_BACKEND=theano"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "bda931cc-9290-d98d-e9ce-889b2dfb9a3b"
      },
      "outputs": [],
      "source": [
        "import os, random\n",
        "\n",
        "from skimage.io import imread\n",
        "from skimage.transform import resize\n",
        "import matplotlib.pyplot as plt\n",
        "from matplotlib import ticker\n",
        "import seaborn as sns\n",
        "%matplotlib inline \n",
        "\n",
        "import keras\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.optimizers import SGD\n",
        "from keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\n",
        "from keras.utils import np_utils\n",
        "from keras import backend as K"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "2d2d3e13-ad2f-db60-97eb-c369d05b9571"
      },
      "outputs": [],
      "source": [
        "random.seed(2718)\n",
        "K.set_image_dim_ordering('th') \n",
        "print(\"keras version: \", keras.__version__)\n",
        "print(\"keras image dimension ordering: \", keras.backend.image_dim_ordering())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a811f307-478f-d4ee-51c6-13c7d01dd7c2"
      },
      "outputs": [],
      "source": [
        "TRAIN_DIR = '../input/train/'\n",
        "TEST_DIR =  '../input/test/'\n",
        "\n",
        "ROWS = 64\n",
        "COLS = 64\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[:100] + train_cats[:100]\n",
        "random.shuffle(train_images)\n",
        "test_images =  test_images[:25]\n",
        "\n",
        "def read_image(file_path):\n",
        "    im = imread(file_path)\n",
        "    im = resize(im, (ROWS, COLS))\n",
        "    return im\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))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "ae957108-ee27-54ac-1c67-04cf30625cd1"
      },
      "outputs": [],
      "source": [
        "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')"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "219bfa7e-0b46-2b51-2382-0619352f84e2"
      },
      "outputs": [],
      "source": [
        "optimizer = RMSprop(lr=1e-4)\n",
        "\n",
        "#epochs = 25\n",
        "#lrate = 4.e-4\n",
        "#decay = lrate/epochs\n",
        "#optimizer = SGD(lr=lrate, momentum=0.9, decay=decay, nesterov=False)\n",
        "\n",
        "\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=(2, 2)))\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=(2, 2)))\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=(2, 2)))\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(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()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "5e8fcac4-afd7-9a81-f79f-c71b7dd3fb4e"
      },
      "outputs": [],
      "source": [
        "nb_epoch = 10\n",
        "batch_size = 100\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])\n",
        "    \n",
        "\n",
        "    predictions = model.predict(test, verbose=0)\n",
        "    return  predictions, history\n",
        "\n",
        "predictions, history = run_catdog()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "5d2eb580-b4ca-23a3-8881-81e460ed6a20"
      },
      "outputs": [],
      "source": [
        "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()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "c359698b-39bc-2ce8-4f17-63beaa445981"
      },
      "source": [
        "This looks like a strong proof that the problems I had running Jeff Delaney kernel on my laptop are due to the fact that I use skimage imread and resize. If I use the same code but read the input images with cv2 I get a proper behavior for the validation loss."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "d057f87a-de4c-d3af-db70-d2d8d6241685"
      },
      "outputs": [],
      "source": [
        ""
      ]
    }
  ],
  "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.5.2"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}