{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# To enable the autocomplete\n%config Completer.use_jedi = False","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Global Definitions"},{"metadata":{"trusted":true},"cell_type":"code","source":"# The input of CNN (square image)\nIMAGE_SIZE = 128\nBATCH_SIZE = 32","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Prepating the dataset"},{"metadata":{},"cell_type":"markdown","source":"## Loading the dataset"},{"metadata":{},"cell_type":"markdown","source":"**Categories**\n- Cat == 0\n- Dog == 1"},{"metadata":{"trusted":true},"cell_type":"code","source":"# unzip the dataset\n\n# Just needed do once\n# !mkdir \"/kaggle/tmp\"\n# !unzip \"/kaggle/input/dogs-vs-cats/test1.zip\" -d \"/kaggle/tmp/\"\n# !unzip \"/kaggle/input/dogs-vs-cats/train.zip\" -d \"/kaggle/tmp/\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images_dir = \"/kaggle/tmp/test1/\"\ntrain_images_dir= \"/kaggle/tmp/train/\"\nsample_sub_path = \"/kaggle/input/dogs-vs-cats/sampleSubmission.csv\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# !ls \"/kaggle/tmp/train/\"dog.*","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Submission example\nsubmit_example = pd.read_csv(sample_sub_path)\nsubmit_example.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"list_images_path = os.listdir(train_images_dir)\n\nlabels = []\nfor image_path in list_images_path:\n    if \"cat\" in image_path:\n        labels.append('cat')\n    else:\n        labels.append('dog')\n\ndf = pd.DataFrame({\"file\":list_images_path, \"label\":labels})\n\nprint(df.head())\nprint(df.tail())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df['label'].hist()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image\nimport matplotlib.pyplot as plt","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sample = np.random.randint(len(df))\n\nimg_path = train_images_dir + df['file'][sample]\nlabel    = df['label'][sample]\n\nimg = Image.open(img_path)\n\nplt.imshow(img)\nplt.title(f\"Class:{label}\")\nplt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df.shape","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Spliting the dataset"},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df, valid_df = train_test_split(df, test_size = 0.15)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Train set:\", train_df.shape)\nprint(\"Validation set:\", valid_df.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data augmentation"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.preprocessing.image import ImageDataGenerator","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator\ntrain_gen = ImageDataGenerator(rescale = 1.0/255.0,\n                               horizontal_flip = True,\n                               vertical_flip   = True,\n                               fill_mode = 'nearest',\n                               rotation_range = 10,\n                               width_shift_range = 0.2,\n                               height_shift_range= 0.2,\n                               shear_range= 0.15,\n                               brightness_range= (.5,1.2),\n                               zoom_range = 0.2)\n\n# https://www.tensorflow.org/api_docs/python/tf/keras/preprocessing/image/ImageDataGenerator#flow_from_dataframe\ntrain_gen = train_gen.flow_from_dataframe(train_df,\n                                          directory = train_images_dir,\n                                          x_col = 'file', \n                                          y_col = 'label', \n                                          target_size =(IMAGE_SIZE, IMAGE_SIZE), \n                                          class_mode = 'categorical',\n                                          batch_size = BATCH_SIZE, \n                                          color_mode = 'rgb', \n                                          shuffle = True)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**Let's take a look at some generates images**"},{"metadata":{"trusted":true},"cell_type":"code","source":"n_samples = 8\n\nplt.figure(figsize=(20,20))\nfor x_gens, y_gens in train_gen:\n#     the first dimension of x_gens and y_gens will be equal to batch_size specifed previously\n    print(x_gens.shape)\n    i = 0\n    for sample_img, sample_class in zip(x_gens, y_gens):\n        \n        plt.subplot(5,4,i+1)\n        plt.title(f'Class:{np.argmax(sample_class)}')\n        plt.axis('off')\n        plt.imshow(sample_img)\n        \n        i += 1\n        \n        if i >= n_samples:\n            break\n    break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_gen = ImageDataGenerator(rescale=1./255)\nvalid_gen = valid_gen.flow_from_dataframe( valid_df, \n                                           directory = train_images_dir,\n                                           x_col='file',\n                                           y_col='label',\n                                           target_size=(IMAGE_SIZE,IMAGE_SIZE),\n                                           class_mode='categorical',\n                                           batch_size=BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# The Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"from tensorflow import keras","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def myModel(input_shape):\n    \n    X_input = keras.layers.Input(shape=input_shape, name='input')\n    \n#     128x128x3\n    \n    X = keras.layers.Conv2D(filters=32, kernel_size=(3,3), padding='same', name='conv-1')(X_input)    \n    X = keras.layers.BatchNormalization(name='b1')(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.MaxPool2D(pool_size=(2,2))(X)\n    X = keras.layers.Dropout(0.2)(X)\n    \n#     64x64x32\n    \n    X = keras.layers.Conv2D(filters=64, kernel_size=(3,3), padding='same', name='conv-2')(X)    \n    X = keras.layers.BatchNormalization(name='b2')(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.MaxPool2D(pool_size=(2,2))(X)\n    X = keras.layers.Dropout(0.2)(X)\n#     32x32x64\n\n    X = keras.layers.Conv2D(filters=128, kernel_size=(3,3), padding='same', name='conv-3')(X)    \n    X = keras.layers.BatchNormalization(name='b3')(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.MaxPool2D(pool_size=(2,2))(X)\n    X = keras.layers.Dropout(0.2)(X)\n\n#     16x16x128\n    \n    X = keras.layers.Conv2D(filters=128, kernel_size=(3,3), padding='same', name='conv-4')(X)    \n    X = keras.layers.BatchNormalization(name='b4')(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.MaxPool2D(pool_size=(2,2))(X)\n    X = keras.layers.Dropout(0.2)(X)\n\n#     8x8x128\n    \n    X = keras.layers.Conv2D(filters=128, kernel_size=(3,3), padding='same', name='conv-5')(X)    \n    X = keras.layers.BatchNormalization(name='b5')(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.MaxPool2D(pool_size=(2,2))(X)\n    X = keras.layers.Dropout(0.2)(X)\n    \n#     8x8x128\n    \n    X = keras.layers.Flatten()(X)\n    X = keras.layers.Dense(units=512, name='fc-6')(X)\n    X = keras.layers.BatchNormalization()(X)\n    X = keras.layers.Activation('relu')(X)\n    X = keras.layers.Dropout(0.3)(X)\n    \n    X = keras.layers.Dense(units=2, activation='softmax', name='output')(X)\n    \n    model = keras.Model(inputs = X_input, outputs = X, name='My_CNN_Model')\n    \n    return model\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = myModel((IMAGE_SIZE,IMAGE_SIZE,3))\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])\nmodel.summary()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training"},{"metadata":{"trusted":true},"cell_type":"code","source":"from keras.callbacks import EarlyStopping, ReduceLROnPlateau","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# To stop the training after N epochs and val_loss value not decreased\nearlystop = EarlyStopping(patience=2)\n# To reduce the learning rate when the accuracy not increase for 5 steps\nlearning_rate_reduction = ReduceLROnPlateau(monitor='val_acc', \n                                            patience=2, \n                                            verbose=1, \n                                            factor=0.5, \n                                            min_lr=0.0001)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# callbacks = [earlystop, learning_rate_reduction]\ncallbacks = [earlystop]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# model.load_weights(\"./weights.h5\")\nepochs = 30\nhistory = model.fit(train_gen, \n                    steps_per_epoch = len(train_df)//BATCH_SIZE, \n                    epochs = epochs, \n                    validation_data = valid_gen, \n                    validation_steps = len(valid_df)//BATCH_SIZE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Saving the weights\nmodel.save_weights('/kaggle/working/weights_v3.h5')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Evaluating"},{"metadata":{"trusted":true},"cell_type":"code","source":"history.history.keys()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Accuracy = \", history.history['accuracy'][-1])\nprint(\"Val. Accuracy = \", history.history['val_accuracy'][-1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs = range(1,len(loss)+1)\n\nplt.plot(epochs, loss, label='Train set')\nplt.plot(epochs, val_loss, label='Validation set')\n\nplt.legend()\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"accuracy = history.history['accuracy']\nval_accuracy = history.history['val_accuracy']\nepochs = range(1,len(loss)+1)\n\nplt.plot(epochs, accuracy, label='Train set')\nplt.plot(epochs, val_accuracy, label='Validation set')\n\nplt.legend()\nplt.xlabel('Accuracy')\nplt.ylabel('Loss')\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"**If I'd let training more it will be better**"},{"metadata":{},"cell_type":"markdown","source":"# Prediction from test subset"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_images_path = os.listdir(test_images_dir)\ntest_df = pd.DataFrame({'file':test_images_path})\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_gen = ImageDataGenerator(rescale=1.0/255.0)\ntest_gen = test_gen.flow_from_dataframe(test_df, \n                                        directory=test_images_dir, \n                                        x_col='file', \n                                        y_col=None,\n                                        class_mode=None,\n                                        target_size=(IMAGE_SIZE, IMAGE_SIZE),\n                                        color_mode=\"rgb\",\n                                        shuffle = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = model.predict(test_gen)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions = np.argmax(predictions,axis=1)\npredictions.shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"nsamples = 8\n\nplt.figure(figsize=(20,20))\nfor i, file in enumerate(test_df['file'][:nsamples]):\n    img = Image.open(test_images_dir+file)\n    \n    plt.subplot(5,4, i+1)\n    plt.imshow(img)\n    plt.title(f\"Class:{predictions[i]}\")\n    plt.axis('off')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"submit_df = pd.DataFrame()\nsubmit_df['id'] = range(1,len(predictions)+1)\nsubmit_df['label'] = predictions\n\nsubmit_df.to_csv('./submission.csv', index=False)\n\nsubmit_df.head(10)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}