{"metadata": {"kernelspec": {"language": "python", "name": "python3", "display_name": "Python 3"}, "language_info": {"nbconvert_exporter": "python", "file_extension": ".py", "pygments_lexer": "ipython3", "mimetype": "text/x-python", "version": "3.6.1", "codemirror_mode": {"version": 3, "name": "ipython"}, "name": "python"}}, "nbformat": 4, "cells": [{"cell_type": "markdown", "metadata": {"_uuid": "835129eff817b32d827fc8b19b3c6f127a14029b", "_cell_guid": "c2b0398a-0b66-4717-ba3e-40b66dad7811"}, "source": ["**Setup imports**"]}, {"cell_type": "code", "metadata": {"_uuid": "7611e54c0c42b2ce72f903ee6710a838c21274be", "_cell_guid": "734eceed-936e-40b6-98e0-af8ea4f17bbe"}, "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, Conv2D, MaxPooling2D, Dense, Activation\n", "from keras.optimizers import RMSprop\n", "from keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\n", "from keras.utils import np_utils"], "execution_count": 4}, {"cell_type": "markdown", "metadata": {"_uuid": "a4da051fd88f9e97062a6f01d1e6d4a27f7ca35d", "_cell_guid": "8ca96c62-bf30-48af-a5e4-66b87de38a20"}, "source": ["Read datasets.We will use a subset of the data to reduce the running time. There is train set and a test set.\n"]}, {"cell_type": "code", "metadata": {"_uuid": "0d38a6d58dd9d5d18f2b8d73a9b95ec3251d8534", "_cell_guid": "7748c04d-310d-498d-8c36-e8af0472c109"}, "outputs": [], "source": ["TRAIN_DIR = '../input/train/'\n", "TEST_DIR = '../input/test/'\n", "\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", "# select a subset of the data. 1000 images of cats and dogs each\n", "train_images = train_dogs[:1000] + train_cats[:1000]\n", "# mix it up\n", "random.shuffle(train_images)\n", "test_images = test_images[:25]\n", "\n", "print(\"Done\")"], "execution_count": 5}, {"cell_type": "markdown", "metadata": {"_uuid": "e5d882a27bcd491ec4edca840b3d2ba43dca5876", "_cell_guid": "7235d360-ccd9-4c56-81b1-db8022ebe9b2"}, "source": ["Reduce the pictures to 64x64"]}, {"cell_type": "code", "metadata": {"_uuid": "95c7abe9b29cb209d1fbd4807bc375f9cd7cd144", "_cell_guid": "90559bb7-065f-434d-ab0c-ee0a6b053b9e"}, "outputs": [], "source": ["ROWS = 64\n", "COLS = 64\n", "CHANNELS = 3\n", "\n", "def read_image(file_path):\n", "    img = cv2.imread(file_path, cv2.IMREAD_UNCHANGED)\n", "    return cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\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))"], "execution_count": 6}, {"cell_type": "markdown", "metadata": {"collapsed": true, "_uuid": "bfb1a80513ca1dc3c7656252a067cb6ec1c5b8f2", "_cell_guid": "6d011370-95b3-46df-b1cf-611ae1e14472"}, "source": ["Display a few examples"]}, {"cell_type": "code", "metadata": {"_uuid": "5cc9224d7bf60b6639a86404500b5e88760ae35c", "_cell_guid": "3b6d7367-b57c-4cbb-8e17-55724497f990"}, "outputs": [], "source": ["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 img in range(0,3):\n", "    show_cats_and_dogs(img)"], "execution_count": 7}, {"cell_type": "markdown", "metadata": {"_uuid": "8338c9e49399d88b378b079cdb4adea0d1b9e01a", "_cell_guid": "d73f413f-507f-4d04-8369-abb4bfeed00f"}, "source": ["Initialise an array with labels from the training data denoting if it is a dog or cat"]}, {"cell_type": "code", "metadata": {"_uuid": "7c74a706ea517c581467f6ba01cb4955b4c7646f", "_cell_guid": "65abdd91-84b7-4212-9693-b42ca52d2cf4"}, "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')"], "execution_count": 8}, {"cell_type": "markdown", "metadata": {"_uuid": "2c0675d75a72e587ca6762d308feb82e4717049e", "_cell_guid": "73f19687-1603-42f5-a1f3-804790ef2f11"}, "source": ["Initialise the model. A scaled down version of VGG-16 see https://arxiv.org/pdf/1409.1556.pdf"]}, {"cell_type": "code", "metadata": {"_uuid": "67984a8d7e855cbc4da70fb009b06eaa2970fbd7", "_cell_guid": "7c795eef-ea03-4ec2-83c0-60f88c17c0af"}, "outputs": [], "source": ["optimizer = RMSprop(lr=1e-4)\n", "objective = 'binary_crossentropy'\n", "\n", "from keras import backend as K\n", "K.set_image_dim_ordering('th')\n", "\n", "def catdog():\n", "    model = Sequential()\n", "    \n", "    model.add(Conv2D(32, (3, 3), input_shape=(3, ROWS, COLS), activation='relu', padding='same'))\n", "    model.add(Conv2D(32, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(MaxPooling2D(pool_size=(2, 2)))\n", "\n", "    model.add(Conv2D(64, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(Conv2D(64, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(MaxPooling2D(pool_size=(2, 2)))\n", "    \n", "    model.add(Conv2D(128, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(Conv2D(128, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(MaxPooling2D(pool_size=(2, 2)))\n", "    \n", "    model.add(Conv2D(256, (3, 3), activation=\"relu\", padding=\"same\"))\n", "    model.add(Conv2D(256, (3, 3), activation=\"relu\", padding=\"same\"))\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", "    model.compile(loss=objective, optimizer=optimizer, metrics=['accuracy'])\n", "    return model\n", "\n", "model = catdog()\n", "model.summary()"], "execution_count": 14}, {"cell_type": "markdown", "metadata": {"_uuid": "678da9dda09444d56fead73b1bbbb2af557752ba", "_cell_guid": "45d18a9a-71e6-4871-a6bc-0031806a0be7"}, "source": ["Train and predict.\n", "Uses two callbacks\n", "- LossHistory logs values for each epoch which are used to create a graph later\n", "- early_stopping stops the run if validation_loss stops improving"]}, {"cell_type": "code", "metadata": {"_uuid": "375da6020368ffdc96a57112683c015a42eb62f5", "_cell_guid": "58c01dfb-1325-4421-8429-3980f2826823"}, "outputs": [], "source": ["## 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", "        print(\"epoch done\")\n", "\n", "def run_catdog():\n", "    history = LossHistory()\n", "    early_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto') \n", "    \n", "    model.fit(train, labels, batch_size=16, epochs=10,\n", "              validation_split=0.25, verbose=2, shuffle=True, callbacks=[history, early_stopping])\n", "    \n", "    predictions = model.predict(test, verbose=0)\n", "    return predictions, history\n", "\n", "predictions, history = run_catdog()"], "execution_count": 15}, {"cell_type": "markdown", "metadata": {"_uuid": "ce7e96eef454d357bd45fe02a3b216bd0c9eedc4", "_cell_guid": "06bf9f24-e845-496e-b1a6-c746b7c1b099"}, "source": ["Plots the results of the run"]}, {"cell_type": "code", "metadata": {"_uuid": "d30239cf1080c69ee7b663ed76a45f79ff842973", "_cell_guid": "abaf986b-89a4-4855-bc83-e68f9657b1ff"}, "outputs": [], "source": ["loss = history.losses\n", "val_loss = history.val_losses\n", "epochs = 10\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,epochs)[0::2])\n", "plt.legend()\n", "plt.show()"], "execution_count": 17}, {"cell_type": "markdown", "metadata": {"_uuid": "cdd16b5ffe82fca558e3f546a3621f0bebe81ae4", "_cell_guid": "5b580eaa-cbfa-486c-bfae-09990079d59a"}, "source": ["Classify a few examples with the model"]}, {"cell_type": "code", "metadata": {"_uuid": "86a432e21b66496ca024a78ad2da11ec077509f2", "_cell_guid": "c76a19bb-084f-4889-b36f-2985d4908d29"}, "outputs": [], "source": ["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()"], "execution_count": 18}, {"cell_type": "markdown", "metadata": {"_uuid": "93862a4041379eae0048fe2e77c307e4ed2c38fc", "_cell_guid": "3a09c989-4d33-4c64-976c-7a5599bcecda"}, "source": ["Measure the accuracy on the test set"]}, {"cell_type": "code", "metadata": {"_uuid": "2d282faed08aecb004b92b6296dc7b87aa9f9bc6", "_cell_guid": "69326781-eebc-46e7-8ec5-842671d10add"}, "outputs": [], "source": ["batch_size = 16\n", "test_labels = []\n", "for i in test_images:\n", "    if 'dog' in i:\n", "        test_labels.append(1)\n", "    else:\n", "        test_labels.append(0)\n", "\n", "predictions = model.predict(test, batch_size, verbose=0)\n", "evaluations = model.evaluate(test, test_labels, batch_size, verbose=0, sample_weight=None)\n", "print(\"scalar loss: \", evaluations[0])\n", "print(\"accuracy: \", evaluations[1])\n", "model.save(\"test1\")"], "execution_count": 20}, {"cell_type": "markdown", "metadata": {"_uuid": "cfbafbedd688563020f139fd29b21de7e8bf92b8", "_cell_guid": "f0eb6b57-4272-4c10-bdbd-d9fb97345a6e"}, "source": ["Write the model and model weights to file"]}, {"cell_type": "code", "metadata": {"collapsed": true, "_uuid": "09213f79a6f8fd058d61857f351da32787e509a9", "_cell_guid": "742a7485-d4bf-4f8e-a93b-91ef542662b1"}, "outputs": [], "source": ["from keras.models import model_from_json\n", "from os import listdir\n", "import pickle\n", "model_json = model.to_json()\n", "model_weights = model.get_weights()\n", "\n", "pickle.dump(model_json, open('model.pkl', 'wb'))\n", "pickle.dump(model_weights, open('model_weights.pkl', 'wb'))\n", "os.listdir()"], "execution_count": null}], "nbformat_minor": 1}