{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.12"},"papermill":{"default_parameters":{},"duration":26.601064,"end_time":"2023-11-13T02:44:18.358611","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2023-11-13T02:43:51.757547","version":"2.4.0"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":45867,"databundleVersionId":6924515,"sourceType":"competition"},{"sourceId":6640479,"sourceType":"datasetVersion","datasetId":3833517},{"sourceId":6746686,"sourceType":"datasetVersion","datasetId":3884593},{"sourceId":6827935,"sourceType":"datasetVersion","datasetId":3926155},{"sourceId":6874344,"sourceType":"datasetVersion","datasetId":3950227},{"sourceId":7259757,"sourceType":"datasetVersion","datasetId":4207197},{"sourceId":147635265,"sourceType":"kernelVersion"}],"dockerImageVersionId":30627,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## 📂 Importing necessary libraries","metadata":{}},{"cell_type":"code","source":"# 📂 Operating System and Garbage Collection\nimport os\nimport gc\n\n# 📷 Computer Vision Library for image processing\nimport cv2\n\n# 📊 Mathematical functions\nimport math\n\n# 📦 Python's built-in library for shallow and deep copy operations\nimport copy\n\n# ⏰ Time-related functions\nimport time\n\n# 🎲 Random number generation\nimport random\n\n# 🔍 File globbing utility\nimport glob\n\n# 🖼️ Image processing library\nfrom PIL import Image\n\n# 📊 Data manipulation library\nimport numpy as np\nimport pandas as pd\n\n# 🚀 Deep Learning Library - PyTorch\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.nn.functional as F\nfrom torch.optim import lr_scheduler\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.cuda import amp\nimport torchvision\n\n# 🛠️ Utility functions\nimport joblib\nfrom tqdm import tqdm\nfrom collections import defaultdict\n\n# 🧱 Sklearn - Machine learning library\nfrom sklearn.preprocessing import LabelEncoder\nfrom sklearn.model_selection import StratifiedKFold\n\n# 🌐 Image Models from torchvision and timm\nimport timm\n\n# 🌈 Augmentation library for image data\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\n# 🎨 Colored terminal text\nfrom colorama import Fore, Back, Style\nb_ = Fore.BLUE\nsr_ = Style.RESET_ALL\n\n# ⚠️ Ignore warnings\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\n# 🚨 For descriptive error messages during CUDA operations\nos.environ['CUDA_LAUNCH_BLOCKING'] = \"1\"\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:43:55.281538Z","iopub.status.busy":"2023-11-13T02:43:55.280498Z","iopub.status.idle":"2023-11-13T02:44:03.308463Z","shell.execute_reply":"2023-11-13T02:44:03.307539Z"},"papermill":{"duration":8.038554,"end_time":"2023-11-13T02:44:03.310789","exception":false,"start_time":"2023-11-13T02:43:55.272235","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🛠️ Configuration parameters for the model and training process.\n\nCONFIG = {\n    \"seed\": 40,  # 🌱 Seed for reproducibility\n    \"img_size\": 2054,  # 🖼️ Image size for training\n    \"model_name\": \"tf_efficientnetv2_s_in21ft1k\",  # 🧠 Model architecture name\n    \"num_classes\": 5,  # 🎯 Number of output classes\n    \"valid_batch_size\": 4,  # 🚚 Batch size for validation\n    \"device\": torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\"),  # 🧭 Device for training (GPU if available, else CPU)\n}\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.340872Z","iopub.status.busy":"2023-11-13T02:44:03.339746Z","iopub.status.idle":"2023-11-13T02:44:03.400977Z","shell.execute_reply":"2023-11-13T02:44:03.39985Z"},"papermill":{"duration":0.071669,"end_time":"2023-11-13T02:44:03.4033","exception":false,"start_time":"2023-11-13T02:44:03.331631","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🌱 Function to set seed for random number generators, ensuring reproducibility.\n\ndef set_seed(seed=42):\n    np.random.seed(seed)  # 🎲 Set seed for NumPy\n    torch.manual_seed(seed)  # 🚀 Set seed for PyTorch on CPU\n    torch.cuda.manual_seed(seed)  # 🚀 Set seed for PyTorch on GPU\n    \n    # ⚙️ When running on the CuDNN backend, two further options must be set\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = False\n    \n    # 🔏 Set a fixed value for the hash seed\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    \n# 🌱 Set seed using the configured seed value\nset_seed(CONFIG['seed'])\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.419081Z","iopub.status.busy":"2023-11-13T02:44:03.418309Z","iopub.status.idle":"2023-11-13T02:44:03.428392Z","shell.execute_reply":"2023-11-13T02:44:03.427695Z"},"papermill":{"duration":0.019962,"end_time":"2023-11-13T02:44:03.43038","exception":false,"start_time":"2023-11-13T02:44:03.410418","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🗂️ Directory paths and file locations for data and model-related files.\n\nROOT_DIR = '/kaggle/input/UBC-OCEAN'  # 📁 Root directory containing the dataset\nTEST_DIR = '/kaggle/input/UBC-OCEAN/test_thumbnails'  # 📁 Test thumbnails directory\nALT_TEST_DIR = '/kaggle/input/UBC-OCEAN/test_images'  # 📁 Alternative test images directory\nModel_predict = '/kaggle/input/check-ponit007'  # 📁 Model prediction directory\nLABEL_ENCODER_BIN = \"/kaggle/input/ubcpytorchwith-classweights-training-fold1of5/label_encoder.pkl\"  # 📄 Label encoder binary file\nBEST_WEIGHT = \"/kaggle/input/baseline-0-36/Acc0.70_Loss1.0140_epoch29_tf_efficientnetv2_s_in21ft1k_0.36.bin\"  # 📄 Best weight file 1\nBEST_WEIGHT2 = \"/kaggle/input/ubc-efficienetnetb0-fold1of10-2048pix-thumbnails/Recall0.9178_Acc0.9437_Loss0.1685_epoch9.bin\"  # 📄 Best weight file 2\nBEST_WEIGHT3 = \"/kaggle/input/ubc-efficienetnetb0-fold1of10-2048pix-thumbnails/Recall0.8858_Acc0.9155_Loss0.2106_epoch1.bin\"  # 📄 Best weight file 3\nBEST_WEIGHT4 = \"/kaggle/input/ver-21-10/Acc0.50_Loss1.2095_epoch4.bin\"  # 📄 Best weight file 4\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.445474Z","iopub.status.busy":"2023-11-13T02:44:03.445157Z","iopub.status.idle":"2023-11-13T02:44:03.450081Z","shell.execute_reply":"2023-11-13T02:44:03.449129Z"},"papermill":{"duration":0.014908,"end_time":"2023-11-13T02:44:03.452122","exception":false,"start_time":"2023-11-13T02:44:03.437214","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📄 Function to get the file path for a test image given its ID.\n\ndef get_test_file_path(image_id):\n    # 📄 Check if the thumbnail file exists in the primary test directory\n    if os.path.exists(f\"{TEST_DIR}/{image_id}_thumbnail.png\"):\n        return f\"{TEST_DIR}/{image_id}_thumbnail.png\"  # 📄 Return the thumbnail file path\n    else:\n        return f\"{ALT_TEST_DIR}/{image_id}.png\"  # 📄 Return the alternative image file path\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.466964Z","iopub.status.busy":"2023-11-13T02:44:03.466672Z","iopub.status.idle":"2023-11-13T02:44:03.472267Z","shell.execute_reply":"2023-11-13T02:44:03.471459Z"},"papermill":{"duration":0.015472,"end_time":"2023-11-13T02:44:03.47424","exception":false,"start_time":"2023-11-13T02:44:03.458768","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📊 Reading test data from a CSV file and adding additional columns.\n\n# 📊 Read the test data CSV file into a DataFrame\ndf = pd.read_csv(f\"{ROOT_DIR}/test.csv\")\n\n# 🖼️ Add a new column 'file_path' by applying the get_test_file_path function to the 'image_id' column\ndf['file_path'] = df['image_id'].apply(get_test_file_path)\n\n# 🏷️ Add a dummy 'label' column with all values set to 0\ndf['label'] = 0  # 🤖 Dummy label for test data\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.489276Z","iopub.status.busy":"2023-11-13T02:44:03.488955Z","iopub.status.idle":"2023-11-13T02:44:03.52001Z","shell.execute_reply":"2023-11-13T02:44:03.518998Z"},"papermill":{"duration":0.041286,"end_time":"2023-11-13T02:44:03.522376","exception":false,"start_time":"2023-11-13T02:44:03.48109","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📊 Reading the sample submission data from a CSV file.\n\n# 📊 Read the sample submission CSV file into a DataFrame\ndf_sub = pd.read_csv(f\"{ROOT_DIR}/sample_submission.csv\")\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.538357Z","iopub.status.busy":"2023-11-13T02:44:03.537537Z","iopub.status.idle":"2023-11-13T02:44:03.550143Z","shell.execute_reply":"2023-11-13T02:44:03.54926Z"},"papermill":{"duration":0.022531,"end_time":"2023-11-13T02:44:03.552076","exception":false,"start_time":"2023-11-13T02:44:03.529545","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📄 Loading the label encoder using joblib.\n\n# 📄 Load the label encoder from the specified binary file\nencoder = joblib.load(LABEL_ENCODER_BIN)\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.567269Z","iopub.status.busy":"2023-11-13T02:44:03.566998Z","iopub.status.idle":"2023-11-13T02:44:03.574044Z","shell.execute_reply":"2023-11-13T02:44:03.573396Z"},"papermill":{"duration":0.017015,"end_time":"2023-11-13T02:44:03.575976","exception":false,"start_time":"2023-11-13T02:44:03.558961","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📄 Function to get cropped images based on specified conditions.\n\ndef get_cropped_images(file_path, image_id, th_area=1000):\n    # 🖼️ Open the image using the PIL library\n    image = Image.open(file_path)\n    \n    # 🔄 Calculate the aspect ratio\n    as_ratio = image.size[0] / image.size[1]\n    \n    sxs, exs, sys, eys = [], [], [], []\n    \n    if as_ratio >= 1.5:\n        # 💡 If aspect ratio is greater than or equal to 1.5, perform cropping\n        \n        # 🎭 Create a mask using maximum value condition\n        mask = np.max(np.array(image) > 0, axis=-1).astype(np.uint8)\n        \n        # 🖼️ Find connected components in the mask\n        retval, labels = cv2.connectedComponents(mask)\n        \n        if retval >= as_ratio:\n            # 🔄 Loop through connected components\n            x, y = np.meshgrid(np.arange(image.size[0]), np.arange(image.size[1]))\n            for label in range(1, retval):\n                # 🚫 Skip small components\n                area = np.sum(labels == label)\n                if area < th_area:\n                    continue\n                \n                # 🔄 Get coordinates of connected components\n                xs, ys = x[labels == label], y[labels == label]\n                \n                # 🎯 Calculate cropping boundaries\n                sx, ex = np.min(xs), np.max(xs)\n                cx = (sx + ex) // 2\n                crop_size = image.size[1]\n                sx = max(0, cx - crop_size // 2)\n                ex = min(sx + crop_size - 1, image.size[0] - 1)\n                sx = ex - crop_size + 1\n                sy, ey = 0, image.size[1] - 1\n                \n                # 📊 Append cropping boundaries to lists\n                sxs.append(sx)\n                exs.append(ex)\n                sys.append(sy)\n                eys.append(ey)\n        else:\n            # 🎯 If no connected components found, divide the image into equal parts\n            crop_size = image.size[1]\n            for i in range(int(as_ratio)):\n                sxs.append(i * crop_size)\n                exs.append((i + 1) * crop_size - 1)\n                sys.append(0)\n                eys.append(crop_size - 1)\n    else:\n        # 🎯 If aspect ratio is less than 1.5, use the entire image without cropping\n        sxs, exs, sys, eys = [0,], [image.size[0] - 1], [0,], [image.size[1] - 1]\n\n    # 📊 Create a DataFrame with image_id, file_path, and cropping boundaries\n    df_crop = pd.DataFrame()\n    df_crop[\"image_id\"] = [image_id] * len(sxs)\n    df_crop[\"file_path\"] = [file_path] * len(sxs)\n    df_crop[\"sx\"] = sxs\n    df_crop[\"ex\"] = exs\n    df_crop[\"sy\"] = sys\n    df_crop[\"ey\"] = eys\n    \n    return df_crop\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.591572Z","iopub.status.busy":"2023-11-13T02:44:03.591217Z","iopub.status.idle":"2023-11-13T02:44:03.605474Z","shell.execute_reply":"2023-11-13T02:44:03.604695Z"},"papermill":{"duration":0.024171,"end_time":"2023-11-13T02:44:03.607376","exception":false,"start_time":"2023-11-13T02:44:03.583205","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🔄 Loop through each row in the 'df' DataFrame and apply the get_cropped_images function.\n\n# 📊 Initialize an empty list to store the DataFrames returned by get_cropped_images\ndfs = []\n\n# 🔄 Loop through each row in the 'df' DataFrame\nfor (file_path, image_id) in zip(df[\"file_path\"], df[\"image_id\"]):\n    # 📊 Append the DataFrame returned by get_cropped_images to the list\n    dfs.append(get_cropped_images(file_path, image_id))\n\n# 📊 Concatenate the list of DataFrames into a single DataFrame\ndf_crop = pd.concat(dfs)\n\n# 🏷️ Add a dummy 'label' column with all values set to 0\ndf_crop[\"label\"] = 0  # 🤖 Dummy label for cropped images\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:03.623716Z","iopub.status.busy":"2023-11-13T02:44:03.623338Z","iopub.status.idle":"2023-11-13T02:44:04.197868Z","shell.execute_reply":"2023-11-13T02:44:04.197015Z"},"papermill":{"duration":0.585144,"end_time":"2023-11-13T02:44:04.199892","exception":false,"start_time":"2023-11-13T02:44:03.614748","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🔄 Remove duplicate rows based on specified columns and reset the index.\n\n# 📊 Drop duplicate rows in the 'df_crop' DataFrame based on the specified subset of columns\ndf_crop = df_crop.drop_duplicates(subset=[\"image_id\", \"sx\", \"ex\", \"sy\", \"ey\"]).reset_index(drop=True)\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:04.216025Z","iopub.status.busy":"2023-11-13T02:44:04.215705Z","iopub.status.idle":"2023-11-13T02:44:04.232242Z","shell.execute_reply":"2023-11-13T02:44:04.23129Z"},"papermill":{"duration":0.026989,"end_time":"2023-11-13T02:44:04.23431","exception":false,"start_time":"2023-11-13T02:44:04.207321","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📦 Custom dataset class for the UBC dataset.\n\nclass UBCDataset(Dataset):\n    def __init__(self, df, transforms=None):\n        # 📊 Initialize the dataset with DataFrame, file names, labels, and transformations\n        self.df = df\n        self.file_names = df['file_path'].values\n        self.labels = df['label'].values\n        self.transforms = transforms\n        self.sxs = df[\"sx\"].values\n        self.exs = df[\"ex\"].values\n        self.sys = df[\"sy\"].values\n        self.eys = df[\"ey\"].values\n        \n    def __len__(self):\n        # 🔄 Return the length of the dataset\n        return len(self.df)\n    \n    def __getitem__(self, index):\n        # 🔍 Get an item from the dataset based on the index\n        \n        # 📄 Get image path, cropping boundaries, and label\n        img_path = self.file_names[index]\n        sx, ex, sy, ey = self.sxs[index], self.exs[index], self.sys[index], self.eys[index]\n        \n        # 🖼️ Read and convert the image to RGB\n        img = cv2.imread(img_path)\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        \n        # 🔄 Crop the image based on cropping boundaries\n        img = img[sy:ey, sx:ex, :]\n        \n        # 🔍 Get the label\n        label = self.labels[index]\n        \n        # 🔄 Apply transformations if specified\n        if self.transforms:\n            img = self.transforms(image=img)[\"image\"]\n            \n        # 🔍 Return a dictionary containing the image and label as torch tensors\n        return {\n            'image': img,\n            'label': torch.tensor(label, dtype=torch.long)\n        }\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:04.25096Z","iopub.status.busy":"2023-11-13T02:44:04.250286Z","iopub.status.idle":"2023-11-13T02:44:04.260089Z","shell.execute_reply":"2023-11-13T02:44:04.259149Z"},"papermill":{"duration":0.020623,"end_time":"2023-11-13T02:44:04.262244","exception":false,"start_time":"2023-11-13T02:44:04.241621","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🔄 Data transformations dictionary for validation images.\n\ndata_transforms = {\n    \"valid\": A.Compose([\n        # 🔄 Resize images to the specified size\n        A.Resize(CONFIG['img_size'], CONFIG['img_size']),\n        \n        # 🚀 Normalize pixel values of the image\n        A.Normalize(\n            mean=[0.485, 0.456, 0.406], \n            std=[0.229, 0.224, 0.225], \n            max_pixel_value=255.0, \n            p=1.0\n        ),\n        \n        # 🚀 Convert the image to a PyTorch tensor\n        ToTensorV2()\n    ], p=1.)\n}","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:04.279468Z","iopub.status.busy":"2023-11-13T02:44:04.278866Z","iopub.status.idle":"2023-11-13T02:44:04.285046Z","shell.execute_reply":"2023-11-13T02:44:04.284214Z"},"papermill":{"duration":0.01697,"end_time":"2023-11-13T02:44:04.287059","exception":false,"start_time":"2023-11-13T02:44:04.270089","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🚀 Implementation of Generalized Mean Pooling (GeM) layer as a PyTorch module.\n\nclass GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        # 🔄 Initialize the GeM layer with parameters p and eps\n        super(GeM, self).__init__()\n        self.p = nn.Parameter(torch.ones(1) * p)\n        self.eps = eps\n\n    def forward(self, x):\n        # 🔍 Forward pass through the GeM layer\n        return self.gem(x, p=self.p, eps=self.eps)\n        \n    def gem(self, x, p=3, eps=1e-6):\n        # 🚀 Generalized Mean Pooling function\n        return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1./p)\n        \n    def __repr__(self):\n        # 🔤 Representation of the GeM layer\n        return self.__class__.__name__ + \\\n                '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + \\\n                ', ' + 'eps=' + str(self.eps) + ')'\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:04.304331Z","iopub.status.busy":"2023-11-13T02:44:04.303509Z","iopub.status.idle":"2023-11-13T02:44:04.311932Z","shell.execute_reply":"2023-11-13T02:44:04.310979Z"},"papermill":{"duration":0.019491,"end_time":"2023-11-13T02:44:04.313901","exception":false,"start_time":"2023-11-13T02:44:04.29441","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🚀 Custom model class for UBC dataset based on the EfficientNet architecture.\n\nclass UBCModel(nn.Module):\n    def __init__(self, model_name, num_classes, pretrained=False, checkpoint_path=None):\n        # 🔄 Initialize the UBCModel with specified parameters\n        super(UBCModel, self).__init__()\n        \n        # 🚀 Create the specified model with or without pretraining\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n\n        # 📏 Get the number of input features for the linear layer\n        in_features = self.model.classifier.in_features\n        \n        # 🔄 Replace the classifier and global pooling layers with Identity\n        self.model.classifier = nn.Identity()\n        self.model.global_pool = nn.Identity()\n        \n        # 🚀 Add Generalized Mean Pooling (GeM) layer\n        self.pooling = GeM()\n        \n        # 📏 Linear layer for final classification\n        self.linear = nn.Linear(in_features, num_classes)\n        \n        # 🔍 Softmax layer for probability distribution\n        self.softmax = nn.Softmax(dim=1)\n\n    def forward(self, images):\n        # 🔍 Forward pass through the UBCModel\n        features = self.model(images)\n        pooled_features = self.pooling(features).flatten(1)\n        output = self.linear(pooled_features)\n        return output\n\n# 🚀 Instantiate UBCModel instances with different weights\nmodel = UBCModel('tf_efficientnetv2_s_in21ft1k', CONFIG['num_classes'])\nmodel2 = UBCModel('tf_efficientnet_b0_ns', CONFIG['num_classes'])\nmodel3 = UBCModel('tf_efficientnet_b0_ns', CONFIG['num_classes'])\nmodel4 = UBCModel('tf_efficientnet_b0_ns', CONFIG['num_classes'])\n\n# 📄 Load the weights into the models\nmodel.load_state_dict(torch.load(BEST_WEIGHT))\nmodel2.load_state_dict(torch.load(BEST_WEIGHT2))\nmodel3.load_state_dict(torch.load(BEST_WEIGHT3))\nmodel4.load_state_dict(torch.load(BEST_WEIGHT3))\n\n# 🔄 Move models to the specified device (GPU if available, else CPU)\nmodel.to(CONFIG['device'])\nmodel2.to(CONFIG['device'])\nmodel3.to(CONFIG['device'])\nmodel4.to(CONFIG['device'])\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:04.330969Z","iopub.status.busy":"2023-11-13T02:44:04.330093Z","iopub.status.idle":"2023-11-13T02:44:09.856385Z","shell.execute_reply":"2023-11-13T02:44:09.855493Z"},"papermill":{"duration":5.537674,"end_time":"2023-11-13T02:44:09.859078","exception":false,"start_time":"2023-11-13T02:44:04.321404","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🚀 Create a DataLoader for the UBC test dataset using the UBCDataset class.\n\n# 🚀 Instantiate the UBCDataset with the cropped DataFrame and validation transforms\ntest_dataset = UBCDataset(df_crop, transforms=data_transforms[\"valid\"])\n\n# 🚚 Create a DataLoader for the test dataset with specified batch size and other settings\ntest_loader = DataLoader(\n    test_dataset, \n    batch_size=CONFIG['valid_batch_size'], \n    num_workers=2,  # 🔍 Number of workers for data loading\n    shuffle=False,   # 🔄 Do not shuffle the data for test set\n    pin_memory=True  # 🚀 Pin the memory for faster GPU data transfer\n)\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:09.877275Z","iopub.status.busy":"2023-11-13T02:44:09.876584Z","iopub.status.idle":"2023-11-13T02:44:09.882313Z","shell.execute_reply":"2023-11-13T02:44:09.881378Z"},"papermill":{"duration":0.017005,"end_time":"2023-11-13T02:44:09.884413","exception":false,"start_time":"2023-11-13T02:44:09.867408","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🔍 Inference loop for making predictions on the test set.\n\n# 📊 Initialize an empty list to store the predictions\npreds = []\n\n# 🔍 Iterate through the test DataLoader\nwith torch.no_grad():\n    bar = tqdm(enumerate(test_loader), total=len(test_loader))\n    for step, data in bar:\n        # 🔄 Move the input images to the specified device\n        images = data['image'].to(CONFIG[\"device\"], dtype=torch.float)\n        \n        # 🔍 Forward pass through the models and combine the outputs\n        outputs1 = model(images)\n        outputs2 = model2(images)\n        outputs3 = model3(images)\n        outputs4 = model4(images)\n        \n        # 🔄 Combine the model outputs using specified weights\n        outputs = 0.66 * (0.37 * outputs4 + 0.675 * outputs2) + 0.322 * (0.35 * outputs1 + 0.655 * outputs3)\n        \n        # 🚀 Apply softmax to obtain probability distribution\n        outputs = model.softmax(outputs)\n        \n        # 📊 Append the predictions to the list\n        preds.append(outputs.detach().cpu().numpy())\n\n# 📊 Stack the predictions into a single NumPy array\npreds = np.vstack(preds)\nprint(preds.shape)\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:09.902157Z","iopub.status.busy":"2023-11-13T02:44:09.901787Z","iopub.status.idle":"2023-11-13T02:44:15.744831Z","shell.execute_reply":"2023-11-13T02:44:15.743674Z"},"papermill":{"duration":5.8547,"end_time":"2023-11-13T02:44:15.747075","exception":false,"start_time":"2023-11-13T02:44:09.892375","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 🔄 Post-processing to get final predictions from the softmax outputs.\n\n# 📊 Create columns for each category in the DataFrame based on predictions\nfor i in range(preds.shape[-1]):\n    df_crop[f\"cat{i}\"] = preds[:, i]\n\n# 📊 Create a dictionary to store the final label for each image\ndict_label = {}\n\n# 🔍 Iterate through the DataFrame grouped by \"image_id\"\nfor image_id, gdf in df_crop.groupby(\"image_id\"):\n    # 🔄 Assign the final label as the index of the maximum value in each category\n    dict_label[image_id] = np.argmax(gdf[[f\"cat{i}\" for i in range(preds.shape[-1])]].values.max(axis=0))\n\n# 📊 Update the 'preds' array with the final labels for each image\npreds = np.array([dict_label[image_id] for image_id in df[\"image_id\"].values])\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:15.766133Z","iopub.status.busy":"2023-11-13T02:44:15.765784Z","iopub.status.idle":"2023-11-13T02:44:15.781338Z","shell.execute_reply":"2023-11-13T02:44:15.780465Z"},"papermill":{"duration":0.027482,"end_time":"2023-11-13T02:44:15.783349","exception":false,"start_time":"2023-11-13T02:44:15.755867","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 📊 Inverse transform the predicted labels using the label encoder and create the submission CSV.\n\n# 📊 Inverse transform the predicted labels using the label encoder\npred_labels = encoder.inverse_transform(preds)\n\n# 📊 Update the 'label' column in the submission DataFrame\ndf_sub[\"label\"] = pred_labels\n\n# 📄 Save the submission DataFrame to a CSV file\ndf_sub.to_csv(\"submission.csv\", index=False)\n","metadata":{"execution":{"iopub.execute_input":"2023-11-13T02:44:15.802229Z","iopub.status.busy":"2023-11-13T02:44:15.80186Z","iopub.status.idle":"2023-11-13T02:44:15.81089Z","shell.execute_reply":"2023-11-13T02:44:15.810121Z"},"papermill":{"duration":0.020861,"end_time":"2023-11-13T02:44:15.812793","exception":false,"start_time":"2023-11-13T02:44:15.791932","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]}]}