{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Starter notebook for data loading, preprocessing / augmentation and applying a simple CNN\n### Acknowledgments: \n####    **https://www.kaggle.com/vstepanenko/batch-image-viewer**\n####    This excellent notebook for sampling and viewing batches of images","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator \nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport pandas as pd\nimport numpy as np \nimport random \nimport cv2\nimport os ","metadata":{"execution":{"iopub.status.busy":"2021-08-15T10:27:07.213077Z","iopub.execute_input":"2021-08-15T10:27:07.213699Z","iopub.status.idle":"2021-08-15T10:27:13.282687Z","shell.execute_reply.started":"2021-08-15T10:27:07.213603Z","shell.execute_reply":"2021-08-15T10:27:13.281441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dir = '/kaggle/input/landmark-recognition-2021/train'\ntrain_df = pd.read_csv('/kaggle/input/landmark-recognition-2021/train.csv')\n\n# Basic data exploaration \nprint(f'There are {len(train_df)} training images and {len(train_df[\"landmark_id\"].unique())} classes.\\n')\n# Count per class \nprint('The top 10 classes are as follows:\\n')\nprint(train_df['landmark_id'].value_counts()[:10])\n\n# Add extra column with relative path (up to the train directory)\ntrain_df['id_path'] = train_df['id'].map(lambda x: '/'.join(list(x[:3])) + f'/{x}.jpg')\ntrain_df[\"landmark_id\"] = train_df[\"landmark_id\"].astype(str).apply(lambda x:x.split(\",\"))","metadata":{"execution":{"iopub.status.busy":"2021-08-14T06:37:05.692986Z","iopub.execute_input":"2021-08-14T06:37:05.693295Z","iopub.status.idle":"2021-08-14T06:37:11.827575Z","shell.execute_reply.started":"2021-08-14T06:37:05.693262Z","shell.execute_reply":"2021-08-14T06:37:11.826764Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot n random images  \ndef plot_imgs(n):\n    for i in range(n):\n        ax = plt.subplot(1,n,i+1)\n        rand_num = random.randint(1,len(train_df))\n        img = list(train_df['id_path'])[rand_num]\n        landmark_id = list(train_df['landmark_id'])[rand_num]\n        path = os.path.join(train_dir, img)\n        img = cv2.imread(path)\n        img = cv2.resize(img,(224,224))\n        plt.imshow(img)\n        plt.title(landmark_id[0])\n        plt.show()\n    \nplot_imgs(3)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T05:00:31.59905Z","iopub.execute_input":"2021-08-14T05:00:31.599389Z","iopub.status.idle":"2021-08-14T05:00:33.052504Z","shell.execute_reply.started":"2021-08-14T05:00:31.599354Z","shell.execute_reply":"2021-08-14T05:00:33.051721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Data preprocessing and augmentation \nimage_generator = ImageDataGenerator(rescale=1./255,\n                                    zoom_range=0.2,\n                                    width_shift_range=0.4,\n                                    height_shift_range=0.4,\n                                    horizontal_flip=True,\n                                    vertical_flip=True,\n                                    rotation_range=60,\n                                    brightness_range=[0.8,1.1])\n\n# Load data from dataframe \ntrain_batches = image_generator.\\\n                flow_from_dataframe(\n                                    directory = train_dir,\n                                    dataframe = train_df.sample(n=20000),\n                                    class_mode = 'categorical',\n                                    x_col='id_path',\n                                    y_col='landmark_id',\n                                    batch_size=32,\n                                    shuffle=True,\n                                    target_size=(224,224))\n\n\n# Get the number of classes\nclasses = len(train_batches.class_indices) \n \n","metadata":{"execution":{"iopub.status.busy":"2021-08-14T05:01:21.5905Z","iopub.execute_input":"2021-08-14T05:01:21.590832Z","iopub.status.idle":"2021-08-14T05:02:05.038876Z","shell.execute_reply.started":"2021-08-14T05:01:21.590801Z","shell.execute_reply":"2021-08-14T05:02:05.037407Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = tf.keras.models.Sequential([\n  tf.keras.layers.Conv2D(filters = 64, \n                         kernel_size = (4,4),\n                         strides=(2,2),\n                         padding = 'same',\n                         input_shape = (224,224,3)),\n  tf.keras.layers.Activation(activation = 'relu'), \n  tf.keras.layers.BatchNormalization(),\n  tf.keras.layers.MaxPool2D(pool_size = (2,2), strides = 2), \n\n    tf.keras.layers.Conv2D(filters = 128, \n                         kernel_size = (4,4),\n                         strides=(2,2),\n                         padding = 'same'),\n  tf.keras.layers.Activation(activation = 'relu'), \n  tf.keras.layers.BatchNormalization(),\n  tf.keras.layers.MaxPool2D(pool_size = (2,2), strides = 2),\n  tf.keras.layers.Dropout(0.3),\n\n  \n  tf.keras.layers.Conv2D(filters = 64, \n                         kernel_size = (4,4),\n                         strides=(2,2),\n                         padding = 'same'),\n  tf.keras.layers.Activation(activation = 'relu'), \n  tf.keras.layers.BatchNormalization(),\n  tf.keras.layers.MaxPool2D(pool_size = (2,2), strides = 2),\n  tf.keras.layers.Dropout(0.3), \n\n  \n  tf.keras.layers.Conv2D(filters = 32, \n                         kernel_size = (4,4),\n                         strides=(2,2),\n                         padding = 'same'),\n  tf.keras.layers.Activation(activation = 'relu'), \n  tf.keras.layers.BatchNormalization(),\n  tf.keras.layers.MaxPool2D(pool_size = (2,2), strides = 2),\n\n  tf.keras.layers.Flatten(), \n  tf.keras.layers.Dense(4096, activation='relu'),\n  tf.keras.layers.Dropout(0.3),\n  tf.keras.layers.Dense(512, activation='relu'),\n  tf.keras.layers.Dropout(0.3), \n  tf.keras.layers.Dense(64, activation='relu'),\n  tf.keras.layers.BatchNormalization(),\n  tf.keras.layers.Dropout(0.3), \n  tf.keras.layers.Dense(classes, activation = 'softmax')\n])\n\n\n\n\nmodel.compile(loss = tf.keras.losses.CategoricalCrossentropy(),\n                     optimizer = tf.keras.optimizers.Adam(lr = 0.001),\n                     metrics = ['accuracy'])\n\nmodel.summary()\nprint(tf.keras.utils.plot_model(model))\nmodel_history = model.fit(train_batches,\n                          epochs = 10)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T05:04:43.655346Z","iopub.execute_input":"2021-08-14T05:04:43.655698Z","iopub.status.idle":"2021-08-14T06:09:37.977478Z","shell.execute_reply.started":"2021-08-14T05:04:43.655665Z","shell.execute_reply":"2021-08-14T06:09:37.976517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_loss_curves(history):\n    '''\n    Returns loss curves for training and validation metrics (if available)\n    '''\n    if \"val_loss\" in history.history:\n        loss = history.history[\"loss\"]\n        val_loss = history.history[\"val_loss\"]\n        accuracy = history.history[\"accuracy\"]\n        val_accuracy = history.history[\"val_accuracy\"]\n\n        epochs = range(len(history.history[\"loss\"])) #number of epochs \n\n        # Plot losses \n        plt.figsize=(10,7)\n        plt.plot(epochs, loss, label = 'training_loss')\n        plt.plot(epochs, val_loss, label = 'val_loss')\n        plt.title('loss')\n        plt.xlabel('epochs')\n        plt.legend()\n\n        # Plot accuracy \n        plt.figure()\n        plt.plot(epochs, accuracy, label = 'training_accuracy')\n        plt.plot(epochs, val_accuracy, label = 'val_accuracy')\n        plt.title('accuracy')\n        plt.xlabel('epochs')\n        plt.legend()\n    \n    else:\n        # Plot training loss and accuracy together \n        loss = history.history[\"loss\"]\n        accuracy = history.history[\"accuracy\"]\n\n        epochs = range(len(history.history[\"loss\"])) #number of epochs \n\n        fig, ax1 = plt.subplots(figsize=(11, 9))\n        ax1.plot(epochs, accuracy, label = 'training_accuracy')\n        plt.xlabel('epochs')\n        ax1.set_ylabel('Training Accuracy')\n        \n        ax2 = ax1.twinx()\n        ax2.plot(epochs, loss, label = 'training_loss', color = 'tab:red')\n        ax2.set_ylabel('Training Loss')\n        \nplot_loss_curves(model_history)","metadata":{"execution":{"iopub.status.busy":"2021-08-14T06:41:23.694622Z","iopub.execute_input":"2021-08-14T06:41:23.694981Z","iopub.status.idle":"2021-08-14T06:41:23.968562Z","shell.execute_reply.started":"2021-08-14T06:41:23.694949Z","shell.execute_reply":"2021-08-14T06:41:23.967722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## TO DO:\n* Split to train and validation batches \n* Apply transfer larning \n* Experiment with different class selections and class-weights \n* Submit results\n\n### The updated version will be following soon  ","metadata":{}}]}