{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "d02af827-edda-3054-375f-c3fbfbbe53f6"
      },
      "source": [
        "# Development notebook\n",
        "\n",
        "- data generator for Keras\n",
        "- random submission"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "ebc9ee4d-ccdb-f049-1ac8-8bc4488ced1a"
      },
      "outputs": [],
      "source": [
        "import os \n",
        "from glob import glob\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 cv2\n",
        "\n",
        "import matplotlib.pyplot as plt\n",
        "\n",
        "from keras.backend import set_image_dim_ordering, image_dim_ordering\n",
        "\n",
        "set_image_dim_ordering('th')\n",
        "print(\"Image dim ordering : \", image_dim_ordering())"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a1461181-304b-4fe8-112c-197dab930a6e"
      },
      "outputs": [],
      "source": [
        "TRAIN_DATA = \"../input/train\"\n",
        "TEST_DATA = \"../input/test\"\n",
        "ADDITIONAL_DATA = \"../input/additional\"\n",
        "\n",
        "\n",
        "type_1_files = glob(os.path.join(TRAIN_DATA, \"Type_1\", \"*.jpg\"))\n",
        "type_1_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_1\"))+1:-4] for s in type_1_files])\n",
        "type_2_files = glob(os.path.join(TRAIN_DATA, \"Type_2\", \"*.jpg\"))\n",
        "type_2_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_2\"))+1:-4] for s in type_2_files])\n",
        "type_3_files = glob(os.path.join(TRAIN_DATA, \"Type_3\", \"*.jpg\"))\n",
        "type_3_ids = np.array([s[len(os.path.join(TRAIN_DATA, \"Type_3\"))+1:-4] for s in type_3_files])\n",
        "\n",
        "additional_type_1_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_1\", \"*.jpg\"))\n",
        "additional_type_1_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_1\"))+1:-4] for s in additional_type_1_files])\n",
        "additional_type_2_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_2\", \"*.jpg\"))\n",
        "additional_type_2_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_2\"))+1:-4] for s in additional_type_2_files])\n",
        "additional_type_3_files = glob(os.path.join(ADDITIONAL_DATA, \"Type_3\", \"*.jpg\"))\n",
        "additional_type_3_ids = np.array([s[len(os.path.join(ADDITIONAL_DATA, \"Type_3\"))+1:-4] for s in additional_type_3_files])\n",
        "\n",
        "test_files = glob(os.path.join(TEST_DATA, \"*.jpg\"))\n",
        "test_ids = np.array([s[len(TEST_DATA)+1:-4] for s in test_files])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a0f5eddf-8cb8-6a0d-667a-efd618e030d3"
      },
      "outputs": [],
      "source": [
        "def get_filename(image_id, image_type):\n",
        "    \"\"\"\n",
        "    Method to get image file path from its id and type   \n",
        "    \"\"\"\n",
        "    if image_type == \"Type_1\" or \\\n",
        "        image_type == \"Type_2\" or \\\n",
        "        image_type == \"Type_3\":\n",
        "        data_path = os.path.join(TRAIN_DATA, image_type)\n",
        "    elif image_type == \"Test\":\n",
        "        data_path = TEST_DATA\n",
        "    elif image_type == \"AType_1\" or \\\n",
        "          image_type == \"AType_2\" or \\\n",
        "          image_type == \"AType_3\":\n",
        "        data_path = os.path.join(ADDITIONAL_DATA, image_type)\n",
        "    else:\n",
        "        raise Exception(\"Image type '%s' is not recognized\" % image_type)\n",
        "\n",
        "    ext = 'jpg'\n",
        "    return os.path.join(data_path, \"{}.{}\".format(image_id, ext))\n",
        "\n",
        "\n",
        "def get_image_data(image_id, image_type):\n",
        "    \"\"\"\n",
        "    Method to get image data as np.array specifying image id and type\n",
        "    \"\"\"\n",
        "    fname = get_filename(image_id, image_type)\n",
        "    img = cv2.imread(fname)\n",
        "    assert img is not None, \"Failed to read image : %s, %s\" % (image_id, image_type)\n",
        "    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n",
        "    return img"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "6cf918d9-10a4-0076-d52c-55f78660b202"
      },
      "outputs": [],
      "source": [
        "type_to_index = {\n",
        "    \"Type_1\": 0,\n",
        "    \"Type_2\": 1,\n",
        "    \"Type_3\": 2,\n",
        "}\n",
        "\n",
        "\n",
        "def data_iterator(image_id_type_list, batch_size, image_size, verbose=0, test_mode=False):\n",
        "    \n",
        "    while True:\n",
        "        X = np.zeros((batch_size, 3) + image_size, dtype=np.float32)\n",
        "        Y = np.zeros((batch_size, 3), dtype=np.uint8)\n",
        "        image_ids = np.empty((batch_size,), dtype=np.object)\n",
        "        counter = 0\n",
        "        for i, (image_id, image_type) in enumerate(image_id_type_list):\n",
        "            \n",
        "            img = get_image_data(image_id, image_type)\n",
        "            img = cv2.resize(img, dsize=image_size[::-1])\n",
        "            img = img.transpose([2,0,1])\n",
        "            img = img.astype(np.float32) / 255.0\n",
        "                        \n",
        "            X[counter, :, :, :] = img            \n",
        "            if test_mode:\n",
        "                image_ids[counter] = image_id\n",
        "            else:\n",
        "                Y[counter, type_to_index[image_type]] = 1    \n",
        "                \n",
        "            if verbose > 0:\n",
        "                print(\"Image id/type:\", image_id, image_type)\n",
        "            \n",
        "            counter += 1\n",
        "            if counter == batch_size:\n",
        "                yield (X, Y) if not test_mode else (X, Y, image_ids)\n",
        "                X = np.zeros((batch_size, 3) + image_size, dtype=np.float32)\n",
        "                Y = np.zeros((batch_size, 3), dtype=np.uint8)\n",
        "                image_ids = np.empty((batch_size,), dtype=np.object)\n",
        "                counter = 0\n",
        "        \n",
        "        if counter > 0:\n",
        "            X = X[:counter,:,:,:]\n",
        "            Y = Y[:counter,:]\n",
        "            image_ids = image_ids[:counter]\n",
        "            yield (X, Y) if not test_mode else (X, Y, image_ids)\n",
        "            \n",
        "        if test_mode:\n",
        "            break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "3090c8b3-f1d9-30b4-85d2-a89ecb5a5c78"
      },
      "outputs": [],
      "source": [
        "val_split=0.3\n",
        "type_ids = [type_1_ids, type_2_ids, type_3_ids]\n",
        "image_types = [\"Type_1\", \"Type_2\", \"Type_3\"]\n",
        "train_ll = [int(len(ids) * (1.0 - val_split)) for ids in type_ids]\n",
        "val_ll = [int(len(ids) * (val_split)) for ids in type_ids]\n",
        "\n",
        "\n",
        "count = 0\n",
        "train_id_type_list = []\n",
        "train_ids = [ids[:l] for ids, l in zip(type_ids, train_ll)]\n",
        "max_size = max(train_ll)\n",
        "while count < max_size:    \n",
        "    for l, ids, image_type in zip(train_ll, train_ids, image_types):    \n",
        "        image_id = ids[count % l]\n",
        "        train_id_type_list.append((image_id, image_type))\n",
        "    count += 1\n",
        "   \n",
        "\n",
        "count = 0\n",
        "val_id_type_list = []\n",
        "val_ids = [ids[tl:tl+vl] for ids, tl, vl in zip(type_ids, train_ll, val_ll)]\n",
        "max_size = max(val_ll)\n",
        "while count < max_size:    \n",
        "    for l, ids, image_type in zip(val_ll, val_ids, image_types):    \n",
        "        image_id = ids[count % l]\n",
        "        val_id_type_list.append((image_id, image_type))\n",
        "    count += 1\n",
        "\n",
        "assert len(set(train_id_type_list) & set(val_id_type_list)) == 0, \"WTF\" \n",
        "\n",
        "    \n",
        "print(\"Train dataset contains : \")\n",
        "print(\"-\", train_ll, \" images of corresponding types\")\n",
        "print(\"Validation dataset contains : \")\n",
        "print(\"-\", val_ll, \" images of corresponding types\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "696d4b4f-17bc-ce9d-4f46-cbb81fd12e60"
      },
      "outputs": [],
      "source": [
        "image_size = (224, 224)\n",
        "batch_size = 15\n",
        "train_iter = data_iterator(train_id_type_list, batch_size=batch_size, image_size=image_size, verbose=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "1202960d-1113-85a2-8211-142c8e020cc0"
      },
      "outputs": [],
      "source": [
        "for X, Y in train_iter:\n",
        "    print(X.shape, X.dtype, Y.shape)\n",
        "    n = 5\n",
        "    for counter in range(batch_size):\n",
        "        if counter % n == 0:\n",
        "            plt.figure(figsize=(12, 4))\n",
        "        plt.subplot(1, n, counter % n + 1)\n",
        "        plt.imshow(X[counter, :, :, :].transpose([1, 2, 0]))\n",
        "        plt.title(\"Type : {}\".format(Y[counter,:]))\n",
        "        plt.axis('off')\n",
        "    \n",
        "    break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a24022e8-a665-e461-7fe3-e265ff75fdb7"
      },
      "outputs": [],
      "source": [
        "image_size = (224, 224)\n",
        "batch_size = 15\n",
        "val_iter = data_iterator(val_id_type_list, batch_size=batch_size, image_size=image_size, verbose=1)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "8a643e65-083f-1f60-f6ed-38881193a236"
      },
      "outputs": [],
      "source": [
        "for X, Y in val_iter:\n",
        "    print(X.shape, X.dtype, Y.shape)\n",
        "    n = 5\n",
        "    for counter in range(batch_size):\n",
        "        if counter % n == 0:\n",
        "            plt.figure(figsize=(12, 4))\n",
        "        plt.subplot(1, n, counter % n + 1)\n",
        "        plt.imshow(X[counter, :, :, :].transpose([1, 2, 0]))\n",
        "        plt.title(\"Type : {}\".format(Y[counter,:]))\n",
        "        plt.axis('off')\n",
        "    \n",
        "    break"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "969725f8-a841-152f-6a3c-a5e8a6ed9e02"
      },
      "outputs": [],
      "source": ""
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "248665e2-fb26-4052-7c78-eec07199d44c"
      },
      "source": [
        "### Try ResNet from Keras applications"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "829aa560-ad9b-c46d-5c9f-16a399dea1c1"
      },
      "outputs": [],
      "source": [
        "from keras.applications.resnet50 import ResNet50\n",
        "from keras.layers import Dense, Flatten\n",
        "from keras.models import Model\n",
        "\n",
        "image_size = (224, 224)\n",
        "\n",
        "base_model = ResNet50(include_top=False, weights=None, input_tensor=None, input_shape=(3,) + image_size)\n",
        "x = Flatten()(base_model.output)\n",
        "output = Dense(3, activation='softmax')(x)\n",
        "model = Model(inputs=base_model.input, outputs=output)\n",
        "model.summary()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "d1a0a8e3-5884-dec2-5850-d58a36d92e13"
      },
      "outputs": [],
      "source": [
        "model.compile(loss='categorical_crossentropy', optimizer='adadelta', metrics=['accuracy',])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "91e407e4-79a5-8b65-76c3-e84625d228f9"
      },
      "source": [
        "### Random predictions"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "fb5f6ad0-4f20-d665-1962-ec9df3e72de0"
      },
      "outputs": [],
      "source": [
        "def logloss_mc(y_true, y_prob, epsilon=1e-15):\n",
        "    \"\"\" Multiclass logloss\n",
        "    This function is not officially provided by Kaggle, so there is no\n",
        "    guarantee for its correctness.\n",
        "    https://github.com/ottogroup/kaggle/blob/master/benchmark.py\n",
        "    \"\"\"\n",
        "    # normalize\n",
        "    y_prob = y_prob / y_prob.sum(axis=1).reshape(-1, 1)\n",
        "    y_prob = np.maximum(epsilon, y_prob)\n",
        "    y_prob = np.minimum(1 - epsilon, y_prob)\n",
        "    # get probabilities\n",
        "    y = [y_prob[i, j] for (i, j) in enumerate(y_true)]\n",
        "    ll = - np.mean(np.log(y))\n",
        "    return ll"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "ad86c7b9-085a-938c-07c0-3480eff2650a"
      },
      "outputs": [],
      "source": [
        "batch_size = 16\n",
        "val_iter = data_iterator(val_id_type_list, batch_size=batch_size, image_size=image_size, test_mode=True)\n",
        "\n",
        "total_loss = 0.0\n",
        "total_counter = 0 \n",
        "for X, Y_true, _ in val_iter:            \n",
        "    s = Y_true.shape[0]\n",
        "    total_counter += s\n",
        "    #Y_pred = model.predict(X)\n",
        "    Y_pred = 0.33333 * np.ones_like(Y_true)\n",
        "    loss = logloss_mc(Y_true, Y_pred)\n",
        "    print(\"--\", total_counter, \"batch loss : \", loss)\n",
        "    total_loss += s * loss\n",
        "\n",
        "total_loss *= 1.0 / total_counter   \n",
        "print(\"Total loss : \", total_loss)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "9af7139d-0f3b-7c91-e55d-5f8733c4e91d"
      },
      "outputs": [],
      "source": [
        "df = pd.DataFrame(columns=['image_name','Type_1','Type_2','Type_3'])\n",
        "def get_test_id_type_list():\n",
        "    return [(image_id, 'Test') for image_id in test_ids]\n",
        "\n",
        "image_size = (224, 224)\n",
        "batch_size = 16\n",
        "test_id_type_list = get_test_id_type_list()\n",
        "test_iter = data_iterator(test_id_type_list, batch_size=batch_size, image_size=image_size, test_mode=True)\n",
        "\n",
        "\n",
        "df = pd.DataFrame(columns=['image_name','Type_1','Type_2','Type_3'])\n",
        "total_counter = 0\n",
        "for X, _, image_ids in test_iter:            \n",
        "    #Y_pred = model.predict(X)    \n",
        "    s = X.shape[0]\n",
        "    total_counter += s\n",
        "    Y_pred = 0.33333 * np.ones((s, 3))\n",
        "    print(\"--\", total_counter, image_ids)\n",
        "    for i in range(s):\n",
        "        df.loc[total_counter + i, :] = (image_ids[i] + '.jpg', ) + tuple(Y_pred[i, :])"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "fe93644a-8a18-7c80-08c7-6e399fdd49be"
      },
      "outputs": [],
      "source": [
        "print(df.shape)\n",
        "df.head()"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "eeefe47c-0567-7ee8-3995-751905183f74"
      },
      "outputs": [],
      "source": [
        "import datetime\n",
        "now = datetime.datetime.now()\n",
        "info = 'random_predictions'\n",
        "sub_file = 'submission_' + info + '_' + str(now.strftime(\"%Y-%m-%d-%H-%M\")) + '.csv'\n",
        "df.to_csv(sub_file, index=False)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "a93b5287-f7f0-3aaa-6bbc-b65cb921299c"
      },
      "outputs": [],
      "source": [
        "!ls "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "_cell_guid": "5b5a3c1c-7712-3a9a-e4a9-600dd88b872c"
      },
      "source": [
        "### Training phase\n",
        "\n",
        "Stops by Kaggle server due to 1200 timeout "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "46037148-008f-e031-9732-1755e1a121c1"
      },
      "outputs": [],
      "source": [
        "batch_size=16\n",
        "samples_per_epoch = 512\n",
        "nb_val_samples = 64\n",
        "\n",
        "print(batch_size, samples_per_epoch, nb_val_samples)\n",
        "\n",
        "train_iter = data_iterator(train_id_type_list, batch_size=batch_size, image_size=image_size)\n",
        "val_iter = data_iterator(val_id_type_list, batch_size=batch_size, image_size=image_size)\n",
        "\n",
        "#history = model.fit_generator(\n",
        "#    train_iter,\n",
        "#    steps_per_epoch=samples_per_epoch, \n",
        "#    epochs=1,\n",
        "#    validation_data=val_iter,\n",
        "#    validation_steps=nb_val_samples,\n",
        "#    verbose=1\n",
        "#)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "6b4eb433-3a88-c08e-f717-eb1c3001b758"
      },
      "outputs": [],
      "source": [
        "type_3_ids"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "_cell_guid": "24ac2241-1168-4b34-81e1-3e978404778b"
      },
      "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.6.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}