{"cells":[{"metadata":{"trusted":true,"_uuid":"aa7cdc2729c16965787492a8461bb075a6e21079"},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# from keras import layers, models, optimizers\nfrom keras.models import Model\nfrom keras.layers import (Input, Dropout, Flatten, Conv2D, MaxPooling2D, Dense, Activation,\n                          BatchNormalization, Concatenate)\nfrom keras.optimizers import SGD, RMSprop, Adam\nfrom keras.callbacks import ModelCheckpoint, Callback, EarlyStopping\n\nfrom keras.preprocessing.image import ImageDataGenerator, img_to_array, load_img\nfrom keras.utils import np_utils\nfrom sklearn.model_selection import train_test_split\nimport os, cv2, random, re, csv\nfrom tqdm import tqdm\n\n# %matplotlib inline\n# import keras\n# keras.backend.backend() #=> Tensorflow","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1061c8a7081db39401d034506d388ef1f270f50a"},"cell_type":"markdown","source":"# 1 - Preparing the data"},{"metadata":{"trusted":true,"_uuid":"fb2c08b9d93aaaf8c9a7d6911d8a1f11ba20ec8d"},"cell_type":"code","source":"TRAIN_DIR = '../input/train'\nTEST_DIR = '../input/test'\n\nROWS = 200\nCOLS = 200\nCHANNELS = 3\n\n# because of the limited resources we have, we have to adapt the BATCH_SIZE \n# With image size and complexity of the model (nb params)\nBATCH_SIZE=50\nEPOCHS=40","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2af2a3c27b43e1eb616fbc81e11ca348b80d094b","scrolled":true},"cell_type":"code","source":"# This function resizes the images to 64x64 and samples 2000 images (8%) of the data.\n# I also separated cats and dogs for exploratory analysis\n\ntrain_images = [TRAIN_DIR+\"/\"+i for i in os.listdir(TRAIN_DIR)]\ntrain_dogs = [TRAIN_DIR+\"/\"+i for i in os.listdir(TRAIN_DIR) if 'dog' in i]\ntrain_cats = [TRAIN_DIR+\"/\"+i for i in os.listdir(TRAIN_DIR) if 'cat' in i]\n\ntest_images = [TEST_DIR+\"/\"+i for i in os.listdir(TEST_DIR)]\n\n#### For testing purposes\n# train_images = train_dogs[:4000] + train_cats[:4000]\n# test_images = test_images[:1000]\n# random.shuffle(train_images)\n\n# # Helper function to sort the image files based on the numeric value in each file name.\n# def atoi(text): return int(text) if text.isdigit() else text\n# def natural_keys(text): return [ atoi(c) for c in re.split('(\\d+)', text) ]\n# train_dogs.sort(key=natural_keys);\n# train_cats.sort(key=natural_keys);\n####\n\ndef read_image(file_path):\n    img= cv2.imread(file_path, cv2.IMREAD_COLOR)\n    return cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\n\n# Alternative function\nfrom keras.preprocessing import image\ndef read_image_(file_path):\n        img = image.load_img(file_path, target_size=(ROWS, COLS))\n        return image.img_to_array(img)\n\ndef prep_data(images):\n    X = [] # images as arrays\n    y = [] # labels\n    for image_file in tqdm(images):\n        image = read_image_(image_file)\n        X.append(image)\n        if 'dog' in image_file: y.append(1)\n        elif 'cat' in image_file: y.append(0)      \n    return X, y\n\nprint(\"Processing Train images\")\nX_train, y_train = prep_data(train_images)\n\nprint(\"Train: {} images with shape {}\".format(len(X_train),X_train[0].shape))\nprint(\"Test: {} images\".format(len(test_images)))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1d4463e2f7cbab63fc98277d263fa302e3c9c4e4"},"cell_type":"markdown","source":"# 2 - Generating the labels"},{"metadata":{"trusted":true,"_uuid":"61d19f207e0e3af2dbda7f715ae8a49938fab42f"},"cell_type":"code","source":"# We're dealing with classification problem here - (1) dogs (0) cats\nlabels = [1 if 'dog' in l else 0 for l in train_images]\nsns.countplot(labels)\nplt.title('Cats and Dogs');","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"d4483e0a00a89c6e94bd7119627143ffd5a6feca"},"cell_type":"markdown","source":"# 3 - Checking out Cats and Dogs"},{"metadata":{"trusted":true,"_uuid":"a8afe20840cca426831c5b9b697fcc78d5e2d34d"},"cell_type":"code","source":"# A quick side-by-side comparison of the animals\nfor idx in range(2):\n    idx = idx + np.random.randint(low=1, high=100); # To randomize images\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=(15, 5))\n    f = plt.imshow(pair)\n    f.axes.get_xaxis().set_visible(False)\n    f.axes.get_yaxis().set_visible(False)\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"e68eda8965dbba477b0a3dc2341ea4a696b5850c"},"cell_type":"markdown","source":"# 4 - CatdogNet-16\nA scaled down version of the VGG-16, with a few notable changes.\n- Number of convolution filters cut in half, fully connected (dense) layers scaled down\n- Optimizer changed to RMSprop\n- Output layer activation set to sigmooid for binary crossentropy\n- Some layers commented out for efficiency"},{"metadata":{"trusted":true,"_uuid":"9adaab5e9634d86b41640eff6de4cf8107b1a70f","scrolled":false},"cell_type":"code","source":"def convBatchActivMax_block(_input, N_Filters, N, kernel, blockNumber):\n    # N is used to Variate number of filters for each block\n    x = Conv2D(N_Filters* N, kernel_size=kernel, padding='same', activation='relu', name='block{}_conv{}_{}'.format(blockNumber, 1, kernel))(_input)\n    x = Conv2D(N_Filters* N, kernel_size=kernel, padding='same', name='block{}_conv{}_{}'.format(blockNumber, 2, kernel))(x)\n    x = BatchNormalization(name=\"block{}_BatchNorm_{}\".format(blockNumber,kernel))(x)\n    x = Activation('relu')(x)\n    \n    x = MaxPooling2D((2,2), strides=(2,2), name='block{}_pool_{}'.format(blockNumber, kernel))(x)\n    return x\n\ndef build_model(N_Filters=32):\n    input_layer = Input((ROWS, COLS, CHANNELS), name=\"InputLayer\")\n    \n    #----- Branch 1-------\n    ######################\n    # Block 1\n    x1 = convBatchActivMax_block(input_layer, N_Filters, 1, 3, 1)\n    # Block 2\n    x1 = convBatchActivMax_block(x1, N_Filters, 2, 3, 2)\n    # Block 3\n    x1 = convBatchActivMax_block(x1, N_Filters, 3, 3, 3)\n    \n    #----- Branch 2-------\n    ######################\n    x2 = convBatchActivMax_block(input_layer, N_Filters, 1, 5, 1)\n    # Block 2\n    x2 = convBatchActivMax_block(x2, N_Filters, 2, 5, 2)\n    # Block 3\n    x2 = convBatchActivMax_block(x2, N_Filters, 3, 5, 3)\n    \n    OutConcat = Concatenate()([x1,x2])\n    x = Conv2D(N_Filters*3, 1, activation='relu')(OutConcat)\n    \n    x = Flatten(name='flatten')(x)\n    x = Dense(N_Filters*10, activation='relu', name='fc1')(x)\n    x = Dropout(0.5)(x)\n    x = Dense(N_Filters*4, activation='relu', name='fc2')(x)\n    x = Dropout(0.5)(x)\n    \n    output = Dense(1, activation='sigmoid')(x)\n    \n    model = Model(input_layer, output)\n    model.compile(optimizer=RMSprop(lr=1e-4), loss='binary_crossentropy', metrics=['accuracy'])\n    return model\nmodel = build_model()\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"1e99530bae6008a8dc5ff85a8667eecda3067800","scrolled":false},"cell_type":"code","source":"#################\n# Plot The Model\n#################\nfrom keras.utils import plot_model \nplot_model(model, to_file='keras-baseline-architecture.png')\n\nfrom IPython.display import Image\nImage(filename='keras-baseline-architecture.png') ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6ebdcbbfd6e9abe6a905eab028c075b9a09fa768"},"cell_type":"code","source":"# First split the data in two sets, 80% for training, 20% for Val)\nX_train, X_val, y_train, y_val = train_test_split(X_train,y_train, test_size=0.2, random_state=1)\n\n# Augmentation configuration to use for training and validation\ntrain_datagen = ImageDataGenerator(\n                rescale=1. / 255,\n                rotation_range=40,\n                width_shift_range=0.2,\n                shear_range=0.2,\n                zoom_range=0.2,\n                horizontal_flip=True\n)\nvalidation_datagen = ImageDataGenerator(rescale=1./255)\n\n# Prepare generators for training and validation sets\ntrain_generator = train_datagen.flow(np.array(X_train), y_train, batch_size=BATCH_SIZE)\nvalidation_generator = validation_datagen.flow(np.array(X_val), y_val, batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"67acef950bbaf67b4b7cb5c626ff9c0c3d79181f","scrolled":false},"cell_type":"code","source":"from keras.callbacks import ReduceLROnPlateau, EarlyStopping, ModelCheckpoint\nCallbacks = [\n    EarlyStopping(monitor='val_loss', mode = 'min',patience=10, verbose=1),\n    ModelCheckpoint('BestModel.hdf5', monitor='val_loss', mode='min', save_best_only=True, verbose=1),\n    ReduceLROnPlateau(monitor='val_loss', mode='min', factor=0.1, patience=5, min_lr=0.0001, verbose=1)\n]\n\nhistory = model.fit_generator(\n    train_generator, \n    steps_per_epoch = len(X_train) // BATCH_SIZE,\n    callbacks = Callbacks,\n    epochs = EPOCHS,\n    validation_data = validation_generator,\n    validation_steps = len(X_val) // BATCH_SIZE\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"b858ea4f1f838c04055b2ffbc886d107232027fd"},"cell_type":"markdown","source":"# 5 - Plot Loss Trend"},{"metadata":{"trusted":true,"_uuid":"8c04888e85b9aa04eea12888731b2b6bb7c4cd17"},"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(history.history['acc'])\nplt.plot(history.history['val_acc'])\nplt.title('model accuracy')\nplt.ylabel('accuracy')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()\n\nplt.plot(history.history['loss'])\nplt.plot(history.history['val_loss'])\nplt.title('model loss')\nplt.ylabel('loss')\nplt.xlabel('epoch')\nplt.legend(['train', 'test'], loc='upper left')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f645df9b9434d4c1080eb9e96fb9b7ad4bb3babb"},"cell_type":"markdown","source":"# 6 - Save model"},{"metadata":{"trusted":true,"_uuid":"d53404f15e9e99c382f98732cd8e51d550ff92d7"},"cell_type":"code","source":"# model.save_weights('model_wieghts.h5')\n# model.save('model_keras.h5')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"84db2039f379c8c65dd1925029b3fdaac495423f"},"cell_type":"markdown","source":"# 8 - Generate .csv for submission"},{"metadata":{"_uuid":"e5b56fead6b031e3ed7010995cb72aefc21a1385"},"cell_type":"markdown","source":"## First Way"},{"metadata":{"trusted":true,"_uuid":"e55dabfa915b5990fcdaf21c8d735789b3e2ffc6"},"cell_type":"code","source":"from keras.models import load_model\nbest_model = load_model('BestModel.hdf5')\n\n# making_test_data() differs from prep_data(), because here we need the image & it's id\ndef making_test_data():\n    testing_data = []\n    for img_path in tqdm(test_images):\n        img_num = img_path.split('/')[-1].split('.')[0]\n        image = read_image(img_path)\n        testing_data.append([np.array(image), img_num])      \n    return testing_data # List of lists of images and there id's\n\ntest_data = making_test_data()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3f26b6ae1ad313117d2bfca23b88357a88d77fb1"},"cell_type":"code","source":"with open('submission_file.csv','w') as f:\n    f.write('id,label\\n')\n            \nwith open('submission_file.csv','a') as f:\n    # Predicting image by image\n    for data in tqdm(test_data):\n        img_num = data[1]\n        img_data = (data[0] / 255)\n        data = img_data.reshape(1, ROWS, COLS, 3)\n        out = best_model.predict([data])[0][0]\n        f.write('{},{}\\n'.format(img_num,out))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3634022790d10c157820403fec4b3cff1bbae44d"},"cell_type":"markdown","source":"## Second Way"},{"metadata":{"trusted":true,"_uuid":"7c780bba273a1cd55e5443438737a59f05ad1d60"},"cell_type":"code","source":"# Free some space\nimport gc\ndel X_train, X_val, y_train, y_val, test_data, labels\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b65218483c387c0866fea4f201006b4098df1fc1","scrolled":false},"cell_type":"code","source":"X_test, _ = prep_data(test_images)\nX_test = np.array(X_test)\nX_test /= 255.\npredictions = best_model.predict(X_test)\nfor 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(image.array_to_img(X_test[i]))\n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"72bc5389348e11af80a87d7d61f63cb9739365b8"},"cell_type":"code","source":"with open('dogs-v-cat-results.csv', 'w') as csvfile:\n    writer = csv.writer(csvfile, delimiter=',',\n                        quotechar='|', quoting=csv.QUOTE_MINIMAL)\n    writer.writerow(['id', 'label'])\n    for i, path in enumerate(test_images):\n        basename = os.path.basename(path)\n        name = os.path.splitext(basename)[0]\n        writer.writerow([name, predictions[i, 0]])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c041d7623ad6e31f67d1022cf2e38b14e24bbd60"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"42108214464e32e5654651d0a0b10429a43cbfd0"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}