{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "7a98e214-fcaa-373a-c677-bca8d582aec4"
      },
      "source": ""
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "b9c4cf08-e964-d988-0ff6-0c82b55f22cc"
      },
      "outputs": [],
      "source": ""
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "46e9a366-75fb-1cc8-ee28-45e88abbfad1"
      },
      "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",
        "import keras \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/train\"]).decode(\"utf8\"))\n",
        "\n",
        "# Any results you write to the current directory are saved as output."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "2f51f69f-6834-ed8e-a323-7d7258c81089"
      },
      "outputs": [],
      "source": [
        "import theano\n",
        "theano.config.device = 'gpu'\n",
        "theano.config.floatX = 'float32'"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "74589918-b954-5f2f-eeb6-cebab6eef28a"
      },
      "outputs": [],
      "source": [
        "fimport matplotlib.pyplot as plt\n",
        "import matplotlib.image as mpimg\n",
        "first = mpimg.imread('../input/train/c0/img_100026.jpg')\n",
        "plt.imshow(first)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "68f9b755-630e-6d89-d94f-35eeae72a3c7"
      },
      "outputs": [],
      "source": [
        "from __future__ import division, print_function\n",
        "\n",
        "import os, json\n",
        "from glob import glob\n",
        "import numpy as np\n",
        "from scipy import misc, ndimage\n",
        "from scipy.ndimage.interpolation import zoom\n",
        "\n",
        "from keras.utils.data_utils import get_file\n",
        "from keras import backend as K\n",
        "from keras.layers.normalization import BatchNormalization\n",
        "from keras.utils.data_utils import get_file\n",
        "from keras.models import Sequential\n",
        "from keras.layers.core import Flatten, Dense, Dropout, Lambda\n",
        "from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D\n",
        "from keras.layers.pooling import GlobalAveragePooling2D\n",
        "from keras.optimizers import SGD, RMSprop, Adam\n",
        "from keras.preprocessing import image\n",
        "\n",
        "\n",
        "vgg_mean = np.array([123.68, 116.779, 103.939], dtype=np.float32).reshape((3,1,1))\n",
        "def vgg_preprocess(x):\n",
        "    x = x - vgg_mean\n",
        "    return x[:, ::-1] # reverse axis rgb->bgr\n",
        "\n",
        "\n",
        "class Vgg16():\n",
        "    \"\"\"The VGG 16 Imagenet model\"\"\"\n",
        "\n",
        "\n",
        "    def __init__(self):\n",
        "        self.FILE_PATH = 'http://www.platform.ai/models/'\n",
        "        self.create()\n",
        "        self.get_classes()\n",
        "\n",
        "\n",
        "    def get_classes(self):\n",
        "        fname = 'imagenet_class_index.json'\n",
        "        fpath = get_file(fname, self.FILE_PATH+fname, cache_subdir='models')\n",
        "        with open(fpath) as f:\n",
        "            class_dict = json.load(f)\n",
        "        self.classes = [class_dict[str(i)][1] for i in range(len(class_dict))]\n",
        "    \n",
        "    def ConvBlock(self, layers, filters):\n",
        "        model = self.model\n",
        "        for i in range(layers):\n",
        "            model.add(ZeroPadding2D((1, 1)))\n",
        "            model.add(Convolution2D(filters, 3, 3, activation='relu'))\n",
        "        model.add(MaxPooling2D((2, 2), strides=(2, 2)))\n",
        "\n",
        "\n",
        "    def FCBlock(self):\n",
        "        model = self.model\n",
        "        model.add(Dense(4096, activation='relu'))\n",
        "        model.add(Dropout(0.5))\n",
        "\n",
        "\n",
        "    def create(self):\n",
        "        model = self.model = Sequential()\n",
        "        model.add(Lambda(vgg_preprocess, input_shape=(3,224,224)))\n",
        "\n",
        "        self.ConvBlock(2, 64)\n",
        "        self.ConvBlock(2, 128)\n",
        "        self.ConvBlock(3, 256)\n",
        "        self.ConvBlock(3, 512)\n",
        "        self.ConvBlock(3, 512)\n",
        "\n",
        "        model.add(Flatten())\n",
        "        self.FCBlock()\n",
        "        self.FCBlock()\n",
        "        model.add(Dense(1000, activation='softmax'))\n",
        "\n",
        "        fname = 'vgg16.h5'\n",
        "        model.load_weights(get_file(fname, self.FILE_PATH+fname, cache_subdir='models'))\n",
        "\n",
        "    def get_batches(self, path, gen=image.ImageDataGenerator(), shuffle=True, batch_size=8, class_mode='categorical'):\n",
        "        return gen.flow_from_directory(path, target_size=(224,224),\n",
        "                class_mode=class_mode, shuffle=shuffle, batch_size=batch_size)\n",
        "\n",
        "\n",
        "    def ft(self, num):\n",
        "        model = self.model\n",
        "        model.pop()\n",
        "        for layer in model.layers: layer.trainable=False\n",
        "        model.add(Dense(num, activation='softmax'))\n",
        "        self.compile()\n",
        "\n",
        "    def finetune(self, batches):\n",
        "        model = self.model\n",
        "        model.pop()\n",
        "        for layer in model.layers: layer.trainable=False\n",
        "        model.add(Dense(batches.nb_class, activation='softmax'))\n",
        "        self.compile()\n",
        "\n",
        "\n",
        "    def compile(self, lr=0.001):\n",
        "        self.model.compile(optimizer=Adam(lr=lr),\n",
        "                loss='categorical_crossentropy', metrics=['accuracy'])\n",
        "\n",
        "\n",
        "    def fit_data(self, trn, labels,  val, val_labels,  nb_epoch=1, batch_size=64):\n",
        "        self.model.fit(trn, labels, nb_epoch=nb_epoch,\n",
        "                validation_data=(val, val_labels), batch_size=batch_size)\n",
        "\n",
        "\n",
        "    def fit(self, batches, val_batches, nb_epoch=1):\n",
        "        self.model.fit_generator(batches, samples_per_epoch=batches.nb_sample, nb_epoch=nb_epoch,\n",
        "                validation_data=val_batches, nb_val_samples=val_batches.nb_sample)\n",
        "\n",
        "\n",
        "    def test(self, path, batch_size=8):\n",
        "        test_batches = self.get_batches(path, shuffle=False, batch_size=batch_size, class_mode=None)\n",
        "        return test_batches, self.model.predict_generator(test_batches, test_batches.nb_sample)\n",
        "\n",
        "    def predict(self, imgs, details=False):\n",
        "        all_preds = self.model.predict(imgs)\n",
        "        idxs = np.argmax(all_preds, axis=1)\n",
        "        preds = [all_preds[i, idxs[i]] for i in range(len(idxs))]\n",
        "        classes = [self.classes[idx] for idx in idxs]\n",
        "        return np.array(preds), idxs, classes"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "aef3a165-8052-b874-b809-c7669b115574"
      },
      "outputs": [],
      "source": [
        "vgg = Vgg16()\n",
        "# Grab a few images at a time for training and validation.\n",
        "# NB: They must be in subdirectories named based on their category\n",
        "batches = vgg.get_batches(path+'train', batch_size=batch_size)\n",
        "val_batches = vgg.get_batches(path+'valid', batch_size=batch_size*2)\n",
        "vgg.finetune(batches)\n",
        "vgg.fit(batches, val_batches, nb_epoch=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "e7521431-987a-4d1e-eff0-a2ff4fc946d5"
      },
      "outputs": [],
      "source": [
        "vgg = Vgg16()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "2e2d9763-60ff-ef3f-cbcb-648f527036c6"
      },
      "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
}