{"cells": [{"metadata": {}, "cell_type": "markdown", "source": ["## Introduction\n", "The purpose of this kernal is to demonstrate how keras works. To better understand the CNN model used, visit:\n", "[https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/](https://ujjwalkarn.me/2016/08/11/intuitive-explanation-convnets/)"]}, {"metadata": {"_cell_guid": "53b2a834-b677-4988-8dd1-5cb3816d2306", "_uuid": "6e0f7ac1f5b04fd2c9263031ee04543234764cae"}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["import numpy as np\n", "import pandas as pd\n", "import random, cv2, os\n", "# 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\n", "from sklearn.model_selection import StratifiedKFold, cross_val_score"]}, {"metadata": {}, "cell_type": "markdown", "source": ["## Prepare Directories"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["# Will retrieve all file directories and lable them with dogs and cats.\n", "SAMEPLE_SIZE = 200 # To expedite development, we will first sample a very small portion of all images to do programming, but this number can later be changed to scale up\n", "TRAIN_DIRECTORY = \"../input/train/\"\n", "TEST_DIRECTORY = \"../input/test/\"\n", "\n", "dog_directories = [TRAIN_DIRECTORY + filename for filename in os.listdir(TRAIN_DIRECTORY) if 'dog' in filename]\n", "cat_directories = [TRAIN_DIRECTORY + filename for filename in os.listdir(TRAIN_DIRECTORY) if 'cat' in filename]\n", "test_directories_all = [TEST_DIRECTORY + filename for filename in os.listdir(TEST_DIRECTORY)]\n", "\n", "# shuffle directories in case we want to have different images\n", "random.shuffle(dog_directories)\n", "random.shuffle(cat_directories)\n", "random.shuffle(test_directories_all)\n", "train_directories = dog_directories[:SAMEPLE_SIZE] + cat_directories[:SAMEPLE_SIZE]\n", "random.shuffle(train_directories)\n", "\n", "test_directories = test_directories_all[:25]"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["y_train = []\n", "\n", "for filepath in train_directories:\n", "    if(\"dog\" in filepath):\n", "        y_train.append(1)\n", "    else:\n", "        y_train.append(0)"]}, {"metadata": {}, "cell_type": "markdown", "source": ["## Resize Images\n", "Kaggle has certain limitations on speed, so we resize the picture to reduce calculation. cv2 is the out-of-the-box solution for image related tasks in python."]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["ROWS = 64\n", "COLS = 64\n", "CHANNELS = 3\n", "sample_image_directory = train_directories[5]\n", "temp = cv2.imread(sample_image_directory, 1)\n", "img = cv2.resize(temp, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n", "plt.imshow(img)\n", "plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis\n", "plt.show()"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["# Load all images to data after resize\n", "ROWS = 64\n", "COLS = 64\n", "CHANNELS = 3\n", "\n", "\n", "def load_images(directories):\n", "    count = len(directories)\n", "    data = np.ndarray((count, CHANNELS, ROWS, COLS), dtype=np.uint8)\n", "    for (i, file) in enumerate(directories):\n", "        temp = cv2.imread(file, 1) # 1 = load color image\n", "        img = cv2.resize(temp, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n", "        data[i] = img.T\n", "        if i > 1 and i%50 == 0: print(\"Loaded {} of {}.\".format(i, count))\n", "    return data\n", "x_train = load_images(train_directories)\n", "x_test = load_images(test_directories)"]}, {"metadata": {}, "cell_type": "markdown", "source": ["## CNN Model"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["model = Sequential()\n", "\n", "model.add(Conv2D(32, (3, 3), padding=\"same\", input_shape=(3, ROWS, COLS), activation='relu' , data_format=\"channels_first\"))\n", "model.add(Conv2D(32, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(MaxPooling2D(pool_size=(2, 2)))\n", "\n", "model.add(Conv2D(64, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(Conv2D(64, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(MaxPooling2D(pool_size=(2, 2)))\n", "\n", "model.add(Conv2D(128, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(Conv2D(128, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(MaxPooling2D(pool_size=(2, 2)))\n", "\n", "model.add(Conv2D(256, (3, 3), padding=\"same\", activation='relu'))\n", "model.add(Conv2D(256, (3, 3), padding=\"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'])"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["model.summary()"]}, {"metadata": {}, "cell_type": "markdown", "source": ["## Train"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["class LossHistory(Callback):\n", "    def on_train_begin(self, logs={}):\n", "        self.losses = []\n", "\n", "    def on_batch_end(self, batch, logs={}):\n", "        self.losses.append(logs.get('loss'))\n", "        \n", "history = LossHistory()\n", "\n", "epochs  = 10\n", "batch_size = 16\n", "\n", "early_stopping = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto')        \n", "\n", "model.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,\n", "              validation_split=0.25, verbose=0, shuffle=True, callbacks=[history, early_stopping])"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["history.losses"]}, {"metadata": {}, "cell_type": "markdown", "source": ["## Predict"]}, {"metadata": {"collapsed": true}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["y_predict = model.predict(x_test)"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["# Function for show single image\n", "def show_img(data, text=\"\"):\n", "    plt.figure(figsize=(10,5))\n", "    plt.imshow(data.T)\n", "    plt.xticks([]), plt.yticks([])  # to hide tick values on X and Y axis\n", "    plt.title(text)\n", "    plt.show()\n", "show_img(x_train[0])"]}, {"metadata": {}, "cell_type": "code", "execution_count": null, "outputs": [], "source": ["arr = random.sample(range(0,24), 4)\n", "y_animal = [\"dog\" if i > 0.5 else \"cat\" for i in y_predict]\n", "for i in arr:\n", "    show_img(x_test[i], \"I'm {}% sure am a {}.\".format(100*y_predict[i], y_animal[i]))"]}], "metadata": {"language_info": {"nbconvert_exporter": "python", "pygments_lexer": "ipython3", "mimetype": "text/x-python", "name": "python", "version": "3.6.3", "codemirror_mode": {"version": 3, "name": "ipython"}, "file_extension": ".py"}, "kernelspec": {"display_name": "Python 3", "name": "python3", "language": "python"}}, "nbformat": 4, "nbformat_minor": 1}