{"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":"# Hotel Recognition to Combat Human Trafficking\n![Hotel Traffiking](https://polarisproject.org/wp-content/uploads/2019/01/800x640-marriott-blog.jpg)\n## Description\n\nVictims of human trafficking are often photographed in hotel rooms as in the below examples. Identifying these hotels is vital to these trafficking investigations but poses particular challenges due to low quality of images and uncommon camera angles.Even without victims in the images, hotel identification in general is a challenging fine-grained visual recognition task with a huge number of classes and potentially high intraclass and low interclass variation. In order to support research into this challenging task and create image search tools for human trafficking investigators, we created the TraffickCam mobile application, which allows every day travelers to submit photos of their hotel room. Read more about [TraffickCam on TechCrunch](https://techcrunch.com/2016/06/25/traffickcam/).\n\n## Task\nIn this contest, competitors are tasked with identifying the hotel seen in test images from the TraffickCam dataset, which are based  on a large gallery of training images with known hotel IDs.\nOur team currently supports an image search system used at the National Center for Missing and Exploited Children in human        trafficking investigations. Novel and interesting approaches have the potential to be incorporated in this search system.","metadata":{}},{"cell_type":"code","source":"!/opt/conda/bin/python3.7 -m pip install --upgrade pip\n! pip install -q efficientnet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#importing necessary libraries\nimport tensorflow as tf\nfrom kaggle_datasets import KaggleDatasets\nimport efficientnet.tfkeras as efn\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport PIL","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"AUTO = tf.data.experimental.AUTOTUNE\n\ntry:\n    tpu = tf.distribute.cluster_resolver.TPUClusterResolver()  \n    print('Running on TPU ', tpu.master())\nexcept ValueError:\n    tpu = None\n\nif tpu:\n    tf.config.experimental_connect_to_cluster(tpu)\n    tf.tpu.experimental.initialize_tpu_system(tpu)\n    strategy = tf.distribute.experimental.TPUStrategy(tpu)\nelse:\n    strategy = tf.distribute.get_strategy()\n\nprint(\"REPLICAS: \", strategy.num_replicas_in_sync)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"GCS_DS_PATH = KaggleDatasets().get_gcs_path()\nTRAIN_PATH = GCS_DS_PATH + \"/train_images/\"\n\ntrain_df = pd.read_csv(\"../input/hotel-id-2021-fgvc8/train.csv\")\n\nprint(\"Number of unique chains: \",train_df.chain.nunique())\nprint(\"Number of unique hotel_ids: \",train_df.hotel_id.nunique())\n\nlabel2id = dict(zip(range(train_df.hotel_id.nunique()),train_df.hotel_id.unique()))\nid2label = dict(zip(train_df.hotel_id.unique(),range(train_df.hotel_id.nunique())))\n\ntrain_df[\"hotel_id\"] = train_df[\"hotel_id\"].map(id2label)\ntrain_df[\"path\"] = train_df['chain'].astype(str) + '/' + train_df['image']\ntrain_df.sort_values(\"path\",inplace=True)\ntrain_df = train_df.drop_duplicates(subset=['image'])\n\ntrain_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Visualization","metadata":{}},{"cell_type":"code","source":"chain_dict = train_df.chain.value_counts()\nchains = list(chain_dict.index)\nchains_count = list(chain_dict.values)\n\nid_dict = train_df.hotel_id.value_counts()\nids = list(id_dict.index)\nids_count = list(id_dict.values)\n\nplt.figure(figsize = (20,10))\nplt.subplot(1,2,1)\nplt.bar(chains,chains_count)\nplt.title(\"Number of instances per chain\",fontweight=\"bold\",fontsize=20)\nplt.xlabel(\"Chains\",fontsize = 30)\nplt.xticks(rotation=20,fontweight = \"bold\")\nplt.xticks(fontweight = \"bold\")\nplt.ylabel(\"Count\",fontsize=30)\n\nplt.subplot(1,2,2)\nplt.bar(ids,ids_count)\nplt.title(\"Number of instances per each ID\",fontweight=\"bold\",fontsize=20)\nplt.xlabel(\"Unique Id's\",fontsize = 30)\nplt.xticks(rotation=20,fontweight = \"bold\")\nplt.xticks(fontweight = \"bold\")\nplt.ylabel(\"Count\",fontsize=30)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"temp_df = train_df.groupby( [\"chain\",\"hotel_id\"])\nfor key,val in temp_df.groups.items():\n    temp_df.groups[key] = len(val)\ncount_ls = list(temp_df.groups.items())\n\ncount_ls = [[a,b,c] for ((a,b),c) in count_ls]\nprint(\"The chain with label '{}' has count of '{}' that belongs to hotel id '{}'\".format(count_ls[0][0],\n                                                                                    count_ls[0][2],\n                                                                                    label2id[count_ls[0][1]]))\nls1 = [i[0] for i in count_ls]\nls2 = [i[1] for i in count_ls]\nls3 = [i[2] for i in count_ls]\n\nfig = plt.figure(figsize = (10, 10))\nax = plt.axes(projection =\"3d\")\nax.scatter3D(ls1,ls2,ls3, color = \"green\")\nax.set_xlabel('Chain',fontweight=\"bold\",fontsize = 20)\nax.set_ylabel('Unique Id',fontweight=\"bold\",fontsize = 20)\nax.set_zlabel('Count',fontweight=\"bold\",fontsize = 20)\nax.set_title(\"Varition of count with Chain and unique Id\",fontweight=\"bold\",fontsize = 25)\n#ax.view_init(40,0)\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### We can see that many images are in first and last chains (0-10,60-88) almost equally spread amon unique Id's","metadata":{}},{"cell_type":"markdown","source":"# Data Pipeline","metadata":{}},{"cell_type":"code","source":"NUM_CLASSES =  train_df.hotel_id.nunique()\nHEIGHT,WIDTH = 256,256\nCHANNELS = 3\nBATCH_SIZE = 8 * strategy.num_replicas_in_sync\nSEED = 143\nSPLIT = int(0.8*len(train_df))\nAUTO = tf.data.experimental.AUTOTUNE\nSTEPS_PER_EPOCH  = SPLIT//BATCH_SIZE\nVALID_STEPS = (len(train_df)-SPLIT)//BATCH_SIZE","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def process_img(filepath,label):\n    image = tf.io.read_file(filepath)\n    image = tf.image.decode_jpeg(image, channels=CHANNELS)\n    image = tf.image.convert_image_dtype(image, tf.float32) \n    image = tf.image.resize(image, [HEIGHT,WIDTH])\n    return image,label\n\n\ndef data_augment(image, label):\n    p_spatial = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_rotate = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_pixel_1 = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_pixel_2 = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_pixel_3 = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n    p_crop = tf.random.uniform([], 0, 1.0, dtype=tf.float32)\n            \n    # Flips\n    image = tf.image.random_flip_left_right(image)\n    image = tf.image.random_flip_up_down(image)\n    if p_spatial > .75:\n        image = tf.image.transpose(image)\n        \n    # Rotates\n    if p_rotate > .75:\n        image = tf.image.rot90(image, k=3) \n    elif p_rotate > .5:\n        image = tf.image.rot90(image, k=2) \n    elif p_rotate > .25:\n        image = tf.image.rot90(image, k=1) \n        \n    \n    if p_pixel_1 >= .4:\n        image = tf.image.random_saturation(image, lower=.7, upper=1.3)\n    if p_pixel_2 >= .4:\n        image = tf.image.random_contrast(image, lower=.8, upper=1.2)\n    if p_pixel_3 >= .4:\n        image = tf.image.random_brightness(image, max_delta=.1)\n        \n    \n    if p_crop > .7:\n        if p_crop > .9:\n            image = tf.image.central_crop(image, central_fraction=.7)\n        elif p_crop > .8:\n            image = tf.image.central_crop(image, central_fraction=.8)\n        else:\n            image = tf.image.central_crop(image, central_fraction=.9)\n    elif p_crop > .4:\n        crop_size = tf.random.uniform([], int(HEIGHT*.8), HEIGHT, dtype=tf.int32)\n        image = tf.image.random_crop(image, size=[crop_size, crop_size, CHANNELS])\n    \n    image = tf.image.resize(image, [HEIGHT,WIDTH])\n    return image,label","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"files_ls = tf.io.gfile.glob(TRAIN_PATH + '*/*.jpg')\nlabels = np.array(train_df.hotel_id.values).astype(\"uint8\")\n    \ndataset = tf.data.Dataset.from_tensor_slices((files_ls,labels))\ndataset = dataset.map(process_img,num_parallel_calls=AUTO)\ndataset = dataset.map(data_augment,num_parallel_calls=AUTO)\n\ntrain_ds = dataset.take(SPLIT)\nval_ds = dataset.skip(SPLIT)\n\ntrain_ds = train_ds.cache().repeat().shuffle(2048).batch(BATCH_SIZE).prefetch(AUTO)\nval_ds = val_ds.cache().repeat().batch(BATCH_SIZE).prefetch(AUTO)\nprint(\"Data Pipeline\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model Function","metadata":{}},{"cell_type":"code","source":"def create_model():\n    \n    pretrained = efn.EfficientNetB4(include_top=False, weights='noisy-student',input_shape=[HEIGHT,WIDTH, 3])\n            \n    x = pretrained.output\n    x = tf.keras.layers.GlobalAveragePooling2D() (x)\n    outputs = tf.keras.layers.Dense(NUM_CLASSES,activation=\"softmax\", dtype='float32')(x)\n        \n    model = tf.keras.Model(pretrained.input, outputs)\n    return model\n\nmodel = create_model()\n#model.summary()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Compiling Function","metadata":{}},{"cell_type":"code","source":"import tensorflow_addons as tfa\n\ndef compile_model(model, lr=0.0001):\n    \n    optimizer = tf.keras.optimizers.Adam(lr=lr)\n    \n    loss = tf.keras.losses.SparseCategoricalCrossentropy()\n    #loss = tfa.losses.TripletSemiHardLoss()   \n    metrics = [\n       tf.keras.metrics.SparseCategoricalAccuracy(name='categorical_accuracy')\n    ]\n\n    model.compile(optimizer=optimizer, loss=loss, metrics=metrics)\n\n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Callbacks Function","metadata":{}},{"cell_type":"code","source":"def create_callbacks():\n    \n    cpk_path = './best_model.h5'\n    \n    checkpoint = tf.keras.callbacks.ModelCheckpoint(\n        filepath=cpk_path,\n        monitor='val_categorical_accuracy',\n        mode='max',\n        save_best_only=True,\n        verbose=1,\n    )\n\n    reducelr = tf.keras.callbacks.ReduceLROnPlateau(\n        monitor='val_categorical_accuracy',\n        mode='max',\n        factor=0.1,\n        patience=3,\n        verbose=0\n    )\n\n    earlystop = tf.keras.callbacks.EarlyStopping(\n        monitor='val_categorical_accuracy',\n        mode='max',\n        patience=10, \n        verbose=1\n    )\n    \n    callbacks = [checkpoint, reducelr, earlystop]         \n    \n    return callbacks","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"code","source":"EPOCHS= 1\nVERBOSE =1\n\ntf.keras.backend.clear_session()\n\nwith strategy.scope():\n    \n    model = create_model()\n    model = compile_model(model, lr=0.0001)\n   \n    callbacks = create_callbacks()\n    \n    history = model.fit(train_ds, \n                        epochs=EPOCHS,\n                        callbacks=callbacks,\n                        steps_per_epoch = STEPS_PER_EPOCH,\n                        validation_data = val_ds,\n                        validation_steps = VALID_STEPS,\n                        verbose=VERBOSE\n                       )","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# History Plotting","metadata":{}},{"cell_type":"code","source":"acc = history.history['categorical_accuracy']\nval_acc = history.history['val_categorical_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs_range = range(len(history.history['val_loss']))\nplt.figure(figsize=(8, 8))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Training Categorical Accuracy')\nplt.plot(epochs_range, val_acc, label='Validation Categorical Accuracy')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Categorical Accuracy')\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Training Loss')\nplt.plot(epochs_range, val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}