{"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\nimport time\nt_start = time.time()","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\n# Initial size is 224\nROWS = 224\nCOLS = 224\nCHANNELS = 1\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=40\nEPOCHS=100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2af2a3c27b43e1eb616fbc81e11ca348b80d094b","scrolled":true},"cell_type":"code","source":"# Separating 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\ntrain_images = train_dogs[:4000] + train_cats[:4000]\ntest_images = test_images[:1000]\nrandom.shuffle(train_images)\n\ndef read_image(file_path):\n    img= cv2.imread(file_path, cv2.IMREAD_GRAYSCALE)\n    return cv2.resize(img, (ROWS, COLS), interpolation=cv2.INTER_CUBIC)\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    X = np.array(X)\n    X = np.expand_dims(X, axis=3)\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"},{"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":{"trusted":true,"_uuid":"85ea2b747ee0c9981688d5399eb989150ef916d6"},"cell_type":"code","source":"# Free some space\nimport gc\ndel X_train, X_val, y_train, y_val, labels\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"84db2039f379c8c65dd1925029b3fdaac495423f"},"cell_type":"markdown","source":"# 8 - Generate .csv for submission"},{"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":"663a0512aeb6e2db44bac179a1b819f1c9d65834"},"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, CHANNELS)\n        out = best_model.predict([data])[0][0]\n        f.write('{},{}\\n'.format(img_num,out))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"26d6cb3dc8908ddf4a9b0b491825892a0cbdc760"},"cell_type":"code","source":"t_finish = time.time()\nprint(f\"Kernel run time = {(t_finish-t_start)/3600} hours\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ef8d4f2f5f2980c53f3e70fdbb49e3735d3ff7a4"},"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}