{"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":"# Training file Hotel Id assignment #\n*more info here*","metadata":{}},{"cell_type":"markdown","source":"# Imports, Setup, etc. #","metadata":{}},{"cell_type":"code","source":"# Imports:\n! pip install timm --no-index --find-links=file:///kaggle/input/timm-package/timm","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-06-03T17:26:15.994341Z","iopub.execute_input":"2022-06-03T17:26:15.994757Z","iopub.status.idle":"2022-06-03T17:26:28.009017Z","shell.execute_reply.started":"2022-06-03T17:26:15.994725Z","shell.execute_reply":"2022-06-03T17:26:28.007793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np # linear algebra\nimport math as m\nfrom datetime import datetime\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nimport torch.nn as nn\nimport torchvision\nimport random\nimport numpy.random as rnd\nimport os\nimport matplotlib.pyplot as plt\nfrom PIL import Image as pil_image\nimport albumentations.pytorch as APT\nimport albumentations as A\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.models as models\nimport timm\n\n\n# Don't know what this does, so I'll just keep it there just in case...\n#import os\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        pass\n        #print(os.path.join(dirname, filename))\n\n# File & Folder names (not all used atm):        \nPROJECT_FOLDER = \"../input/hotel-id-to-combat-human-trafficking-2022-fgvc9/\"\nDATA_FOLDER = \"../input/hotelid-2022-train-images-256x256/\" # I added this one but we do not use it currently... (includes all pictures shuffled and padded.)\nIMAGE_FOLDER = DATA_FOLDER + \"images/\"\nOUTPUT_FOLDER = \"\"\n\n# NMBR_HOTELS = 3116\nNMBR_HOTELS = 100\nMAX_WINDOWS_FILENAME_CHAR_LENGTH = 260 \nNMBR_EMBEDDINGS = 20\n","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.011594Z","iopub.execute_input":"2022-06-03T17:26:28.012106Z","iopub.status.idle":"2022-06-03T17:26:28.026864Z","shell.execute_reply.started":"2022-06-03T17:26:28.012052Z","shell.execute_reply":"2022-06-03T17:26:28.025502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Image Processing\n##### Includes creating datasets & Loaders, and data transformations","metadata":{}},{"cell_type":"markdown","source":"### Dataset class v1\n##### Written by Nicolay, currently unused","metadata":{}},{"cell_type":"code","source":"class HotelDataset_Nicolay(Dataset):\n    \"\"\"Dataset used for testing and validation set of hotel images.\"\"\"\n    \n    def __init__(self, DataSet=None,root_dir=\"../input/hotel-id-to-combat-human-trafficking-2022-fgvc9/\", data_path=\"train_images/\", test_data_path=\"test_images/\", validation_percent=0.3, min_images=1, max_images=None, max_entries=None, transform=None):\n        \n        # Setting variables:\n        \n        MAX_WINDOWS_FILENAME_CHAR_LENGTH = 260\n        self.transform = transform\n        # Directory paths:\n        self.root_dir = root_dir\n        self.data_path = data_path\n        self.test_data_path = test_data_path\n        self.full_data_path = os.path.join(root_dir, data_path)\n        self.full_test_data_path = os.path.join(root_dir, test_data_path)\n        \n        # Directory lists\n        dirs = os.listdir(self.full_data_path)\n        tests_dirs = os.listdir(self.full_test_data_path)\n        \n        # Initialise as empty dataset:\n        if DataSet != None:\n            self.hotel_data = DataSet[0]\n            self.hotel_test_data = DataSet[0]\n            self.total_files = DataSet[1]\n            return\n\n        # Scanning for 'usefull' directories:\n        \n        self.num_labels = len(dirs)\n        self.total_files = 0\n        for directory in dirs:\n            files=os.listdir(os.path.join(self.full_data_path,directory))\n            files_number = len(files)\n            # Remove file if it doesn't have required # of images (note: why is there a maximum, can't we just take less out of these dirs?)\n            if (max_images != None and files_number > max_images) or (files_number < min_images):\n                dirs.remove(directory)\n                continue\n            self.total_files += files_number\n            # Stop if max #pictures has been reached\n            if max_entries != None and max_entries >= self.total_files:\n                dirs = dirs[:max_entries]\n                break\n        \n        # Load Test & Validation data :\n        \n        self.hotel_data = np.chararray([self.total_files,2], itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n        iterator = 0\n        for directory in dirs:\n            files=os.listdir(os.path.join(self.full_data_path,directory))\n            for f in files:\n                if not iterator < self.total_files:\n                    break\n                self.hotel_data[iterator] = [f, directory]\n                iterator = iterator + 1\n        \n        # Defide into validation and testing sets:\n        \n        # Validation set:\n        self.validation_files = self.total_files * validation_percent\n        self.validation_files = round(self.validation_files)\n        total_files_copy = self.total_files - self.validation_files\n        self.validation_data = np.chararray([self.validation_files,2], itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n        hotel_data_copy = np.chararray([total_files_copy,2], itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n        iterator = 0\n        indexes_to_remove = []\n        while iterator < self.validation_files:\n            rand_index = random.randint(0, self.total_files-1)\n            self.validation_data[iterator] = self.hotel_data[rand_index]\n            indexes_to_remove.append(rand_index)\n            iterator = iterator + 1\n        \n        # Training set:\n        iterator = 0\n        train_iterator = 0\n        while iterator < self.total_files:\n            if iterator in indexes_to_remove:\n                iterator = iterator + 1\n                continue\n            else:\n                if not train_iterator < self.validation_files:\n                    break\n                hotel_data_copy[train_iterator] = self.hotel_data[iterator]\n                iterator = iterator + 1\n                train_iterator = train_iterator + 1\n        self.total_files = total_files_copy\n        self.hotel_data = hotel_data_copy\n        \n        # Load test data:\n        \n        iterator = 0\n        self.test_files=os.listdir(self.full_test_data_path)\n        self.test_data = np.chararray(len(self.test_files), itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n        print(self.test_data)\n        for i,f in enumerate(self.test_files):\n            self.test_data[i] = f\n        print(self.test_data)\n       \n        \n    def getValidationSet(self):\n        return HotelDataset(DataSet=(self.validation_data, self.validation_files), transform=self.transform)\n    def getTrainSet(self):\n        return HotelDataset(DataSet=(self.training_data, self.training_files), transform=self.transform)\n    def getTestSet(self):\n        return HotelDataset(DataSet=(self.test_data, self.test_files), transform=self.transform)\n            \n    def __getitem__(self, index):\n        label = self.hotel_data[index,1].decode()\n        hotel_image_id = self.hotel_data[index,0].decode()\n        image_path = os.path.join(self.full_data_path, label, hotel_image_id)\n        \n        image = Image.open(image_path)\n        item = image\n        if self.transform != None:\n            item = self.transform(image)\n        return item, label\n        \n    def __len__(self):\n        return self.total_files","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.029265Z","iopub.execute_input":"2022-06-03T17:26:28.029776Z","iopub.status.idle":"2022-06-03T17:26:28.068575Z","shell.execute_reply.started":"2022-06-03T17:26:28.029727Z","shell.execute_reply":"2022-06-03T17:26:28.067329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Dataset class v2\n##### used in rest of code","metadata":{}},{"cell_type":"code","source":"class Hotel_Dataset_Merlijn(Dataset):\n    \"\"\"Dataset to load Hotel images.\"\"\"\n    \n    def __init__(self, root_dir=\"../input/hotel-id-to-combat-human-trafficking-2022-fgvc9/\", data_path=\"train_images/\",\n                 labels_known = True, max_images=10, transform=None, label_list=None, save_names=False):\n        # Setting variables:\n        \n        self.transform = transform\n        self.max_images = max_images\n        self.labels_known = labels_known\n        \n        # Directory paths:\n        self.root_dir = root_dir\n        self.data_path = data_path\n        self.full_data_path = os.path.join(root_dir, data_path)\n        dirs = os.listdir(self.full_data_path)\n\n        # Initialise as empty dataset:\n        data_size = NMBR_HOTELS*self.max_images\n        if labels_known:\n            self.data = np.chararray((data_size,2), itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n            self.label_to_id_arr = np.zeros( NMBR_HOTELS, dtype=np.int32 )\n        else:\n            self.data = np.chararray(data_size, itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n            if type(label_list) != None:\n                self.label_to_id_arr = label_list\n            else:\n                print(\"Warning: no lable list provided for test dataset!\")\n            \n        # Sampling Train or Val data (with labels known):\n        \n        if labels_known:\n            for (dir_nmbr, this_dir) in enumerate(dirs):\n                if dir_nmbr < NMBR_HOTELS:\n                    self.label_to_id_arr[dir_nmbr] = int(this_dir)\n\n                    # Sample pictures:\n                    path_to_dir = os.path.join(self.full_data_path, this_dir)\n                    files = os.listdir(path_to_dir)\n                    sampled_pics = rnd.choice(files, size=self.max_images) #Note: these could be duplicates...\n\n                    #Save as data:\n                    data = np.dstack( (sampled_pics, np.repeat(dir_nmbr, self.max_images)))\n                    (index_start, index_end) = ( (dir_nmbr)*self.max_images, (dir_nmbr+1)*self.max_images)\n                    self.data[index_start: index_end] = data\n            \n        # Sampling Test data:\n        \n        else:\n            self.data = os.listdir(self.full_data_path)\n    \n    def label_to_id(self, label):\n        return self.label_to_id_arr[int(label)]\n    \n    def __len__(self):\n        return len(self.data)\n    \n    def __size__(self):\n        return np.shape(self.data)\n    \n    def __get_label_list__(self):\n        return self.label_to_id_arr\n    \n    def __getitem__(self, idx):\n        #note: has to be changed for no label types, still!\n        \n        if self.labels_known:\n            record = self.data[idx].decode()\n            label = int(record[1])\n            hotel_id = self.label_to_id(label)\n            image_path = os.path.join(self.full_data_path, str(hotel_id), record[0])\n            image = pil_image.open(image_path)\n            if self.transform:\n                image = self.transform(image)\n            \n            return (image, label)\n        \n        else:\n            record = self.data[idx]\n            image_path = os.path.join(self.full_data_path, record)\n            image = pil_image.open(image_path)\n\n            if self.transform:\n                image = self.transform(image)\n            return (image, record)","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.071331Z","iopub.execute_input":"2022-06-03T17:26:28.072149Z","iopub.status.idle":"2022-06-03T17:26:28.096354Z","shell.execute_reply.started":"2022-06-03T17:26:28.072074Z","shell.execute_reply":"2022-06-03T17:26:28.094463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Hotel_Dataset_Merlijn_Bram(Dataset):\n    \"\"\"Dataset to load Hotel images.\"\"\"\n    \n    def __init__(self, root_dir=\"../input/hotel-id-to-combat-human-trafficking-2022-fgvc9/\", data_path=\"train_images/\",\n                 labels_known = True, images_per_hotel=20, ratio_in_training_partition=0.6, training=True, transform=None, shuffle=False):\n        # Setting variables:\n        max_images = self._n_images_in_partition(images_per_hotel, ratio_in_training_partition, training)\n        \n        MAX_WINDOWS_FILENAME_CHAR_LENGTH = 260 \n        self.transform = transform\n        self.max_images = max_images\n        self.labels_known = labels_known\n        \n        # Directory paths:\n        self.root_dir = root_dir\n        self.data_path = data_path\n        self.full_data_path = os.path.join(root_dir, data_path)\n        dirs = os.listdir(self.full_data_path)\n\n        # Initialise as empty dataset:\n        data_size = NMBR_HOTELS*self.max_images\n        if labels_known:\n            self.data = np.chararray((data_size,2), itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n            self.label_to_id_arr = np.zeros( NMBR_HOTELS, dtype=np.int32 )\n        else:\n            self.data = np.chararray(data_size, itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n            \n        # Sampling Train or Val data (with labels known):\n        \n        if labels_known:\n            for (dir_nmbr, this_dir) in enumerate(dirs):\n                if dir_nmbr < NMBR_HOTELS:\n                    self.label_to_id_arr[dir_nmbr] = int(this_dir)\n\n                    # Sample pictures:\n                    path_to_dir = os.path.join(self.full_data_path, this_dir)\n                    files = os.listdir(path_to_dir)\n\n    #                 sampled_pics = rnd.choice(files, size=self.max_images) #Note: these could be duplicates...\n    #                 sampled_pics = self._make_partition(files, training, self.max_images)\n                    sampled_pics = self._make_partition2(files, training, images_per_hotel, ratio_in_training_partition)\n\n                    #Save as data:\n                    data = np.dstack( (sampled_pics, np.repeat(dir_nmbr, self.max_images)))\n                    (index_start, index_end) = ( (dir_nmbr)*self.max_images, (dir_nmbr+1)*self.max_images)\n                    self.data[index_start: index_end] = data\n            \n        # Sampling Test data:\n        \n        else:\n            self.data = os.listdir(self.full_data_path)\n    \n    def _n_images_in_partition(self, images_per_hotel, ratio_in_first_partition, training):\n        n_first_partition = int(np.ceil(images_per_hotel*ratio_in_first_partition))\n        n_second_partition = images_per_hotel - n_first_partition\n        return n_first_partition if training else n_second_partition\n    \n    def _repeatedly_append_to_reach_length(self, l, needed):\n        if len(l) < 1:\n            return []\n        while needed > len(l):\n            l.extend(l[:needed-len(l)])\n        return l\n    \n#     def _make_partition(self, l: [str], make_first_partition = True, amount_per_partition = 10):\n#         if not l:\n#             return []\n#         if len(l) == 1:\n#             return l*amount_per_partition\n#         taken_unique = l[:amount_per_partition*2]\n#         if make_first_partition:\n#             partition = l[:int(np.ceil(len(taken_unique)/2))]\n#         else:\n#             partition = l[int(np.ceil(len(taken_unique)/2)):amount_per_partition*2]\n#         return self._repeatedly_append_to_reach_length(partition, amount_per_partition)\n    \n    def _make_partition2(self, l: [str], make_first_partition = True, images_per_hotel=20, ratio_in_first_partition=0.6):\n        if not l:\n            return []\n\n        amount_in_first_partition = int(np.ceil(min(images_per_hotel, len(l))*ratio_in_first_partition))\n        amount_in_second_partition = min(images_per_hotel, len(l)) - amount_in_first_partition\n        expected_amount = amount_in_first_partition if make_first_partition else amount_in_second_partition\n        expected_total_partition_1 = int(np.ceil(images_per_hotel*ratio_in_first_partition))\n        expected_total_partition_2 = images_per_hotel - expected_total_partition_1\n    #     expected_hotel = expected_total_partition_1 if make_first_partition else expected_total_partition_2\n\n    #     if len(l) == 1:\n    #         return l*expected_amount\n    #     taken_unique = l[:images_per_hotel]\n        if make_first_partition:\n            partition = l[:max(1, amount_in_first_partition)]\n            return self._repeatedly_append_to_reach_length(partition, expected_total_partition_1)\n        else:\n            partition = l[amount_in_first_partition:images_per_hotel]\n            if len(partition) == 0:\n                partition = l[:1]\n            return self._repeatedly_append_to_reach_length(partition, expected_total_partition_2)\n    \n    def label_to_id(self, label):\n        return self.label_to_id_arr[int(label)]\n    \n    def __len__(self):\n        return len(self.data)\n    \n    def __size__(self):\n        return np.shape(self.data)\n    \n    def __getitem__(self, idx, has_label = True):\n        #note: has to be changed for no label types, still!\n        \n        if self.labels_known:\n            record = self.data[idx].decode()\n            label = int(record[1])\n            hotel_id = self.label_to_id(label)\n            image_path = os.path.join(self.full_data_path, str(hotel_id), record[0])\n            image = pil_image.open(image_path)\n            if self.transform:\n                image = self.transform(image=image)\n            \n            return (image, label)\n        \n        else:\n            record = self.data[idx]\n            image_path = os.path.join(self.full_data_path, record)\n            image = pil_image.open(image_path)\n\n            if self.transform:\n                image = self.transform(image)\n            return (image, record)","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.098350Z","iopub.execute_input":"2022-06-03T17:26:28.098788Z","iopub.status.idle":"2022-06-03T17:26:28.133684Z","shell.execute_reply.started":"2022-06-03T17:26:28.098753Z","shell.execute_reply":"2022-06-03T17:26:28.132310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Defining data transformations:","metadata":{}},{"cell_type":"code","source":"class AddRandomMaskTransform:\n    \n    def __init__(self):\n        self.masks_path = r'../input/hotel-id-to-combat-human-trafficking-2022-fgvc9/train_masks'\n        self.max_covered_area_ratio=0.5\n    \n    def __call__(self, source_img: pil_image):\n        import math\n        source_width, source_height = source_img.size\n        source_area = source_width*source_height\n        \n        # Retrieve a random mask\n        random_mask_file_name = random.choice(os.listdir(self.masks_path))\n        random_mask_path = os.path.join(self.masks_path, random_mask_file_name)\n        random_mask = pil_image.open(random_mask_path)\n\n        # The training masks provided by the competition often seem to be at least as large as some of the images\n        # of the hotels. Resize the mask to constrain its surface area to max_covered_area_ratio, while retaining\n        # its aspect ratio.\n        original_mask_width, original_mask_height = random_mask.size\n        original_mask_area = original_mask_width*original_mask_height\n        max_mask_area = source_area*self.max_covered_area_ratio\n        mask_width = math.floor(math.sqrt((max_mask_area*original_mask_width)/original_mask_height))\n        mask_height = math.floor(math.sqrt((max_mask_area*original_mask_height)/original_mask_width))\n        mask = random_mask.resize((mask_width, mask_height))\n\n        # Paste the mask over a random position in the image\n        max_x_coord = max(0, source_width - mask_width)\n        max_y_coord = max(0, source_height - mask_height)\n        random_x_coord = random.randint(0, max_x_coord)\n        random_y_coord = random.randint(0, max_y_coord)\n        source_img.paste(mask, (random_x_coord, random_y_coord), mask)\n        # Mind that most masks have a transparent border that offsets them from (0,0), preventing\n        # most of them from ever showing up all the way at the left or the top of the image.\n        return source_img","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.135647Z","iopub.execute_input":"2022-06-03T17:26:28.136532Z","iopub.status.idle":"2022-06-03T17:26:28.156246Z","shell.execute_reply.started":"2022-06-03T17:26:28.136479Z","shell.execute_reply":"2022-06-03T17:26:28.155226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"IMAGE_SIZE_WIDTH = 256\nIMAGE_SIZE_HEIGHT = 256\n\ntrain_transform = torchvision.transforms.Compose([\n    torchvision.transforms.RandomChoice([\n        torchvision.transforms.Resize((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT)),\n        torchvision.transforms.RandomCrop((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT))\n    ]),\n    AddRandomMaskTransform(),\n#     torchvision.transforms.Resize((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT)),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomRotation((0, 359))]),p=0.3),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomHorizontalFlip()]),p=0.3),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomVerticalFlip()]),p=0.3),\n    #torchvision.transforms.Grayscale(),\n    torchvision.transforms.ToTensor()\n]) #This one should definetly be expanded!\n\ntest_transform = torchvision.transforms.Compose([\n    torchvision.transforms.RandomChoice([\n        torchvision.transforms.Resize((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT)),\n        torchvision.transforms.RandomCrop((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT))\n    ]),\n    AddRandomMaskTransform(),\n#     torchvision.transforms.Resize((IMAGE_SIZE_WIDTH, IMAGE_SIZE_HEIGHT)),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomRotation((0, 359))]),p=0.3),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomHorizontalFlip()]),p=0.3),\n    torchvision.transforms.RandomApply(torch.nn.ModuleList([torchvision.transforms.RandomVerticalFlip()]),p=0.3),\n    #torchvision.transforms.Grayscale(),\n    torchvision.transforms.ToTensor()\n])","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.158290Z","iopub.execute_input":"2022-06-03T17:26:28.158715Z","iopub.status.idle":"2022-06-03T17:26:28.181320Z","shell.execute_reply.started":"2022-06-03T17:26:28.158679Z","shell.execute_reply":"2022-06-03T17:26:28.180243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Creating Datasets & Loaders","metadata":{}},{"cell_type":"code","source":"# Method 1: both sets have each hotel represented, but duplicates are possible:\n\n#dataset_train = Hotel_Dataset_Merlijn(max_images = 1, transform=train_transform)\n#dataset_val = Hotel_Dataset_Merlijn(max_images = 1, transform=train_transform)\n# Not sure if we cannot just use the same one twice, but never mind...\n\n\n# Method 2: only duplicates in dataset may occur, no guarantee about labels\nnmbr_images, val_perc = 20, 0.9\ndataset_total = Hotel_Dataset_Merlijn(max_images = nmbr_images, transform=train_transform)\ntrain_len = m.ceil(nmbr_images*val_perc*NMBR_HOTELS)\nval_len = nmbr_images*NMBR_HOTELS - train_len\ndataset_train, dataset_val = torch.utils.data.random_split(dataset_total, [train_len, val_len])\n\nlabels = dataset_total.__get_label_list__()\ndataset_test = Hotel_Dataset_Merlijn(data_path=\"test_images/\", transform=train_transform, labels_known = False, label_list = labels)\n     \ntrain_loader = DataLoader(dataset_train, batch_size = 25, shuffle=True)\nval_loader = DataLoader(dataset_val, batch_size = 25, shuffle=True)\ntest_loader = DataLoader(dataset_test, batch_size = 1) #this seems sloppy, but makes predict-code nicer now...\n\n# Method 3\n# dataset_train = Hotel_Dataset_Merlijn_Bram(images_per_hotel=10, ratio_in_training_partition=0.6, training=True, transform=train_transform)\n# dataset_val = Hotel_Dataset_Merlijn_Bram(images_per_hotel=10, ratio_in_training_partition=0.6, training=False, transform=test_transform)\n# dataset_test = Hotel_Dataset_Merlijn_Bram(labels_known=False, data_path=\"test_images/\", images_per_hotel=10, ratio_in_training_partition=0.6, training=False, transform=test_transform)\n# dataset_total = Hotel_Dataset_Merlijn_Bram(images_per_hotel=10, ratio_in_training_partition=0.6, training=False, transform=test_transform)\n\n# train_loader = DataLoader(dataset_train, batch_size = 5, shuffle=True)#len(dataset_train))\n# val_loader = DataLoader(dataset_val, batch_size = 5, shuffle=True)\n# test_loader = DataLoader(dataset_test, batch_size = 1, shuffle=False)\n\n","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.182792Z","iopub.execute_input":"2022-06-03T17:26:28.183715Z","iopub.status.idle":"2022-06-03T17:26:28.313935Z","shell.execute_reply.started":"2022-06-03T17:26:28.183675Z","shell.execute_reply":"2022-06-03T17:26:28.312266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Visualising/testing data stuff","metadata":{}},{"cell_type":"code","source":"# Test/visualise datasets:\n\n# Function to visualise datasets:\ndef show_images(ds, n_images=10, labels_known = True):\n    # Only works properly for n_images>10...\n    xlen, ylen = 10, m.ceil(n_images/10)\n    fig, ax = plt.subplots(ylen,xlen, figsize=(22,8))\n    \n    \n    for x in range(xlen):\n        for y in range(ylen):\n            if not labels_known:\n                item = ds.__getitem__(y*10+x)\n            else:\n                (item, label) = ds.__getitem__(y*10+x)\n            ax[y,x].imshow(np.transpose(item, (1,2,0))) # gives error: convert to PIL\n\ndef visualise_data():\n    print(\"\"\"Sizes Datasets:\n        Train: {0}\n        Validate: {1}\n        Test: {2}\"\"\")#.format(dataset_train.__size__(), dataset_val.__size__(), dataset_test.__size__()))\n    print(dataset_train[0])\n\n    show_images(dataset_train,20, labels_known = True) # This gives an error, but I am too lazy to fix it now...\n#visualise_data()\n\n","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.318830Z","iopub.execute_input":"2022-06-03T17:26:28.319651Z","iopub.status.idle":"2022-06-03T17:26:28.330197Z","shell.execute_reply.started":"2022-06-03T17:26:28.319611Z","shell.execute_reply":"2022-06-03T17:26:28.328898Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Auxiliariy functions","metadata":{}},{"cell_type":"code","source":"def save_checkpoint(model, scheduler, optimizer, epoch, name, loss=None, score=None):\n    checkpoint = {\"epoch\": epoch,\n                  \"model\": model.state_dict(),\n                  #\"scheduler\": scheduler.state_dict(),\n                  \"optimizer\": optimizer.state_dict(),\n                  \"loss\": loss,\n                  \"score\": score,\n                  }\n\n    torch.save(checkpoint, f\"{OUTPUT_FOLDER}checkpoint-{name}.pt\")\n\n","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.332911Z","iopub.execute_input":"2022-06-03T17:26:28.333777Z","iopub.status.idle":"2022-06-03T17:26:28.351495Z","shell.execute_reply.started":"2022-06-03T17:26:28.333731Z","shell.execute_reply":"2022-06-03T17:26:28.350313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"# Define model:\n\nclass Hotel_Model (nn.Module):\n    \n    def __init__(self, n_classes = NMBR_HOTELS, embedding_size = NMBR_EMBEDDINGS):\n        super(Hotel_Model, self).__init__()\n        \n        # use (soon-to-be) pre-trained model for heavy lifting:\n        self.main_model = timm.create_model(\"efficientnet_b0\", num_classes=NMBR_HOTELS, pretrained=False)\n        #self.main_model.load_state_dict(torch.load(\"../input/timm-pretrained-efficientnet/efficientnet/efficientnet_b0_ra-3dd342df.pth\"))\n        #self.main_model = models.alexnet()\n        \n        #for param in self.main_model.parameters():\n        #    param.requires_grad = False\n        \n        self.main_model.eval()\n        \n        \n        # Use own torch-layers for last embedding step and classification:\n        #in_features = self.main_model.get_classifier().in_features\n        #in_features = self.main_model.classifier[1].in_features      \n        #self.main_model.classifier = nn.Identity() # turn off classifier in pre-trained model\n        #in_features = 100\n        #self.main_model = nn.Linear(1000, in_features)\n        \n        #self.embedding = nn.Sequential(\n        #    nn.ReLU(),\n        #    nn.Linear(1000, embedding_size),\n        #    nn.ReLU())\n        \n        #Add own final layer and classifier !!! CHANGE THIS TO RETRIEVAL !!!\n        #self.classifier = nn.Sequential(\n        #    nn.Linear(embedding_size, n_classes),\n        #    nn.Softmax(dim=1))\n        \n        self.classifier = nn.Softmax(dim=1)\n    def forward(self,x):\n        x = self.main_model(x)\n        #print(x)\n        #x = x.view(x.size(0), -1) #re-scale\n        #x = self.embedding(x)\n        #print(x)\n        return x,self.classifier(x) #self.classifier(x)\n    \nmodel_test = Hotel_Model()","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.353189Z","iopub.execute_input":"2022-06-03T17:26:28.354327Z","iopub.status.idle":"2022-06-03T17:26:28.487383Z","shell.execute_reply.started":"2022-06-03T17:26:28.354171Z","shell.execute_reply":"2022-06-03T17:26:28.486232Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training Cycle","metadata":{}},{"cell_type":"code","source":"def train_epoch(train_loader, optimizer, loss_fn, model):\n    \"\"\"Training and adjusting model for one epoch.\"\"\"\n    \n    for i, data in enumerate(train_loader): #loop over all data in current batch (in loader!)        \n        # Initialisation:\n        optimizer.zero_grad()\n        inputs, labels =  data\n        #print(inputs)\n        \n        # Make prediction, compute loss\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n        embedding, prediction = model(inputs)\n        loss = loss_fn(prediction, labels)\n        loss.backward()\n        \n        # Adjust model \n        optimizer.step()\n        \n        embedding = embedding.to(\"cpu\")\n        prediction = prediction.to(\"cpu\")\n        labels = labels.to(\"cpu\")\n        \n        pi, l = prediction[0], labels[0]\n        \n        # Log progress\n        prediction, labels = prediction.detach().numpy(), labels.detach().numpy()\n        #print(prediction[0], labels[0])\n        accuracy = np.mean(labels == np.argmax(prediction, axis = 1))\n        \n        print(\"Training batch {} done! (accuracy = {}, Loss = {}, label = {})\".format(i+1, accuracy, loss, labels[0]))\n        \n        \n        \n        embsf, ps = model(inputs)\n        pf = ps[0]\n        #print((pi,pf,l))\n        \n        \n        \n        # Gather data and stuff: TBW\n    \n    print(\"All training completed!\")\n    \n    # Clear all arrays from memory:\n    data, inputs, labels, embedding, prediction, loss = [],[],[],[],[],[]\n    \ndef val_epoch(val_loader, loss_fn, model):\n    \"Compute validation data for one epoch\"\n    \n    # Just like train_epoch, but without adjusting the model...\n    total_vloss = 0.0\n    avg_accuracy = 0.0\n    nmbr_images = 0.0\n    \n    for i, vdata in enumerate(val_loader):\n        nmbr_images += len(vdata)\n        inputs, labels = vdata\n        inputs = inputs.to(device)\n        labels = labels.to(device)\n        emb, prediction = model(inputs)\n        vloss = loss_fn(prediction, labels)\n        total_vloss += vloss\n        top_pred = np.argmax(prediction, axis=1)\n        accuracy = np.mean((top_pred == labels).detach().numpy().astype(int))\n        avg_accuracy += accuracy\n        print( \"Validation batch {0} done! Accuracy: {1}\".format((i+1), accuracy) )\n    \n    vdata, inputs, labels, emb, prediction = [],[],[],[],[]\n    return (total_vloss / (i+1), avg_accuracy / (i+1) )","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.490307Z","iopub.execute_input":"2022-06-03T17:26:28.490705Z","iopub.status.idle":"2022-06-03T17:26:28.511304Z","shell.execute_reply.started":"2022-06-03T17:26:28.490659Z","shell.execute_reply":"2022-06-03T17:26:28.510183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_complete(train_loader, val_loader, model, optimizer, scheduler, loss_fn, nmbr_epochs = 5):\n    \"\"\"Trains and Validates model given loaders and initial model.\"\"\"\n\n    timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')\n    best_vloss = 10**9\n    for epoch in range(nmbr_epochs):\n        print(\"Starting epoch {}\".format(epoch+1))\n        \n        # Train one epoch:\n        model.train(True)\n        train_epoch(train_loader, optimizer, loss_fn, model)\n        scheduler.step()\n        \n        # Validate epoch:\n        print(\"Start Validation...\")\n        model.train(False)\n        with torch.no_grad():\n            (vloss, acc) = val_epoch(val_loader,loss_fn, model)\n        print(\"Validation complete: Loss = {}, Accuracy = {}! Save model & start new epoch:\".format(vloss, acc))\n        \n        # Save current model:\n        #save_checkpoint(model, \"test\", optimizer, epoch, \"TestTraining\")     ","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.513550Z","iopub.execute_input":"2022-06-03T17:26:28.514221Z","iopub.status.idle":"2022-06-03T17:26:28.531571Z","shell.execute_reply.started":"2022-06-03T17:26:28.514165Z","shell.execute_reply":"2022-06-03T17:26:28.530644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"import numpy as np\n#import faiss\n\na1 = np.array([0.,0.,0.,0.,0.])\na2 = np.array([1.,2.,3.,4.,4.])\na3 = np.array([1.,2.,3.,3.,3.])\na4 = np.array([1.,2.,2.,2.,2.])\nembeddings = np.array([a3,a1,a4,a2])\nembeddings = embeddings.astype(np.float32)\nprint(\"Embeddings: \\n{}\".format(embeddings))\n\ntarget = np.array([1.,2.,3.,4.,5.])\ntarget = target.astype(np.float32)\nprint(\"Target: \\n{}\".format(target))\n\nn = 3\n\ndef find_nearest_n_neighbours(target, embeddings, n: int):\n    index =faiss.IndexFlatL2(len(target))\n    index.add(embeddings)\n    \n    distances, indices = index.search(np.array([target]), n)\n    print(\"Indices: \\n{}\".format(indices))\n    print(\"Distances: \\n{}\".format(distances))\n    \nfind_nearest_n_neighbours(target,embeddings,n)","metadata":{"execution":{"iopub.status.busy":"2022-05-30T10:17:18.429245Z","iopub.execute_input":"2022-05-30T10:17:18.429691Z","iopub.status.idle":"2022-05-30T10:17:18.779247Z","shell.execute_reply.started":"2022-05-30T10:17:18.429654Z","shell.execute_reply":"2022-05-30T10:17:18.778127Z"}}},{"cell_type":"code","source":"def predict(test_loader, model, label_to_id):\n    \"\"\"Function to predict the 5 most likely hotels\"\"\"\n    \n    nmbr_cases = len(test_loader)\n    predictions_top_5 = np.chararray((nmbr_cases ,2), itemsize=MAX_WINDOWS_FILENAME_CHAR_LENGTH)\n    \n    for i,data in enumerate(test_loader): #Should just be one batch...\n        (image, name) = data\n        predictions_top_5[i,0] = name[0] # Don't know why we need the [0]...\n        image = image.to(device)\n        emb, prediction = model(image)\n        prediction = prediction.to(\"cpu\")\n        pred_np = prediction.detach().numpy()[0]\n        \n        pred_string = \"\"\n        for j in range(5):\n            ind = np.argmax(pred_np)\n            pred_np[ind] = -10\n            pred_string += str(label_to_id(ind))+\" \"\n        predictions_top_5[i,1] = pred_string\n    return predictions_top_5\n\ndef predict_new(test_loader, model):\n    embeddings = model.embed()","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.532961Z","iopub.execute_input":"2022-06-03T17:26:28.533749Z","iopub.status.idle":"2022-06-03T17:26:28.547333Z","shell.execute_reply.started":"2022-06-03T17:26:28.533711Z","shell.execute_reply":"2022-06-03T17:26:28.546195Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Running the code & Making submission:","metadata":{}},{"cell_type":"code","source":"CUDA_LAUNCH_BLOCKING=1","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.549109Z","iopub.execute_input":"2022-06-03T17:26:28.549520Z","iopub.status.idle":"2022-06-03T17:26:28.567395Z","shell.execute_reply.started":"2022-06-03T17:26:28.549475Z","shell.execute_reply":"2022-06-03T17:26:28.565864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = ('cuda:0' if torch.cuda.is_available() else 'cpu')\nprint(device)","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.568837Z","iopub.execute_input":"2022-06-03T17:26:28.570537Z","iopub.status.idle":"2022-06-03T17:26:28.584037Z","shell.execute_reply.started":"2022-06-03T17:26:28.570472Z","shell.execute_reply":"2022-06-03T17:26:28.582888Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define model & Datasets\nmodel = Hotel_Model()\n\n# Move model to GPU if available\nmodel = model.to(device)\n\n# Optimizer & Loss function: Placeholders for now:\n\noptimizer = torch.optim.AdamW(model.parameters(), lr=0.001)\n#optimizer = torch.optim.SGD(model.parameters(), lr=0.5, momentum=0.9)\nscheduler = torch.optim.lr_scheduler.ExponentialLR(optimizer, gamma=1)\nloss_fn = torch.nn.CrossEntropyLoss()\n#loss_fn = torch.nn.NLLLoss()","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.585207Z","iopub.execute_input":"2022-06-03T17:26:28.585993Z","iopub.status.idle":"2022-06-03T17:26:28.715108Z","shell.execute_reply.started":"2022-06-03T17:26:28.585947Z","shell.execute_reply":"2022-06-03T17:26:28.713610Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train model:\n\nnmbr_epochs = 25\ntrain_complete(train_loader, val_loader, model, optimizer, scheduler, loss_fn, nmbr_epochs)\n\n# Make prediction:\n\nfinal_preds = predict(test_loader, model, dataset_total.label_to_id ) # predictions as np-array\nfinal_preds = pd.DataFrame(final_preds).stack().str.decode('utf-8').unstack() # as panda dataFrame of strings\nfinal_preds.set_axis({'image_id','hotel_id',}, axis=1, inplace=True)  # rename header\n\nprint(final_preds)\nfinal_preds.to_csv(OUTPUT_FOLDER + 'submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2022-06-03T17:26:28.716656Z","iopub.execute_input":"2022-06-03T17:26:28.717269Z"},"trusted":true},"execution_count":null,"outputs":[]}]}