{"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":"# Model Starter + Tensorflow + GEM Pool + MixedPrec\n\n- Epochs: 10\n- Learning rate: 0.0001\n- Batch Size: 16\n- Activation Function on hidden layers: Linear\n- Hidden layers: 1\n- Batch norm? - yes\n- No image crop\n- Images resized size: 320x320","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf # This is how we import tf\nimport os","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:15.247070Z","iopub.execute_input":"2021-10-16T17:30:15.247434Z","iopub.status.idle":"2021-10-16T17:30:19.782896Z","shell.execute_reply.started":"2021-10-16T17:30:15.247337Z","shell.execute_reply":"2021-10-16T17:30:19.782143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 0. Libraries\n\nimport pandas as pd\nimport numpy as np\nimport os\n\nfrom tqdm import tqdm\n\nimport tensorflow as tf\nimport matplotlib.pyplot as plt\n\nfrom tensorflow.keras import models, layers, regularizers, metrics, losses, optimizers, constraints\nfrom tensorflow.keras import mixed_precision\nfrom tensorflow.keras.utils import Sequence\n\nfrom sklearn.model_selection import train_test_split\n\nnp.random.seed(12)\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:19.784526Z","iopub.execute_input":"2021-10-16T17:30:19.784761Z","iopub.status.idle":"2021-10-16T17:30:20.347770Z","shell.execute_reply.started":"2021-10-16T17:30:19.784730Z","shell.execute_reply":"2021-10-16T17:30:20.347061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 1. Global Variables & Paths\n\nPATH = '../input/landmark-recognition-2021/'\nPATH_MODELS = './03_Models/'\n\n\n#df_train = pd.read_csv(PATH + 'train.csv')\ndf_train = pd.read_csv('../input/landmark-recognition-subset/landmarkSubset_train.csv')\ndf_train['path'] = df_train['id'].apply(lambda x: PATH +  'train/' + '/'.join([c for c in x[:3]]) + '/' + x + '.jpg')\n\n# Missing labels between 0-num_classes causes NAN for sparse_categorical_crossentropy.\ndict_map_landmark = {l : i for i, l in enumerate(df_train.landmark_id.unique())}\ndict_map_landmark_inv = {i : l for i, l in enumerate(df_train.landmark_id.unique())}\ndf_train['landmark_id_mapped'] = df_train['landmark_id'].map(dict_map_landmark)\n\nIMG_SIZE = (320, 320, 3)\n#IMG_SIZE_CROP = (280, 280, 3)\n\nif not os.path.exists(PATH_MODELS):\n    os.mkdir(PATH_MODELS)\n    \n# Get test paths\n'''\ntest_filenames=[]\nfor dirname, _, filenames in tqdm(os.walk(PATH + 'test')):\n    for filename in filenames:\n        print(\"filename\")\n        print(filename)\n        test_filenames.append(filename.split(\".\")[0])\n'''        \ndf_test_gt = pd.read_csv('../input/landmark-recognition-subset/landmarkSubset_test.csv')\n#df_test = pd.DataFrame({\"id\": test_filenames,\"landmarks\":\"\"})\ndf_test = pd.DataFrame({\"id\": df_test_gt['id'],\"landmarks\":\"\"})\nprint(df_test)\n#df_test['path'] = df_test['id'].apply(lambda x: PATH +  'test/' + '/'.join([c for c in x[:3]]) + '/' + x + '.jpg')\ndf_test['path'] = df_test_gt['id'].apply(lambda x: PATH +  'train/' + '/'.join([c for c in x[:3]]) + '/' + x + '.jpg')\nprint(df_test['path'])\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:20.349082Z","iopub.execute_input":"2021-10-16T17:30:20.349336Z","iopub.status.idle":"2021-10-16T17:30:20.425040Z","shell.execute_reply.started":"2021-10-16T17:30:20.349304Z","shell.execute_reply":"2021-10-16T17:30:20.424239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 2. Aux functions\n\ndef plot_examples_train(landmark_id=1):\n    fig, axs = plt.subplots(1, 5, figsize=(26, 12))\n    fig.subplots_adjust(hspace = .2, wspace=.2)\n    axs = axs.ravel()\n    len_ = len(df_train[df_train['landmark_id']==landmark_id])\n    for i in range(5):\n        if i>=len_:\n            break\n        idx = df_train[df_train['landmark_id']==landmark_id].index[i]\n        path_ = df_train.loc[idx, 'path']\n        file_bytes = tf.io.read_file(path_)\n        img = tf.image.decode_jpeg(file_bytes, channels=3)\n        img = tf.image.resize(img, size=(IMG_SIZE[0], IMG_SIZE[1]))\n        axs[i].imshow(img / 255.)\n        #axs[i].set_title('landmark_id: '+str(landmark_id) + str(i) + '/' + str(len_))\n        axs[i].set_title('landmark_id: '+str(landmark_id) + \"\\n\" + 'img name:' + str(path_.split('/')[7]))\n        axs[i].set_xticklabels([])\n        axs[i].set_yticklabels([])\n        \ndef plot_img_path(path, figsize=(6, 6)):\n    file_bytes = tf.io.read_file(path)\n    img = tf.image.decode_jpeg(file_bytes, channels=3)\n    img = tf.image.resize(img, size=(IMG_SIZE[0], IMG_SIZE[1]))\n    plt.figure(figsize=figsize)\n    plt.title('Path: '+path)\n    plt.imshow(img / 255.)\n    plt.show()\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:20.427309Z","iopub.execute_input":"2021-10-16T17:30:20.427585Z","iopub.status.idle":"2021-10-16T17:30:20.438526Z","shell.execute_reply.started":"2021-10-16T17:30:20.427552Z","shell.execute_reply":"2021-10-16T17:30:20.437783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 3. Some plots\n\n# Train\n\nunique_landmarks_train = df_train.landmark_id.unique()\n\nlandmark_ = np.random.choice(unique_landmarks_train, 1)[0]\nplot_examples_train(landmark_)\n\nlandmark_ = np.random.choice(unique_landmarks_train, 1)[0]\nplot_examples_train(landmark_)\n\nlandmark_ = np.random.choice(unique_landmarks_train, 1)[0]\nplot_examples_train(landmark_)\n\n# Test\n\nunique_paths_test = df_test.path.unique()\npath_test = np.random.choice(unique_paths_test, 1)[0]\nplot_img_path(path_test)\n\npath_test = np.random.choice(unique_paths_test, 1)[0]\nplot_img_path(path_test)\n\npath_test = np.random.choice(unique_paths_test, 1)[0]\nplot_img_path(path_test)\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:20.439928Z","iopub.execute_input":"2021-10-16T17:30:20.440604Z","iopub.status.idle":"2021-10-16T17:30:26.034641Z","shell.execute_reply.started":"2021-10-16T17:30:20.440436Z","shell.execute_reply":"2021-10-16T17:30:26.034033Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 4. DataLoader\n\n\ndef buildLoader(labels=True):\n    def decode(path):\n        file_bytes = tf.io.read_file(path)\n        img = tf.image.decode_jpeg(file_bytes, channels=3)\n        img = tf.cast(img, tf.float32) / 255.\n        return img\n    \n    def decodeWithLabels(path, label):\n        img = decode(path)\n        return img, label\n    \n    if labels:\n        return decodeWithLabels\n    else:\n        return decode\n\n\ndef preprocessImage(img, label):\n    img = tf.image.resize(img, size=(IMG_SIZE[0], IMG_SIZE[1]))\n    #img = tf.image.random_crop(img, size=(IMG_SIZE_CROP[0], IMG_SIZE_CROP[1], 3))\n    label = tf.expand_dims(label, -1)\n    img = tf.cast(img, tf.float32)\n    label = tf.cast(label, tf.int32)\n    return img, label\n\n\ndef set_shapes(img, label):\n    #img.set_shape(IMG_SIZE_CROP)\n    img.set_shape(IMG_SIZE)\n    if label is not None:\n        label.set_shape([1])\n    return img, label\n\n\ndef buildAugmentations():\n    def applyAugmentations(image, label):\n        image = tf.image.random_flip_left_right(image)\n        image = tf.image.random_flip_up_down(image)\n        return image, label\n    return applyAugmentations\n\n\ndef build_dataset(paths, labels=None, bsize=32, shuffle=True, augmentations=True):\n    aug_builder = buildAugmentations()\n    loader = buildLoader(False if labels is None else True) \n    AUTO = tf.data.AUTOTUNE\n    slices = (paths, labels)\n    \n    dset = tf.data.Dataset.from_tensor_slices(slices)\n    if shuffle:\n        dset = dset.shuffle(len(labels))\n        \n    dset = dset.map(loader, num_parallel_calls=AUTO).prefetch(AUTO)\n    dset = dset.map(preprocessImage, num_parallel_calls=AUTO)\n    if augmentations:\n        dset = dset.map(aug_builder, num_parallel_calls=AUTO)\n    dset = dset.map(set_shapes, num_parallel_calls=AUTO)\n    dset = dset.batch(bsize, drop_remainder=True).prefetch(AUTO)\n    return dset   \n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:26.036112Z","iopub.execute_input":"2021-10-16T17:30:26.036735Z","iopub.status.idle":"2021-10-16T17:30:26.050801Z","shell.execute_reply.started":"2021-10-16T17:30:26.036697Z","shell.execute_reply":"2021-10-16T17:30:26.049946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_tmp = df_train.sample(100)\n\nlist_paths = list(df_tmp['path'])\nlist_labels =list(df_tmp['landmark_id_mapped'])\ndataset_train = build_dataset(list_paths, labels=list_labels, bsize=64, shuffle=False)\nfor batch in tqdm(dataset_train):\n    data, target = batch\n    break\n\ndata, target = batch\n\nidx = 0\nprint(data.shape, target.shape)\nprint(target[idx])\nplt.title(f\"TARGET: {target[idx].numpy()}\", fontsize=16)\nplt.imshow(data[idx]);plt.show();\n\nidx = 12\nprint(data.shape, target.shape)\nprint(target[idx])\nplt.title(f\"TARGET: {target[idx].numpy()}\", fontsize=16)\nplt.imshow(data[idx]);plt.show();\n\nidx = 25\nprint(data.shape, target.shape)\nprint(target[idx])\nplt.title(f\"TARGET: {target[idx].numpy()}\", fontsize=16)\nplt.imshow(data[idx]);plt.show();","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:26.052134Z","iopub.execute_input":"2021-10-16T17:30:26.052684Z","iopub.status.idle":"2021-10-16T17:30:27.965252Z","shell.execute_reply.started":"2021-10-16T17:30:26.052648Z","shell.execute_reply":"2021-10-16T17:30:27.962169Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 5. Model\n\nclass GeMPoolingLayer(tf.keras.layers.Layer):\n    def __init__(self, p=1., train_p=False, mixed_prec=True):\n        super().__init__()\n        if train_p:\n            if mixed_prec:\n                self.p = tf.Variable(p, dtype=tf.float16)\n            else:\n                self.p = tf.Variable(p, dtype=tf.float32)\n        else:\n            self.p = p\n        self.eps = 1e-7\n\n    def call(self, inputs: tf.Tensor, **kwargs):\n        inputs = tf.clip_by_value(inputs, clip_value_min=self.eps, clip_value_max=tf.reduce_max(inputs))\n        inputs = tf.pow(inputs, self.p)\n        inputs = tf.reduce_mean(inputs, axis=[1, 2], keepdims=False)\n        inputs = tf.pow(inputs, 1./self.p)\n        return inputs\n\n    \nclass Model(models.Model):\n    def __init__(self, num_classes, mixed_prec=True):\n        super(Model, self).__init__()\n        #self.backbone_model = tf.keras.applications.InceptionV3(input_shape=(IMG_SIZE_CROP[0], IMG_SIZE_CROP[1], 3),include_top=False, weights='imagenet')\n        self.backbone_model = tf.keras.applications.InceptionV3(input_shape=(IMG_SIZE[0], IMG_SIZE[1], 3),\n                                                                include_top=False, weights='imagenet')\n        self.backbone_model.trainable = True\n        self.gem_pool = GeMPoolingLayer(mixed_prec)\n        self.fc_linear = layers.Dense(512, activation='linear')\n        self.fc_bn = layers.BatchNormalization()\n        \n        self.dense_out = layers.Dense(num_classes, activation='linear')\n        self.dense_mp = layers.Activation('softmax', dtype='float32')\n        \n    def call(self, img_input, training):\n        x = self.backbone_model(img_input, training)\n        x = self.gem_pool(x)\n        x = self.fc_linear(x)\n        x = self.fc_bn(x)\n        x = tf.nn.relu(x)\n        \n        logits = self.dense_mp(self.dense_out(x))\n        return logits\n    \n    \ndef getModel(num_classes, mixed_prec):\n    return Model(num_classes, mixed_prec)\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:27.966607Z","iopub.execute_input":"2021-10-16T17:30:27.966872Z","iopub.status.idle":"2021-10-16T17:30:27.981998Z","shell.execute_reply.started":"2021-10-16T17:30:27.966838Z","shell.execute_reply":"2021-10-16T17:30:27.981168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 6. Training\n\ntf.keras.backend.clear_session()\npolicy = mixed_precision.Policy('mixed_float16')\nmixed_precision.set_global_policy(policy)\n\nbatch_size = 16\nepochs = 10\nmodel_base_name = 'model_v0.1'\nnum_classes = len(df_train['landmark_id'].unique())\n    \ntup_splitted = train_test_split(df_train['path'].values, df_train['landmark_id_mapped'].values, \n                                                    test_size=0.3, random_state=12, stratify=df_train['landmark_id_mapped'].values)\n\nlist_paths_train, list_paths_val, list_labels_train, list_labels_val = tup_splitted\n\nprint(f'Num paths train: {len(list_paths_train)}, Num paths val: {len(list_paths_val)}')\n\ntrain_data_generator = build_dataset(list_paths_train, labels=list_labels_train, bsize=batch_size, augmentations=True, shuffle=True)\nval_data_generator = build_dataset(list_paths_val, labels=list_labels_val, bsize=batch_size, augmentations=False, shuffle=False)\n\n# Model\nmodel = getModel(num_classes, mixed_prec=True)\n\nlearning_rate = 1e-4\nmodel.compile(optimizer=mixed_precision.LossScaleOptimizer(optimizers.Adam(learning_rate)),\n              loss=losses.SparseCategoricalCrossentropy(from_logits=False),\n              metrics=[metrics.SparseCategoricalAccuracy(name='acc'), \n                       metrics.SparseTopKCategoricalAccuracy(k=5, name='acc_top5')])\n\nhistory = model.fit(train_data_generator,\n                    validation_data=val_data_generator,\n                    batch_size=batch_size,\n                    epochs=epochs,\n                    verbose=1)\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 acc', 'val acc'], 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 loss', 'val loss'], loc='upper left')\nplt.show()                                                                                       \n\nif not os.path.exists(PATH_MODELS + model_base_name):\n    os.mkdir(PATH_MODELS + model_base_name)\n\nmodel.save(f'{PATH_MODELS + model_base_name}/{model_base_name}', include_optimizer=False)\nmodel.save_weights(f'{PATH_MODELS + model_base_name}/{model_base_name}_weights', save_format='tf')\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:30:27.983454Z","iopub.execute_input":"2021-10-16T17:30:27.983777Z","iopub.status.idle":"2021-10-16T17:39:21.327954Z","shell.execute_reply.started":"2021-10-16T17:30:27.983739Z","shell.execute_reply":"2021-10-16T17:39:21.327148Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#################################################################\n# 3. Inference and submission\n\nbsize = 1\nmodel_load_name = 'model_v0.1'\nmodel = models.load_model(PATH_MODELS + model_load_name + '/' + model_load_name)\n\nlist_paths_test = list(df_test['path'].values) \ntest_data_generator = build_dataset(list_paths_test, labels=np.zeros(len(list_paths_test)), bsize=bsize, augmentations=False, shuffle=False)\n\nlist_id, list_pred = [], []\nfor index, batch in enumerate(tqdm(test_data_generator)):\n    y_pred = model(batch[0], training=False).numpy()\n    pred_landmark = np.argmax(y_pred, 1) \n    score_landmark = [y_pred[i, pred_landmark[i]].round(2) for i in range(y_pred.shape[0])]\n    category = [dict_map_landmark_inv[x] for x in pred_landmark]\n    for i in range(y_pred.shape[0]):\n        df_test.loc[index+i, 'landmarks'] = str(category[i]) + ' ' + str(score_landmark[i])\n\ndf_test[['id', 'landmarks']].to_csv('./submission.csv', index=False)\n\n#################################################################","metadata":{"execution":{"iopub.status.busy":"2021-10-16T17:39:21.330826Z","iopub.execute_input":"2021-10-16T17:39:21.331095Z","iopub.status.idle":"2021-10-16T17:40:12.799892Z","shell.execute_reply.started":"2021-10-16T17:39:21.331061Z","shell.execute_reply":"2021-10-16T17:40:12.798687Z"},"trusted":true},"execution_count":null,"outputs":[]}]}