{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19233,"databundleVersionId":1322986,"sourceType":"competition"}],"dockerImageVersionId":29963,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from IPython.display import Image\nImage(filename='../input/landmark-retrieval-2020/train/0/0/0/000014b1f770f640.jpg') \n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-02-15T08:18:59.849984Z","iopub.execute_input":"2024-02-15T08:18:59.850291Z","iopub.status.idle":"2024-02-15T08:18:59.871590Z","shell.execute_reply.started":"2024-02-15T08:18:59.850258Z","shell.execute_reply":"2024-02-15T08:18:59.870643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The purpose of this notebook is to illustrate how to create Resnet50 from scratch on Tensorflow 2.x . This kernel just uses top 100 classes. For actual competition we would need to model all classes with neccessary methods to handle class imbalance","metadata":{}},{"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\nimport tensorflow as tf\nimport cv2\nimport skimage.io\nfrom skimage.transform import resize\nfrom imgaug import augmenters as iaa\nfrom sklearn import preprocessing\nfrom sklearn.preprocessing import LabelBinarizer,LabelEncoder\nfrom sklearn.utils.class_weight import compute_class_weight\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers import Input, Add, Dense, Dropout, Activation, ZeroPadding2D, BatchNormalization, Flatten, Conv2D, AveragePooling2D, MaxPooling2D, GlobalMaxPooling2D,GlobalAveragePooling2D,Concatenate, ReLU, LeakyReLU,Reshape, Lambda\nfrom tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler, EarlyStopping, ReduceLROnPlateau\nfrom tensorflow.keras.optimizers import Adam,SGD\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.models import Sequential, load_model, Model\nfrom tensorflow.keras.callbacks import LearningRateScheduler\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.utils import to_categorical\nfrom tensorflow.keras import metrics\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.applications.imagenet_utils import preprocess_input\nfrom tensorflow.keras.initializers import glorot_uniform\nfrom tqdm import tqdm\nimport imgaug as ia\nfrom imgaug import augmenters as iaa\nfrom PIL import Image\nimport keras.backend as K\nK.set_image_data_format('channels_last')\nK.set_learning_phase(1)\n\n\n# You can write up to 5GB 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","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-02-15T08:18:59.877119Z","iopub.execute_input":"2024-02-15T08:18:59.877389Z","iopub.status.idle":"2024-02-15T08:19:01.198838Z","shell.execute_reply.started":"2024-02-15T08:18:59.877363Z","shell.execute_reply":"2024-02-15T08:19:01.197796Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Path retrieval**\n\n\nTaken from the public kernel...thanks for sharing this. It was quite helpful for me. Please upvote that kernel if you also found that helpful\nhttps://www.kaggle.com/derinformatiker/landmark-retrieval-all-paths","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv(\"../input/landmark-retrieval-2020/train.csv\")\ndef get_paths(sub):\n    index = [\"0\",\"1\",\"2\",\"3\",\"4\",\"5\",\"6\",\"7\",\"8\",\"9\",\"a\",\"b\",\"c\",\"d\",\"e\",\"f\"]\n\n    paths = []\n\n    for a in index:\n        for b in index:\n            for c in index:\n                try:\n                    paths.extend([f\"../input/landmark-retrieval-2020/{sub}/{a}/{b}/{c}/\" + x for x in os.listdir(f\"../input/landmark-retrieval-2020/{sub}/{a}/{b}/{c}\")])\n                except:\n                    pass\n\n    return paths","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","execution":{"iopub.status.busy":"2024-02-15T08:19:01.200913Z","iopub.execute_input":"2024-02-15T08:19:01.201301Z","iopub.status.idle":"2024-02-15T08:19:02.657816Z","shell.execute_reply.started":"2024-02-15T08:19:01.201260Z","shell.execute_reply":"2024-02-15T08:19:02.656822Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Thanks and Credits - @nawidsayed for suggesting a change in line number 3 and making it much more efficient. His profile link is given below:   https://www.kaggle.com/nawidsayed","metadata":{}},{"cell_type":"code","source":"\ntrain_path = train\ntrain_path[\"id\"] = train_path.id.map(lambda path: f\"../input/landmark-retrieval-2020/train/{path[0]}/{path[1]}/{path[2]}/{path}.jpg\")","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:02.659212Z","iopub.execute_input":"2024-02-15T08:19:02.659607Z","iopub.status.idle":"2024-02-15T08:19:03.952117Z","shell.execute_reply.started":"2024-02-15T08:19:02.659560Z","shell.execute_reply":"2024-02-15T08:19:03.951362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##Old implementation - changed after suggestion from @nawidsayed\n'''\ntrain_path = train\n\nrows = []\nfor i in tqdm(range(len(train))):\n    row = train.iloc[i]\n    path  = list(row[\"id\"])[:3]\n    temp = row[\"id\"]\n    row[\"id\"] = f\"../input/landmark-retrieval-2020/train/{path[0]}/{path[1]}/{path[2]}/{temp}.jpg\"\n    rows.append(row[\"id\"])\n    \nrows = pd.DataFrame(rows)\ntrain_path[\"id\"] = rows\n'''","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:03.953454Z","iopub.execute_input":"2024-02-15T08:19:03.953849Z","iopub.status.idle":"2024-02-15T08:19:03.959823Z","shell.execute_reply.started":"2024-02-15T08:19:03.953804Z","shell.execute_reply":"2024-02-15T08:19:03.958941Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Setting up some basic model specs**","metadata":{}},{"cell_type":"code","source":"batch_size = 128\nseed = 42\nshape = (64, 64, 3) ##desired shape of the image for resizing purposes\nval_sample = 0.1 # 10 % as validation sample\n","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:03.963323Z","iopub.execute_input":"2024-02-15T08:19:03.963690Z","iopub.status.idle":"2024-02-15T08:19:03.968612Z","shell.execute_reply.started":"2024-02-15T08:19:03.963652Z","shell.execute_reply":"2024-02-15T08:19:03.967777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels = pd.read_csv('../input/landmark-retrieval-2020/train.csv')\ntrain_labels.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:03.971204Z","iopub.execute_input":"2024-02-15T08:19:03.971546Z","iopub.status.idle":"2024-02-15T08:19:04.927195Z","shell.execute_reply.started":"2024-02-15T08:19:03.971518Z","shell.execute_reply":"2024-02-15T08:19:04.926339Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"k =train[['id','landmark_id']].groupby(['landmark_id']).agg({'id':'count'})\nk.rename(columns={'id':'Count_class'}, inplace=True)\nk.reset_index(level=(0), inplace=True)\nfreq_ct_df = pd.DataFrame(k)\nfreq_ct_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:04.928402Z","iopub.execute_input":"2024-02-15T08:19:04.928680Z","iopub.status.idle":"2024-02-15T08:19:05.190834Z","shell.execute_reply.started":"2024-02-15T08:19:04.928651Z","shell.execute_reply":"2024-02-15T08:19:05.189819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_labels = pd.merge(train,freq_ct_df, on = ['landmark_id'], how='left')\ntrain_labels.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.192162Z","iopub.execute_input":"2024-02-15T08:19:05.192561Z","iopub.status.idle":"2024-02-15T08:19:05.403582Z","shell.execute_reply.started":"2024-02-15T08:19:05.192519Z","shell.execute_reply":"2024-02-15T08:19:05.402809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"freq_ct_df.sort_values(by=['Count_class'],ascending=False,inplace=True)\nfreq_ct_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.405117Z","iopub.execute_input":"2024-02-15T08:19:05.405415Z","iopub.status.idle":"2024-02-15T08:19:05.420729Z","shell.execute_reply.started":"2024-02-15T08:19:05.405387Z","shell.execute_reply":"2024-02-15T08:19:05.419894Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Due to Kernel runtime limits, for illustrating the example let's run this for top 100 landmark categories**","metadata":{}},{"cell_type":"code","source":"freq_ct_df_top100 = freq_ct_df.iloc[:100]\ntop100_class = freq_ct_df_top100['landmark_id'].tolist()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.421868Z","iopub.execute_input":"2024-02-15T08:19:05.422135Z","iopub.status.idle":"2024-02-15T08:19:05.428559Z","shell.execute_reply.started":"2024-02-15T08:19:05.422109Z","shell.execute_reply":"2024-02-15T08:19:05.427871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"top100class_train = train_path[train_path['landmark_id'].isin (top100_class) ]\ntop100class_train.shape","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.429919Z","iopub.execute_input":"2024-02-15T08:19:05.430283Z","iopub.status.idle":"2024-02-15T08:19:05.509105Z","shell.execute_reply.started":"2024-02-15T08:19:05.430245Z","shell.execute_reply":"2024-02-15T08:19:05.508088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def getTrainParams():\n    data = top100class_train.copy()\n    le = preprocessing.LabelEncoder()\n    data['label'] = le.fit_transform(data['landmark_id'])\n    lbls = top100class_train['landmark_id'].tolist()\n    lb = LabelBinarizer()\n    labels = lb.fit_transform(lbls)\n    \n    return np.array(top100class_train['id'].tolist()),np.array(labels),le","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.510290Z","iopub.execute_input":"2024-02-15T08:19:05.510575Z","iopub.status.idle":"2024-02-15T08:19:05.516614Z","shell.execute_reply.started":"2024-02-15T08:19:05.510546Z","shell.execute_reply":"2024-02-15T08:19:05.515865Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Credit to Michal Haltuf from whose kernel I had first learnt Data Generators two years back.\nYou can check out his kernel here: https://www.kaggle.com/rejpalcz/cnn-128x128x4-keras-from-scratch-lb-0-328","metadata":{}},{"cell_type":"code","source":"class Landmark2020_DataGenerator(tf.keras.utils.Sequence):\n    def __init__(self, paths, labels, batch_size, shape, shuffle = False, use_cache = False, augment = False):\n        self.paths, self.labels = paths, labels\n        self.batch_size = batch_size\n        self.shape = shape\n        self.shuffle = shuffle\n        self.use_cache = use_cache\n        self.augment = augment\n        if use_cache == True:\n            self.cache = np.zeros((paths.shape[0], shape[0], shape[1], shape[2]), dtype=np.float16)\n            self.is_cached = np.zeros((paths.shape[0]))\n        self.on_epoch_end()\n    \n    def __len__(self):\n        return int(np.ceil(len(self.paths) / float(self.batch_size)))\n    \n    def __getitem__(self, idx):\n        indexes = self.indexes[idx * self.batch_size : (idx+1) * self.batch_size]\n\n        paths = self.paths[indexes]\n        X = np.zeros((paths.shape[0], self.shape[0], self.shape[1], self.shape[2]))\n        # Generate data\n        if self.use_cache == True:\n            X = self.cache[indexes]\n            for i, path in enumerate(paths[np.where(self.is_cached[indexes] == 0)]):\n                image = self.__load_image(path)\n                self.is_cached[indexes[i]] = 1\n                self.cache[indexes[i]] = image\n                X[i] = image\n        else:\n            for i, path in enumerate(paths):\n                X[i] = self.__load_image(path)\n\n        y = self.labels[indexes]\n                \n        if self.augment == True:\n            seq = iaa.Sequential([\n                iaa.OneOf([\n                    iaa.Fliplr(0.5), # horizontal flips\n                    \n                    iaa.ContrastNormalization((0.75, 1.5)),\n                    iaa.AdditiveGaussianNoise(loc=0, scale=(0.0, 0.05*255), per_channel=0.5),\n                    iaa.Multiply((0.8, 1.2), per_channel=0.2),\n                    \n                    iaa.Affine(rotate=0),\n                    #iaa.Affine(rotate=90),\n                    #iaa.Affine(rotate=180),\n                    #iaa.Affine(rotate=270),\n                    iaa.Fliplr(0.5),\n                    #iaa.Flipud(0.5),\n                ])], random_order=True)\n\n            X = np.concatenate((X, seq.augment_images(X), seq.augment_images(X), seq.augment_images(X)), 0)\n            y = np.concatenate((y, y, y, y), 0)\n        \n        return X, y\n    \n    def on_epoch_end(self):\n        \n        # Updates indexes after each epoch\n        self.indexes = np.arange(len(self.paths))\n        if self.shuffle == True:\n            np.random.shuffle(self.indexes)\n\n    def __iter__(self):\n        \"\"\"Create a generator that iterate over the Sequence.\"\"\"\n        for item in (self[i] for i in range(len(self))):\n            yield item\n            \n    def __load_image(self, path):\n        image_norm = skimage.io.imread(path)/255.0\n        \n\n        im = resize(image_norm, (shape[0], shape[1],shape[2]), mode='reflect')\n        return im","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.517913Z","iopub.execute_input":"2024-02-15T08:19:05.518241Z","iopub.status.idle":"2024-02-15T08:19:05.546977Z","shell.execute_reply.started":"2024-02-15T08:19:05.518198Z","shell.execute_reply":"2024-02-15T08:19:05.546098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"nlabls = top100class_train['landmark_id'].nunique()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.548544Z","iopub.execute_input":"2024-02-15T08:19:05.548925Z","iopub.status.idle":"2024-02-15T08:19:05.558164Z","shell.execute_reply.started":"2024-02-15T08:19:05.548882Z","shell.execute_reply":"2024-02-15T08:19:05.557330Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Let's build the building blocks of a Resnet model one by one**\n\n\n\nCredits: Prof. Andrew Ng course on deep learning","metadata":{}},{"cell_type":"markdown","source":"**The complete architecture of a ResNet50 can be shown as follows:**","metadata":{}},{"cell_type":"markdown","source":"![](https://miro.medium.com/max/2792/1*hEU7S-EiVqcmtAlj6kgfRA.png)","metadata":{}},{"cell_type":"markdown","source":"Starting first with the identity block creation","metadata":{}},{"cell_type":"markdown","source":"![](https://i.stack.imgur.com/37qzA.png)","metadata":{}},{"cell_type":"code","source":"def identity_block(X, f, filters, stage, block):\n    \n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n    \n    F1, F2, F3 = filters\n    \n    X_shortcut = X\n        \n    X = Conv2D(filters = F1, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)\n    X = Activation('relu')(X)\n        \n    X = Conv2D(filters = F2, kernel_size = (f, f), strides = (1,1), padding = 'same', name = conv_name_base + '2b', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X)\n    X = Activation('relu')(X)\n\n    X = Conv2D(filters = F3, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2c', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X)\n\n    # Add shortcut value to main path\n    X = Add()([X_shortcut, X])\n    X = Activation('relu')(X)\n        \n    return X","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.559503Z","iopub.execute_input":"2024-02-15T08:19:05.559905Z","iopub.status.idle":"2024-02-15T08:19:05.573026Z","shell.execute_reply.started":"2024-02-15T08:19:05.559867Z","shell.execute_reply":"2024-02-15T08:19:05.572200Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Creating the convolutional block","metadata":{}},{"cell_type":"markdown","source":"![](https://i.stack.imgur.com/0mE2p.png)","metadata":{}},{"cell_type":"code","source":"def convolutional_block(X, f, filters, stage, block, s = 2):\n        \n    conv_name_base = 'res' + str(stage) + block + '_branch'\n    bn_name_base = 'bn' + str(stage) + block + '_branch'\n    F1, F2, F3 = filters\n    X_shortcut = X\n    X = Conv2D(F1, (1, 1), strides = (s,s), name = conv_name_base + '2a', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2a')(X)\n    X = Activation('relu')(X)\n    X = Conv2D(filters = F2, kernel_size = (f, f), strides = (1,1), padding = 'same', name = conv_name_base + '2b', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2b')(X)\n    X = Activation('relu')(X)\n    X = Conv2D(filters = F3, kernel_size = (1, 1), strides = (1,1), padding = 'valid', name = conv_name_base + '2c', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = bn_name_base + '2c')(X)\n    X_shortcut = Conv2D(filters = F3, kernel_size = (1, 1), strides = (s,s), padding = 'valid', name = conv_name_base + '1', kernel_initializer = glorot_uniform(seed=0))(X_shortcut)\n    X_shortcut = BatchNormalization(axis = 3, name = bn_name_base + '1')(X_shortcut)\n    X = Add()([X_shortcut, X])\n    X = Activation('relu')(X)\n   \n    return X","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.574170Z","iopub.execute_input":"2024-02-15T08:19:05.574548Z","iopub.status.idle":"2024-02-15T08:19:05.589872Z","shell.execute_reply.started":"2024-02-15T08:19:05.574511Z","shell.execute_reply":"2024-02-15T08:19:05.589170Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Bringing everything together**\n\nThe architecture we are trying to implement is as follows:\n\nCONV2D -> BATCHNORM -> RELU -> MAXPOOL -> CONVBLOCK -> IDBLOCK*2 -> CONVBLOCK -> IDBLOCK*3\n    -> CONVBLOCK -> IDBLOCK*5 -> CONVBLOCK -> IDBLOCK*2 -> AVGPOOL -> TOPLAYER\n    \n    \nThe detailed architecture of ResNet-50 model is:\n\n* Zero-padding pads the input with a pad of (3,3)\n* Stage 1:\n        The 2D Convolution has 64 filters of shape (7,7) and uses a stride of (2,2). Its name is \"conv1\".\n        BatchNorm is applied to the channels axis of the input.\n        MaxPooling uses a (3,3) window and a (2,2) stride.\n* Stage 2:\n        The convolutional block uses three set of filters of size [64,64,256], \"f\" is 3, \"s\" is 1 and the  block is \"a\".\n        The 2 identity blocks use three set of filters of size [64,64,256], \"f\" is 3 and the blocks are \"b\" and \"c\".\n    Stage 3:\n        The convolutional block uses three set of filters of size [128,128,512], \"f\" is 3, \"s\" is 2 and the block is \"a\".\n        The 3 identity blocks use three set of filters of size [128,128,512], \"f\" is 3 and the blocks are \"b\", \"c\" and \"d\".\n    Stage 4:\n        The convolutional block uses three set of filters of size [256, 256, 1024], \"f\" is 3, \"s\" is 2 and the block is \"a\".\n        The 5 identity blocks use three set of filters of size [256, 256, 1024], \"f\" is 3 and the blocks are \"b\", \"c\", \"d\", \"e\" and \"f\".\n    Stage 5:\n        The convolutional block uses three set of filters of size [512, 512, 2048], \"f\" is 3, \"s\" is 2 and the block is \"a\".\n        The 2 identity blocks use three set of filters of size [512, 512, 2048], \"f\" is 3 and the blocks are \"b\" and \"c\".\n*     The 2D Average Pooling uses a window of shape (2,2) and its name is \"avg_pool\".\n*     The Fully Connected (Dense) layer reduces its input to the number of classes using a softmax activation. ","metadata":{}},{"cell_type":"code","source":"def ResNet50(input_shape = (64, 64, 3), classes = nlabls):\n    X_input = Input(input_shape)\n    X = ZeroPadding2D((3, 3))(X_input)\n    X = Conv2D(64, (7, 7), strides = (2, 2), name = 'conv1', kernel_initializer = glorot_uniform(seed=0))(X)\n    X = BatchNormalization(axis = 3, name = 'bn_conv1')(X)\n    X = Activation('relu')(X)\n    X = MaxPooling2D((3, 3), strides=(2, 2))(X)\n    X = convolutional_block(X, f = 3, filters = [64, 64, 256], stage = 2, block='a', s = 1)\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='b')\n    X = identity_block(X, 3, [64, 64, 256], stage=2, block='c')\n    X = convolutional_block(X, f = 3, filters = [128, 128, 512], stage = 3, block='a', s = 2)\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='b')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='c')\n    X = identity_block(X, 3, [128, 128, 512], stage=3, block='d')\n    X = convolutional_block(X, f = 3, filters = [256, 256, 1024], stage = 4, block='a', s = 2)\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='b')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='c')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='d')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='e')\n    X = identity_block(X, 3, [256, 256, 1024], stage=4, block='f')\n    X = convolutional_block(X, f = 3, filters = [512, 512, 2048], stage = 5, block='a', s = 2)\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='b')\n    X = identity_block(X, 3, [512, 512, 2048], stage=5, block='c')\n    X = AveragePooling2D(pool_size=(2, 2),name='avg_pool')(X)\n    X = Flatten()(X)\n    X = Dense(classes, activation='softmax', name='fc' + str(classes), kernel_initializer = glorot_uniform(seed=0))(X)\n    model = Model(inputs = X_input, outputs = X, name='ResNet50')\n    return model","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.591269Z","iopub.execute_input":"2024-02-15T08:19:05.591558Z","iopub.status.idle":"2024-02-15T08:19:05.616287Z","shell.execute_reply.started":"2024-02-15T08:19:05.591532Z","shell.execute_reply":"2024-02-15T08:19:05.615461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from tensorflow.keras.metrics import categorical_accuracy,top_k_categorical_accuracy\ndef top_5_accuracy(y_true, y_pred):\n    return top_k_categorical_accuracy(y_true, y_pred, k=5)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.617416Z","iopub.execute_input":"2024-02-15T08:19:05.617792Z","iopub.status.idle":"2024-02-15T08:19:05.627331Z","shell.execute_reply.started":"2024-02-15T08:19:05.617751Z","shell.execute_reply":"2024-02-15T08:19:05.626525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = ResNet50(input_shape = (64, 64, 3), classes = nlabls)\nmodel.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['acc',top_5_accuracy])\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:05.628368Z","iopub.execute_input":"2024-02-15T08:19:05.628640Z","iopub.status.idle":"2024-02-15T08:19:10.733945Z","shell.execute_reply.started":"2024-02-15T08:19:05.628613Z","shell.execute_reply":"2024-02-15T08:19:10.732873Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"paths, labels,_ = getTrainParams()","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:10.735472Z","iopub.execute_input":"2024-02-15T08:19:10.735862Z","iopub.status.idle":"2024-02-15T08:19:10.988847Z","shell.execute_reply.started":"2024-02-15T08:19:10.735820Z","shell.execute_reply":"2024-02-15T08:19:10.987838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"keys = np.arange(paths.shape[0], dtype=np.int)  \nnp.random.seed(seed)\nnp.random.shuffle(keys)\nlastTrainIndex = int((1-val_sample) * paths.shape[0])\n\npathsTrain = paths[0:lastTrainIndex]\nlabelsTrain = labels[0:lastTrainIndex]\n\npathsVal = paths[lastTrainIndex:]\nlabelsVal = labels[lastTrainIndex:]\n\nprint(paths.shape, labels.shape)\nprint(pathsTrain.shape, labelsTrain.shape, pathsVal.shape, labelsVal.shape)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:10.990230Z","iopub.execute_input":"2024-02-15T08:19:10.990594Z","iopub.status.idle":"2024-02-15T08:19:11.005066Z","shell.execute_reply.started":"2024-02-15T08:19:10.990556Z","shell.execute_reply":"2024-02-15T08:19:11.003435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_generator = Landmark2020_DataGenerator(pathsTrain, labelsTrain, batch_size, shape, use_cache=False, augment = False, shuffle = True)\nval_generator = Landmark2020_DataGenerator(pathsVal, labelsVal, batch_size, shape, use_cache=False, shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:11.007653Z","iopub.execute_input":"2024-02-15T08:19:11.008125Z","iopub.status.idle":"2024-02-15T08:19:11.017184Z","shell.execute_reply.started":"2024-02-15T08:19:11.008083Z","shell.execute_reply":"2024-02-15T08:19:11.015484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"epochs = 2\nuse_multiprocessing = True \n#workers = 1 ","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:11.019667Z","iopub.execute_input":"2024-02-15T08:19:11.020086Z","iopub.status.idle":"2024-02-15T08:19:11.028467Z","shell.execute_reply.started":"2024-02-15T08:19:11.020040Z","shell.execute_reply":"2024-02-15T08:19:11.026545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"base_cnn = model.fit_generator(\n    train_generator,\n    steps_per_epoch=len(train_generator),\n    validation_data=val_generator,\n    validation_steps=64,\n    #class_weight = class_weights,\n    epochs=epochs,\n    \n    #callbacks = [clr],\n    use_multiprocessing=use_multiprocessing,\n    #workers=workers,\n    verbose=1)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T08:19:11.030462Z","iopub.execute_input":"2024-02-15T08:19:11.031121Z","iopub.status.idle":"2024-02-15T11:29:04.413659Z","shell.execute_reply.started":"2024-02-15T08:19:11.031081Z","shell.execute_reply":"2024-02-15T11:29:04.412183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.save('ResNet50.h5')","metadata":{"execution":{"iopub.status.busy":"2024-02-15T11:29:04.416341Z","iopub.execute_input":"2024-02-15T11:29:04.416796Z","iopub.status.idle":"2024-02-15T11:29:05.625665Z","shell.execute_reply.started":"2024-02-15T11:29:04.416743Z","shell.execute_reply":"2024-02-15T11:29:05.624814Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**If you found this useful, an upvote would be much appreciated.**","metadata":{}},{"cell_type":"code","source":"def evaluate_accuracy(model, val_generator):\n    # Evaluate the model on the validation data\n    evaluation = model.evaluate_generator(val_generator, verbose=1)\n    \n    # Extracting accuracy metrics\n    loss = evaluation[0]\n    accuracy = evaluation[1]\n    top_5_accuracy = evaluation[2]\n    \n    print(\"Validation Loss:\", loss)\n    print(\"Validation Accuracy:\", accuracy)\n    print(\"Top-5 Validation Accuracy:\", top_5_accuracy)\n    \n    return loss, accuracy, top_5_accuracy\n\n# Usage\nloss, accuracy, top_5_accuracy = evaluate_accuracy(model, val_generator)\n","metadata":{"execution":{"iopub.status.busy":"2024-02-15T11:29:05.627051Z","iopub.execute_input":"2024-02-15T11:29:05.627363Z","iopub.status.idle":"2024-02-15T11:37:42.543879Z","shell.execute_reply.started":"2024-02-15T11:29:05.627332Z","shell.execute_reply":"2024-02-15T11:37:42.543033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculate_accuracy(model, generator):\n    # Evaluate the model on the generator\n    evaluation = model.evaluate(generator)\n    \n    # Extract loss and accuracy from evaluation results\n    loss = evaluation[0]\n    accuracy = evaluation[1]\n    \n    # Print the accuracy\n    print(\"Loss: {:.4f}, Accuracy: {:.4f}\".format(loss, accuracy))\n    \n    return accuracy\n\ndef calculate_top_5_accuracy(model, generator):\n    # Generate predictions using the model\n    predictions = model.predict(generator)\n    \n    # Extract labels from the generator\n    labels = generator.labels\n    \n    # Calculate top-5 accuracy\n    top_5_acc = top_5_accuracy(labels, predictions).numpy().mean()\n    \n    # Print the top-5 accuracy\n    print(\"Top-5 Accuracy: {:.4f}\".format(top_5_acc))\n    \n    return top_5_acc\n\n# Calculate accuracy on the training set\ntrain_accuracy = calculate_accuracy(model, train_generator)\ntrain_top_5_accuracy = calculate_top_5_accuracy(model, train_generator)\n\n# Calculate accuracy on the validation set\nval_accuracy = calculate_accuracy(model, val_generator)\nval_top_5_accuracy = calculate_top_5_accuracy(model, val_generator)","metadata":{"execution":{"iopub.status.busy":"2024-02-15T17:04:02.623276Z","iopub.execute_input":"2024-02-15T17:04:02.623636Z","iopub.status.idle":"2024-02-15T17:04:02.770745Z","shell.execute_reply.started":"2024-02-15T17:04:02.623601Z","shell.execute_reply":"2024-02-15T17:04:02.769662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**Image Credits:**\n\n[Stackoverflow](https://stackoverflow.com/questions/58200107/stuck-understanding-resnets-identity-block-and-convolutional-blocks)\n\n\n[Medium](https://miro.medium.com/max/2792/1*hEU7S-EiVqcmtAlj6kgfRA.png)","metadata":{}}]}