{"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":9988,"databundleVersionId":868324,"sourceType":"competition"}],"dockerImageVersionId":30918,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Importing Libraries\nimport os\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nimport torch\nimport torch.nn as nn\nimport torchvision.models as models\n\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision.transforms import v2\nfrom torchvision.tv_tensors import Mask\n\nfrom PIL import Image, UnidentifiedImageError\nfrom sklearn.model_selection import train_test_split","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:29.731752Z","iopub.execute_input":"2025-03-28T11:25:29.732068Z","iopub.status.idle":"2025-03-28T11:25:43.821056Z","shell.execute_reply.started":"2025-03-28T11:25:29.732043Z","shell.execute_reply":"2025-03-28T11:25:43.819767Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Set seed for reproducibility\nSEED = 42\n\n# Set device\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-28T11:25:43.822955Z","iopub.execute_input":"2025-03-28T11:25:43.823661Z","iopub.status.idle":"2025-03-28T11:25:43.832480Z","shell.execute_reply.started":"2025-03-28T11:25:43.823612Z","shell.execute_reply":"2025-03-28T11:25:43.831139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"## Load the dataset\ndataset = pd.read_csv('/kaggle/input/airbus-ship-detection/train_ship_segmentations_v2.csv')\ndataset.head(10)","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:43.835405Z","iopub.execute_input":"2025-03-28T11:25:43.835820Z","iopub.status.idle":"2025-03-28T11:25:45.337592Z","shell.execute_reply.started":"2025-03-28T11:25:43.835790Z","shell.execute_reply":"2025-03-28T11:25:45.336233Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset.info()","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:45.339504Z","iopub.execute_input":"2025-03-28T11:25:45.339920Z","iopub.status.idle":"2025-03-28T11:25:45.401495Z","shell.execute_reply.started":"2025-03-28T11:25:45.339875Z","shell.execute_reply":"2025-03-28T11:25:45.400300Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"duplicate_percent = dataset.duplicated(subset=['ImageId']).sum() / dataset.shape[0] * 100\nprint(\"Percentages of duplicate rows: {:.5}\".format(duplicate_percent))","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:45.402709Z","iopub.execute_input":"2025-03-28T11:25:45.403149Z","iopub.status.idle":"2025-03-28T11:25:45.439416Z","shell.execute_reply.started":"2025-03-28T11:25:45.403108Z","shell.execute_reply":"2025-03-28T11:25:45.438233Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegmentationDataProcessor:\n    def __init__(self, dataset_root: str, csv_file: str, seed: int, image_subdir: str = 'train_v2'):\n        self.dataset_root = dataset_root\n        self.csv_file = csv_file\n        self.seed = seed\n        self.image_subdir = image_subdir\n        self.csv_path = os.path.join(self.dataset_root, self.csv_file)\n\n    def get_data(self) -> tuple[pd.DataFrame, pd.DataFrame, pd.DataFrame]:\n        return self._split_data(self._preprocess_and_group())\n\n    def _preprocess_and_group(self) -> pd.DataFrame:\n        df = pd.read_csv(self.csv_path)\n        df.dropna(subset=['EncodedPixels'], inplace=True)\n        image_dir = os.path.join(self.dataset_root, self.image_subdir)\n        df['ImageId'] = df['ImageId'].apply(lambda image_id: os.path.join(image_dir, image_id))\n\n        # Group RLEs by ImageId\n        grouped_df = df.groupby('ImageId')['EncodedPixels'].apply(list).reset_index()\n        return grouped_df\n\n    def _split_data(self, df: pd.DataFrame):\n        train, evaluation = train_test_split(\n            df,\n            test_size=0.2,\n            random_state=self.seed,\n            shuffle=True\n        )\n        val, test = train_test_split(\n            evaluation,\n            test_size=0.5,\n            random_state=self.seed,\n        )\n        return train, val, test","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:45.440632Z","iopub.execute_input":"2025-03-28T11:25:45.440984Z","iopub.status.idle":"2025-03-28T11:25:45.463130Z","shell.execute_reply.started":"2025-03-28T11:25:45.440939Z","shell.execute_reply":"2025-03-28T11:25:45.461982Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\ntrain, test, val = SegmentationDataProcessor(\n    dataset_root = '/kaggle/input/airbus-ship-detection',\n    csv_file = 'train_ship_segmentations_v2.csv', \n    seed = SEED\n).get_data()","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:45.464554Z","iopub.execute_input":"2025-03-28T11:25:45.464969Z","iopub.status.idle":"2025-03-28T11:25:47.278735Z","shell.execute_reply.started":"2025-03-28T11:25:45.464927Z","shell.execute_reply":"2025-03-28T11:25:47.277681Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegmentationDataset(Dataset):\n    def __init__(self, df: pd.DataFrame, original_shape: tuple[int, int] = (768, 768), transform=None):\n        self.df = df\n        self.original_shape = original_shape\n        self.transform = transform or v2.Compose([\n            v2.Resize((224, 224)),\n            v2.ToImage(),\n        ]\n    )\n        self.image_dtype_transform = v2.ToDtype(torch.float32, scale=True)\n        self.mask_dtype_transform = v2.ToDtype(torch.float32, scale=False)\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        image_path, rle_list = self.df.iloc[idx]\n        combined_mask = torch.zeros(self.original_shape, dtype=torch.uint8)\n\n        for rle_mask_str in rle_list:\n            single_mask = self.rle_decode(rle_mask_str)\n            combined_mask = torch.logical_or(combined_mask, single_mask.to(combined_mask.device))\n\n        mask = Mask(combined_mask.to(torch.uint8))\n\n        try:\n            image = Image.open(image_path).convert('RGB')\n            image, mask = self.transform(image, mask)\n\n            image = self.image_dtype_transform(image)\n            mask = self.mask_dtype_transform(mask)\n        except (OSError, UnidentifiedImageError):\n            next_idx = idx + 1\n            return self.__getitem__(next_idx)\n\n        return image, mask\n\n    @staticmethod\n    def rle_decode(mask_rle: str, shape: tuple[int, int] = (768, 768)) -> torch.Tensor:\n        s_np = np.asarray(mask_rle.split(), dtype=int)     \n\n        starts = torch.from_numpy(s_np[0::2] - 1) \n        lengths = torch.from_numpy(s_np[1::2])\n        ends = starts + lengths\n\n        img_size = shape[0] * shape[1]\n\n        temp_ary = torch.zeros(img_size + 1, dtype=torch.int16)\n        # index_add_(dim, index, tensor) -> adds tensor elements to self at indices in index\n        temp_ary.index_add_(0, starts, torch.ones_like(starts, dtype=torch.int16))\n        temp_ary.index_add_(0, ends, torch.full_like(ends, -1, dtype=torch.int16)) # Add -1 at ends\n\n        # Compute cumulative sum and reshape\n        flat_mask = torch.cumsum(temp_ary, dim=0)[:-1] # Remove the extra element\n\n        # Reshape to (W, H) then transpose to (H, W)\n        mask = flat_mask.reshape((shape[1], shape[0])).T\n\n        # Return the mask as a tensor of type uint8\n        return (mask > 0).to(torch.uint8) ","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:47.279903Z","iopub.execute_input":"2025-03-28T11:25:47.280234Z","iopub.status.idle":"2025-03-28T11:25:47.482812Z","shell.execute_reply.started":"2025-03-28T11:25:47.280169Z","shell.execute_reply":"2025-03-28T11:25:47.481663Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data = SegmentationDataset(train)\ntrain_dataloader = DataLoader(dataset=train_data,\n                                    batch_size=16,\n                                    num_workers=0,\n                                    shuffle=False) ","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:47.485560Z","iopub.execute_input":"2025-03-28T11:25:47.485852Z","iopub.status.idle":"2025-03-28T11:25:47.524500Z","shell.execute_reply.started":"2025-03-28T11:25:47.485828Z","shell.execute_reply":"2025-03-28T11:25:47.523100Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(train_dataloader)","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:25:47.526320Z","iopub.execute_input":"2025-03-28T11:25:47.526697Z","iopub.status.idle":"2025-03-28T11:25:47.552062Z","shell.execute_reply.started":"2025-03-28T11:25:47.526666Z","shell.execute_reply":"2025-03-28T11:25:47.551060Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"image, mask = next(iter(train_dataloader))\n\ndef display_image(image_batch: torch.Tensor, mask_batch: torch.Tensor, idx: int=2, alpha: float=0.3, cmap: str='gray'):\n    # Select the sample image and its corresponding mask\n    image = image_batch[idx].permute(1, 2, 0).cpu().numpy()\n    mask = mask_batch[idx].cpu().numpy()\n\n    # Create subplots: original image, mask, and overlay\n    fig, axes = plt.subplots(1, 3, figsize=(15, 5))\n    \n    # Display original image\n    axes[0].imshow(image)\n    axes[0].set_title(\"Original Image\")\n    \n    # Display mask only\n    axes[1].imshow(mask, cmap=cmap)\n    axes[1].set_title(\"Mask\")\n    \n    # Display overlay of mask on image\n    axes[2].imshow(image)\n    axes[2].imshow(mask, cmap=cmap, alpha=alpha)\n    axes[2].set_title(\"Overlay\")\n    \n    # Remove axis ticks for clarity\n    for ax in axes:\n        ax.axis('off')\n    \n    # Set a suptitle for the entire figure\n    fig.suptitle(f\"Sample {idx} with Mask Overlay\", fontsize=16, y=1.01)\n    plt.tight_layout()\n    plt.show()\n\nimage, mask = next(iter(train_dataloader))\ndisplay_image(image, mask)","metadata":{"execution":{"iopub.status.busy":"2025-03-28T11:27:31.095459Z","iopub.execute_input":"2025-03-28T11:27:31.095803Z","iopub.status.idle":"2025-03-28T11:27:32.295594Z","shell.execute_reply.started":"2025-03-28T11:27:31.095777Z","shell.execute_reply":"2025-03-28T11:27:32.294317Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}