{"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":"\n# Google Landmark Recognition 2021 ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-08-12T21:06:05.862261Z","iopub.execute_input":"2021-08-12T21:06:05.862712Z","iopub.status.idle":"2021-08-12T21:06:05.869081Z","shell.execute_reply.started":"2021-08-12T21:06:05.862673Z","shell.execute_reply":"2021-08-12T21:06:05.867781Z"}}},{"cell_type":"markdown","source":"## Importing Library¶\n","metadata":{}},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image \nimport matplotlib.image as mpimg\nimport os\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Dense, Flatten, Conv2D, MaxPooling2D\nfrom tensorflow.keras.optimizers import Adam\nimport numpy as np\nfrom tensorflow.keras.layers import Input, Conv2D,Dropout\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom IPython.display import clear_output\nimport random, re, math\nimport pandas as pd \nimport keras.backend as K\nfrom sklearn.model_selection import train_test_split\n","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:02.171969Z","iopub.execute_input":"2021-08-14T21:42:02.172259Z","iopub.status.idle":"2021-08-14T21:42:02.179929Z","shell.execute_reply.started":"2021-08-14T21:42:02.172232Z","shell.execute_reply":"2021-08-14T21:42:02.179214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Making a dataframe of label_train\n","metadata":{}},{"cell_type":"code","source":"df=pd.read_csv('../input/landmark-recognition-2021/train.csv')\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:06.767765Z","iopub.execute_input":"2021-08-14T21:42:06.768474Z","iopub.status.idle":"2021-08-14T21:42:08.618759Z","shell.execute_reply.started":"2021-08-14T21:42:06.768412Z","shell.execute_reply":"2021-08-14T21:42:08.617716Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Adding path_columns from train images pathes","metadata":{}},{"cell_type":"markdown","source":"### ***By adding path to our dataframe we can use this dataframe in Tensorflow directly!***","metadata":{}},{"cell_type":"code","source":"%%time\ndf['path']=['../input/landmark-recognition-2021/train/'+id[0]+'/'+id[1]+'/'+id[2]+'/'+id+'.jpg' for id in df['id']]\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:10.758598Z","iopub.execute_input":"2021-08-14T21:42:10.759208Z","iopub.status.idle":"2021-08-14T21:42:12.423788Z","shell.execute_reply.started":"2021-08-14T21:42:10.759158Z","shell.execute_reply":"2021-08-14T21:42:12.422672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Label types and null values check¶","metadata":{}},{"cell_type":"code","source":"df.info()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:13.849408Z","iopub.execute_input":"2021-08-14T21:42:13.849851Z","iopub.status.idle":"2021-08-14T21:42:14.190447Z","shell.execute_reply.started":"2021-08-14T21:42:13.849811Z","shell.execute_reply":"2021-08-14T21:42:14.189293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## label number check","metadata":{}},{"cell_type":"code","source":"df['landmark_id'].nunique()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:15.019981Z","iopub.execute_input":"2021-08-14T21:42:15.020499Z","iopub.status.idle":"2021-08-14T21:42:15.074560Z","shell.execute_reply.started":"2021-08-14T21:42:15.020465Z","shell.execute_reply":"2021-08-14T21:42:15.073183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['landmark_id'].value_counts()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:15.274788Z","iopub.execute_input":"2021-08-14T21:42:15.275197Z","iopub.status.idle":"2021-08-14T21:42:15.322995Z","shell.execute_reply.started":"2021-08-14T21:42:15.275163Z","shell.execute_reply":"2021-08-14T21:42:15.322002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['landmark_id'].describe()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:16.062707Z","iopub.execute_input":"2021-08-14T21:42:16.063084Z","iopub.status.idle":"2021-08-14T21:42:16.109519Z","shell.execute_reply.started":"2021-08-14T21:42:16.063049Z","shell.execute_reply":"2021-08-14T21:42:16.108278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Encoding the landmark_id","metadata":{}},{"cell_type":"code","source":"\ndf['id_counts'] = df.landmark_id.value_counts().loc[df.landmark_id.values].values\nid_map = df.sort_values(by='id_counts').landmark_id.drop_duplicates().reset_index(drop=True)\nid_dict = {id_map.loc[x]:81312-x for x in range(81313)}\ndf['encode_id'] = df.landmark_id.apply(lambda x: id_dict[x])\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:29.581890Z","iopub.execute_input":"2021-08-14T21:42:29.582232Z","iopub.status.idle":"2021-08-14T21:42:33.133788Z","shell.execute_reply.started":"2021-08-14T21:42:29.582203Z","shell.execute_reply":"2021-08-14T21:42:33.132790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['landmark_id'].describe()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:37.372475Z","iopub.execute_input":"2021-08-14T21:42:37.373263Z","iopub.status.idle":"2021-08-14T21:42:37.424351Z","shell.execute_reply.started":"2021-08-14T21:42:37.373196Z","shell.execute_reply":"2021-08-14T21:42:37.423262Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['encode_id'].describe()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:38.048411Z","iopub.execute_input":"2021-08-14T21:42:38.049098Z","iopub.status.idle":"2021-08-14T21:42:38.093472Z","shell.execute_reply.started":"2021-08-14T21:42:38.049045Z","shell.execute_reply":"2021-08-14T21:42:38.092406Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Let's take a look at some image examples and their correponding Landmark_id","metadata":{}},{"cell_type":"code","source":"plt.subplots(3, 4, figsize=(160, 120))\nfor i in range(12):\n    sp = plt.subplot(3, 4, i + 1)\n    sp.axis('Off')\n    im = mpimg.imread(df.iloc[i][2])\n    plt.imshow(im)\n    plt.title(f'landmark_id:{df.iloc[i][1]} ', \n                                     fontweight =\"bold\",fontsize=100)\n    ","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:42:39.638438Z","iopub.execute_input":"2021-08-14T21:42:39.638870Z","iopub.status.idle":"2021-08-14T21:43:02.097677Z","shell.execute_reply.started":"2021-08-14T21:42:39.638832Z","shell.execute_reply":"2021-08-14T21:43:02.094735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Configuration","metadata":{}},{"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\n\n# Configuration\nIMAGE_SIZE = [256, 256]\nEPOCHS = 40\nSEED = 24\nBATCH_SIZE = 32 ","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:02.099519Z","iopub.execute_input":"2021-08-14T21:43:02.099877Z","iopub.status.idle":"2021-08-14T21:43:02.108092Z","shell.execute_reply.started":"2021-08-14T21:43:02.099844Z","shell.execute_reply":"2021-08-14T21:43:02.105154Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def flip(image,label):\n    \n    image = tf.image.flip_left_right(image)\n    \n    return image,label\n\n\n\ndef rotate(image,label):\n\n    rot = 15. * tf.random.normal([1],dtype='float32')\n    rotation = math.pi * rot / 180.\n    c1 = tf.math.cos(rotation)\n    s1 = tf.math.sin(rotation)\n    one = tf.constant([1],dtype='float32')\n    zero = tf.constant([0],dtype='float32')\n    m = tf.reshape( tf.concat([c1,s1,zero, -s1,c1,zero, zero,zero,one],axis=0),[3,3] )\n    DIM = IMAGE_SIZE[0]\n    XDIM = DIM%2 \n    x = tf.repeat( tf.range(DIM//2,-DIM//2,-1), DIM )\n    y = tf.tile( tf.range(-DIM//2,DIM//2),[DIM] )\n    z = tf.ones([DIM*DIM],dtype='int32')\n    idx = tf.stack( [x,y,z] )\n    idx2 = K.dot(m,tf.cast(idx,dtype='float32'))\n    idx2 = K.cast(idx2,dtype='int32')\n    idx2 = K.clip(idx2,-DIM//2+XDIM+1,DIM//2)\n    idx3 = tf.stack( [DIM//2-idx2[0,], DIM//2-1+idx2[1,]] )\n    d = tf.gather_nd(image,tf.transpose(idx3))\n    img=tf.reshape(d,[DIM,DIM,3])\n    return img,label\n#tf.cast(np.array(img), dtype=tf.float32)\n\n\n\ndef read_image_and_label(image_path, label=None,resize=IMAGE_SIZE):\n    \n    image=tf.io.read_file(image_path)\n    image=tf.image.decode_jpeg(image, channels=3)\n    image=tf.image.resize(image, IMAGE_SIZE)\n    image = tf.cast(image, dtype=tf.float32)/255.\n    if not label is None:\n        return image, label\n    return image\n\n\n\n\ndef get_training_dataset(df):\n    \n    training_dataset = tf.data.Dataset.from_tensor_slices((df[\"path\"].values, df[\"encode_id\"].values))\n    training_dataset = training_dataset.map(read_image_and_label,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.map(flip,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.map(rotate,num_parallel_calls=AUTO)\n    training_dataset = training_dataset.shuffle(1000, reshuffle_each_iteration=True)\n    training_dataset = training_dataset.batch(BATCH_SIZE)\n    training_dataset = training_dataset.prefetch(AUTO)\n\n    return training_dataset\n\n\ndef get_validation_dataset(df,batch_size=16):\n  \n  validation_dataset = tf.data.Dataset.from_tensor_slices((df[\"path\"].values, df[\"encode_id\"].values))\n  validation_dataset = validation_dataset.map(read_image_and_label)\n  validation_dataset = validation_dataset.batch(BATCH_SIZE)\n  \n\n  return validation_dataset\n\n\ndef get_test_dataset(images,batch_size=16):\n  \n  test_dataset = tf.data.Dataset.from_tensor_slices((images))\n  test_dataset = test_dataset.map(read_image_and_label)\n  test_dataset = test_dataset.batch(batch_size, drop_remainder=True)\n\n  return test_dataset","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:02.110663Z","iopub.execute_input":"2021-08-14T21:43:02.111244Z","iopub.status.idle":"2021-08-14T21:43:02.141803Z","shell.execute_reply.started":"2021-08-14T21:43:02.111196Z","shell.execute_reply":"2021-08-14T21:43:02.140106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"tr_dataset = get_training_dataset(train_test_split(df, random_state=SEED, test_size=.25)[0])\nval_dataset = get_validation_dataset(train_test_split(df, random_state=SEED, test_size=.25)[1])","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:02.144122Z","iopub.execute_input":"2021-08-14T21:43:02.145070Z","iopub.status.idle":"2021-08-14T21:43:05.258706Z","shell.execute_reply.started":"2021-08-14T21:43:02.145018Z","shell.execute_reply":"2021-08-14T21:43:05.257707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Display Example Augmentation¶¶\n","metadata":{}},{"cell_type":"code","source":"row = 2; col = 4;\nall_elements = tr_dataset.unbatch()\none_element = tf.data.Dataset.from_tensors( next(iter(all_elements)) )\naugmented_element = one_element.repeat().map(rotate).batch(row*col)\n\nfor (img,label) in augmented_element:\n    plt.figure(figsize=(15,int(15*row/col)))\n    for j in range(row*col):\n        plt.subplot(row,col,j+1)\n        plt.axis('off')\n        plt.imshow(img[j,])\n        \n    plt.show()\n    break","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:05.259944Z","iopub.execute_input":"2021-08-14T21:43:05.260241Z","iopub.status.idle":"2021-08-14T21:43:10.475411Z","shell.execute_reply.started":"2021-08-14T21:43:05.260211Z","shell.execute_reply":"2021-08-14T21:43:10.474055Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Build a model","metadata":{}},{"cell_type":"markdown","source":"### Since we have a large dataset,a complex model works better than a simple one but as we will have a long runtime I used a simple model with just 2 epochs in this notebook!","metadata":{}},{"cell_type":"code","source":"from tensorflow import keras\nfrom tensorflow.keras import layers\nfrom tensorflow.keras.layers.experimental import preprocessing\n\n\ndef conv_block(filters, inputs):\n    x = layers.SeparableConv2D(filters, 3, activation=\"relu\", padding=\"same\")(inputs)\n    x = layers.SeparableConv2D(filters, 3, activation=\"relu\", padding=\"same\")(x)\n    x = layers.BatchNormalization()(x)\n    outputs = layers.MaxPool2D()(x)\n\n    return outputs\n\n\ndef dense_block(units, dropout_rate, inputs):\n    x = layers.Dense(units, activation=\"relu\")(inputs)\n    x = layers.BatchNormalization()(x)\n    outputs = layers.Dropout(dropout_rate)(x)\n\n    return outputs","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:16.163735Z","iopub.execute_input":"2021-08-14T21:43:16.164161Z","iopub.status.idle":"2021-08-14T21:43:16.172990Z","shell.execute_reply.started":"2021-08-14T21:43:16.164125Z","shell.execute_reply":"2021-08-14T21:43:16.171700Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def build_model():\n    inputs = keras.Input(shape=(IMAGE_SIZE[0], IMAGE_SIZE[1], 3))\n    x = layers.Conv2D(16, 3, activation=\"relu\", padding=\"same\")(inputs)\n    x = layers.Conv2D(16, 3, activation=\"relu\", padding=\"same\")(x)\n    x = layers.MaxPool2D()(x)\n\n    x = conv_block(32, x)\n    x = conv_block(64, x)\n\n    x = conv_block(128, x)\n    x = layers.Dropout(0.2)(x)\n\n    x = conv_block(256, x)\n    x = layers.Dropout(0.2)(x)\n\n    x = layers.Flatten()(x)\n    x = dense_block(512, 0.7, x)\n    x = dense_block(128, 0.5, x)\n    x = dense_block(64, 0.3, x)\n\n    outputs = layers.Dense(81313, activation=\"softmax\")(x)\n\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:17.358927Z","iopub.execute_input":"2021-08-14T21:43:17.359311Z","iopub.status.idle":"2021-08-14T21:43:17.369504Z","shell.execute_reply.started":"2021-08-14T21:43:17.359274Z","shell.execute_reply":"2021-08-14T21:43:17.368243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nmodel = build_model()\nmodel.summary()","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:43:19.161642Z","iopub.execute_input":"2021-08-14T21:43:19.162069Z","iopub.status.idle":"2021-08-14T21:43:19.549464Z","shell.execute_reply.started":"2021-08-14T21:43:19.162030Z","shell.execute_reply":"2021-08-14T21:43:19.548411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model training","metadata":{}},{"cell_type":"code","source":"\n# Compile Model. \nmodel.compile(\n    optimizer='adam',\n    loss='sparse_categorical_crossentropy',\n    metrics=['acc']\n)\n\n# Train the Model\n#history = model.fit_generator( tr_dataset, epochs=2,validation_data=val_dataset)\n\n","metadata":{"execution":{"iopub.status.busy":"2021-08-14T21:44:18.213477Z","iopub.execute_input":"2021-08-14T21:44:18.213883Z","iopub.status.idle":"2021-08-14T21:44:18.235443Z","shell.execute_reply.started":"2021-08-14T21:44:18.213851Z","shell.execute_reply":"2021-08-14T21:44:18.234040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}