{"cells":[{"metadata":{},"cell_type":"markdown","source":"# In this kernel we’ll try to identify correctly if the image we’re seeing is a dog=1 or a cat=0 .\n# In order to do so I’ll use dog & cat image dataset as input to a data augmentation generator + CNN . \n# After optimzation process - optimal layers are 5 + 2 FC layers \n# I also run semi grid search on dropout , filter size .etc.. \n"},{"metadata":{"_uuid":"fe76d1d1ded592430e7548feacfa38dc42f085d9"},"cell_type":"markdown","source":"# Imports"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport zipfile\nfrom keras.preprocessing.image import ImageDataGenerator, load_img\nfrom keras.utils import to_categorical\nfrom sklearn.model_selection import train_test_split\nimport matplotlib.pyplot as plt\nimport random\nfrom subprocess import check_output\nfrom keras.callbacks import EarlyStopping, ReduceLROnPlateau\nfrom keras.models import Sequential\nfrom keras.layers import Conv2D, MaxPooling2D, Dropout, Flatten, Dense, Activation, BatchNormalization\nimport os\nprint(check_output([\"ls\", \"../input/\"]).decode(\"utf8\"))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Extract all train images"},{"metadata":{"trusted":true},"cell_type":"code","source":"with zipfile.ZipFile('../input/train.zip', 'r') as z:    \n    z.extractall(\".\") \n#print(check_output([\"ls\", \"train\"]).decode(\"utf8\"))\n   ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Get  filenames paths + define category (1 - dog , 0 - cat) and fill both of those varibles inside dataframe"},{"metadata":{"trusted":true},"cell_type":"code","source":"filenames = os.listdir(\"train\")\ncategories = []\nfor filename in filenames:\n    category = filename.split('.')[0]\n    if category == 'dog':\n        categories.append(1)\n    else:\n        categories.append(0)\n\ndf = pd.DataFrame({\n    'filename': filenames,\n    'category': categories\n})\n\ndf.head(10) ##spot check \n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Define constant for CNN & data augmentation generator"},{"metadata":{"trusted":true},"cell_type":"code","source":"FAST_RUN       = False\nIMAGE_WIDTH    =128\nIMAGE_HEIGHT   =128\nIMAGE_SIZE     =(IMAGE_WIDTH, IMAGE_HEIGHT)\nIMAGE_CHANNELS =3\nDROP_OUT_VALUE =0.25\nFILTER_SIZE    =(3, 3)\nPOOL_SIZE      =(2, 2)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load & plot random image from DF"},{"metadata":{"trusted":true},"cell_type":"code","source":"sample = random.choice(filenames)\nimage = load_img(\"train/\"+sample)\nplt.imshow(image)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"a999484fc35b73373fafe2253ae9db7ff46fdb90"},"cell_type":"markdown","source":"# Count  dog & cat images"},{"metadata":{"trusted":true,"_uuid":"fa26f0bc7a6d835a24989790b20f3c6f32946f45"},"cell_type":"code","source":"df['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"3a08da58107777a1dd05c4a4bf5c484484923cac"},"cell_type":"markdown","source":"# Inside training data we have 24000 dog & cat images"},{"metadata":{},"cell_type":"markdown","source":"# We have 6 tiers where inside each tier we have : \n# Conv layer ->  batch normalization -> max pooling -> dropout \n# Last layer will include FC layer : flatten ->dense ->droput ->dense \n# Input layer: We'll take the images and resample image from Height X Weight X 3 ->  256 X256 X 3\n# Output Layer: classify dog=1 or cat =0 "},{"metadata":{"trusted":true,"_uuid":"8c9f833c1441b657c779844912d0b8028218d454"},"cell_type":"code","source":"\n\nmodel = Sequential()\n\nmodel.add(Conv2D(32, FILTER_SIZE, activation='relu', input_shape=(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_CHANNELS)))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=POOL_SIZE))\nmodel.add(Dropout(DROP_OUT_VALUE))\n\nmodel.add(Conv2D(64, FILTER_SIZE, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=POOL_SIZE))\nmodel.add(Dropout(DROP_OUT_VALUE))\n\nmodel.add(Conv2D(128, FILTER_SIZE, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=POOL_SIZE))\nmodel.add(Dropout(DROP_OUT_VALUE))\n\n\nmodel.add(Conv2D(192, FILTER_SIZE, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=POOL_SIZE))\nmodel.add(Dropout(0.35))\n\nmodel.add(Conv2D(256, FILTER_SIZE, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(MaxPooling2D(pool_size=POOL_SIZE))\nmodel.add(Dropout(0.45))\n\n\nmodel.add(Flatten())\nmodel.add(Dense(512, activation='relu'))\nmodel.add(BatchNormalization())\nmodel.add(Dropout(DROP_OUT_VALUE))\nmodel.add(Dense(2, activation='softmax')) # 2 because we have cat and dog classes\n\nmodel.compile(loss='categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])\n\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"76c9ba4fb7f930c96b2c3e0d6b68ed9fa6a4227b"},"cell_type":"markdown","source":"#  Early Stop - prevent over fitting we will stop the learning after 10 epochs or val_loss not decreased "},{"metadata":{"trusted":true,"_uuid":"3421c5ec428da6c0d8cc1184179a9caff1e01d1c"},"cell_type":"code","source":"earlystop = EarlyStopping(patience=15)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"51d3fe52e911286433cedf6e47332948a253361e"},"cell_type":"markdown","source":"# Learning Rate Reduction-reduce learning rate when then accuracy not increase for 2 steps"},{"metadata":{"trusted":true,"_uuid":"8010a5661ad8924d2db24af0f3c00b1593b38901"},"cell_type":"code","source":"learning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', \n                                            patience=2, \n                                            verbose=1, \n                                            factor=0.4, \n                                            min_lr=0.0001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"a79cc604199469789f183096d863f7248e5f6aab"},"cell_type":"code","source":"callbacks = [earlystop, learning_rate_reduction]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Because we will use image genaretor `with class_mode=\"categorical\"`. We need to convert column category into string. Then imagenerator will convert it one-hot encoding which is good for our classification. \n\nSo we will convert 1 to dog and 0 to cat"},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df[\"category\"] = df[\"category\"].replace({0: 'cat', 1: 'dog'}) \ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"4eeb7af8dcf02c4ef5ca744c8305c51a2f5cedef"},"cell_type":"code","source":"train_df, validate_df = train_test_split(df, test_size=0.25, random_state=42)\ntrain_df = train_df.reset_index(drop=True)\nvalidate_df = validate_df.reset_index(drop=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"b84836337441705eda9d2e655665ffa14d9feead"},"cell_type":"code","source":"train_df['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"19cf03f9a3c39532d6e2d06bd30be49a5afd9d57"},"cell_type":"code","source":"validate_df['category'].value_counts().plot.bar()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"ae3dec0361f0443132d0309d3b883ee80070cf9f"},"cell_type":"code","source":"total_train = train_df.shape[0]\ntotal_validate = validate_df.shape[0]\nbatch_size=15\ntotal_train","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ff760be9104f7d9492467b8d9d3405011aa77d11"},"cell_type":"markdown","source":"# Traning Generator"},{"metadata":{"trusted":true,"_uuid":"4d1c7818703a8a4bac5c036fdea45972aa9e5e9e"},"cell_type":"code","source":"train_datagen = ImageDataGenerator(\n    rotation_range=15,\n    rescale=1./255,\n    shear_range=0.1,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    width_shift_range=0.1,\n    height_shift_range=0.1\n)\n\ntrain_generator = train_datagen.flow_from_dataframe(\n    train_df, \n    \"train\", \n    x_col='filename',\n    y_col='category',\n    target_size=IMAGE_SIZE,\n    class_mode='categorical',\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"859c7b2857939c19fd2e3bb32839c9f7deb5aa3f"},"cell_type":"markdown","source":"### Validation Generator"},{"metadata":{"trusted":true,"_uuid":"7925e16bcacc89f4484fb6fe47e54d6420af732e"},"cell_type":"code","source":"validation_datagen = ImageDataGenerator(rescale=1./255)\nvalidation_generator = validation_datagen.flow_from_dataframe(\n    validate_df, \n    \"train\", \n    x_col='filename',\n    y_col='category',\n    target_size=IMAGE_SIZE,\n    class_mode='categorical',\n    batch_size=batch_size\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6e17fc1f002fedd60febb78fee5e81770640b909"},"cell_type":"markdown","source":"# See how our generator work"},{"metadata":{"trusted":true,"_uuid":"4252cce168ab65f88e44a8ebc2672607bc852af4"},"cell_type":"code","source":"example_df = train_df.sample(n=1).reset_index(drop=True)\nexample_generator = train_datagen.flow_from_dataframe(\n    example_df, \n    \"train\", \n    x_col='filename',\n    y_col='category',\n    target_size=IMAGE_SIZE,\n    class_mode='categorical'\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"23d923dba747f8b47dc75569244cecc6f70df321"},"cell_type":"code","source":"plt.figure(figsize=(12, 12))\nfor i in range(0, 15):\n    plt.subplot(5, 3, i+1)\n    for X_batch, Y_batch in example_generator:\n        image = X_batch[0]\n        plt.imshow(image)\n        break\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5cd8df64e794ed17de326b613a9819e7da977a0e"},"cell_type":"markdown","source":"# Fit Model"},{"metadata":{"trusted":true,"_uuid":"0836a4cc8aa0abf603e0f96573c0c4ff383ad56b"},"cell_type":"code","source":"epochs=3 if FAST_RUN else 16\nhistory = model.fit_generator(\n    train_generator, \n    epochs=epochs,\n    validation_data=validation_generator,\n    validation_steps=total_validate//batch_size,\n    steps_per_epoch=total_train//batch_size,\n    callbacks=callbacks\n)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"aa1fbc4081ae0de2993188b2bf658a0be5bc0687"},"cell_type":"markdown","source":"> # Save Model"},{"metadata":{"trusted":true,"_uuid":"67575a4decdaf79a915d23151626b784ffa82642"},"cell_type":"code","source":"model.save_weights(\"cat_dod_model.h5\")    ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"1b76c0a9040bc0babf0a453e567e41e22f8a1e0e"},"cell_type":"markdown","source":"# Plot training images with dog/cat output"},{"metadata":{"trusted":true,"_uuid":"79055f2dc3e2abb47bea758e0464c86ca42ab431"},"cell_type":"code","source":"fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 12))\nax1.plot(history.history['loss'], color='b', label=\"Training loss\")\nax1.plot(history.history['val_loss'], color='r', label=\"validation loss\")\nax1.set_xticks(np.arange(1, epochs, 1))\nax1.set_yticks(np.arange(0, 1, 0.1))\n\nax2.plot(history.history['acc'], color='b', label=\"Training accuracy\")\nax2.plot(history.history['val_acc'], color='r',label=\"Validation accuracy\")\nax2.set_xticks(np.arange(1, epochs, 1))\n\nlegend = plt.legend(loc='best', shadow=True)\nplt.tight_layout()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"huge thanks to Uysim Keras CNN Dog or Cat Classification notebook "}],"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":4}