{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","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":"nvidiaTeslaT4","dataSources":[{"sourceId":30892,"databundleVersionId":2715462,"sourceType":"competition"},{"sourceId":10227431,"sourceType":"datasetVersion","datasetId":6323213}],"dockerImageVersionId":30823,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from torch.utils.data import Dataset,DataLoader, random_split\nfrom torchvision.transforms import Compose,Resize,PILToTensor,InterpolationMode,ToPILImage\nimport os\nfrom PIL import Image\nimport time\nimport torch\nimport numpy as np\nimport torch.nn as nn\nfrom torch.functional import F","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:24.509501Z","iopub.execute_input":"2024-12-29T17:35:24.509856Z","iopub.status.idle":"2024-12-29T17:35:32.184938Z","shell.execute_reply.started":"2024-12-29T17:35:24.509823Z","shell.execute_reply":"2024-12-29T17:35:32.184187Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport wandb","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:32.185989Z","iopub.execute_input":"2024-12-29T17:35:32.186277Z","iopub.status.idle":"2024-12-29T17:35:34.359266Z","shell.execute_reply.started":"2024-12-29T17:35:32.186258Z","shell.execute_reply":"2024-12-29T17:35:34.358327Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_path = '/kaggle/input/bkai-igh-neopolyp/train/train'\nlabel_path = '/kaggle/input/bkai-igh-neopolyp/train_gt/train_gt'\ntest_path = '/kaggle/input/bkai-igh-neopolyp/test/test'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:34.360987Z","iopub.execute_input":"2024-12-29T17:35:34.361223Z","iopub.status.idle":"2024-12-29T17:35:34.364801Z","shell.execute_reply.started":"2024-12-29T17:35:34.361202Z","shell.execute_reply":"2024-12-29T17:35:34.363963Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"transform = Compose([Resize((256, 256), interpolation=InterpolationMode.BILINEAR),\n                     PILToTensor()])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:34.366375Z","iopub.execute_input":"2024-12-29T17:35:34.366894Z","iopub.status.idle":"2024-12-29T17:35:34.38541Z","shell.execute_reply.started":"2024-12-29T17:35:34.366863Z","shell.execute_reply":"2024-12-29T17:35:34.384846Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from albumentations import (\n    Compose,\n    RandomRotate90,\n    Flip,\n    HorizontalFlip,\n    VerticalFlip,\n    RandomGamma,\n    RGBShift,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:34.386214Z","iopub.execute_input":"2024-12-29T17:35:34.386515Z","iopub.status.idle":"2024-12-29T17:35:36.751623Z","shell.execute_reply.started":"2024-12-29T17:35:34.386484Z","shell.execute_reply":"2024-12-29T17:35:36.750722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\naugmentation = Compose([\n    # RandomRotate90(p=0.5),\n    # HorizontalFlip(p=0.5),\n    # VerticalFlip(p=0.5),\n     RandomGamma (gamma_limit=(70, 130), always_apply=False, p=0.2),\n    # RGBShift(p=0.3, r_shift_limit=10, g_shift_limit=10, b_shift_limit=10),\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:36.752298Z","iopub.execute_input":"2024-12-29T17:35:36.752705Z","iopub.status.idle":"2024-12-29T17:35:36.907416Z","shell.execute_reply.started":"2024-12-29T17:35:36.752672Z","shell.execute_reply":"2024-12-29T17:35:36.906478Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_path = '/kaggle/input/bkai-igh-neopolyp/train/train'\nlabel_path = '/kaggle/input/bkai-igh-neopolyp/train_gt/train_gt'\ntest_path = '/kaggle/input/bkai-igh-neopolyp/test/test'\ninput_list = os.listdir(input_path)\nlabel_list = os.listdir(label_path)\ntest_list = os.listdir(test_path)\ninputs_path = [input_path + '/' + i for i in input_list]\nlabels_path = [label_path + '/' + i for i in label_list]\ntests_path = [test_path + '/' + i for i in test_list]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:36.908267Z","iopub.execute_input":"2024-12-29T17:35:36.908576Z","iopub.status.idle":"2024-12-29T17:35:37.150351Z","shell.execute_reply.started":"2024-12-29T17:35:36.908542Z","shell.execute_reply":"2024-12-29T17:35:37.14978Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegDataClass(Dataset):\n    def __init__(self, inputs_path,labels_path, transform, augmentation):\n        super(SegDataClass, self).__init__()\n        \n        self.images_list = inputs_path\n        self.masks_list = labels_path\n        self.transform = transform\n        self.augmentation = augmentation\n        \n    def __getitem__(self, index):\n        img_path = self.images_list[index]\n        mask_path = self.masks_list[index]\n        \n        # Open image and mask\n        image = Image.open(img_path)\n        mask = Image.open(mask_path)\n        \n        # Augmentation\n        if self.augmentation:\n            augmented = self.augmentation(image=np.array(image), mask=np.array(mask))\n            image = Image.fromarray(augmented['image'])\n            mask = Image.fromarray(augmented['mask'])\n        \n        # Normalize \n        image = self.transform(image) / 255\n        mask = self.transform(mask) / 255\n        \n        mask = torch.where(mask > 0.65, 1.0, 0.0)\n        mask[2, :, :] = 0.0001\n        mask = torch.argmax(mask, 0).type(torch.int64)\n        \n        return image, mask\n    \n    def __len__(self):\n        return len(self.images_list)\n\n\n# Create dataset\naug_dataset = SegDataClass(inputs_path, labels_path, transform=transform, augmentation=augmentation)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:37.152345Z","iopub.execute_input":"2024-12-29T17:35:37.152584Z","iopub.status.idle":"2024-12-29T17:35:37.158479Z","shell.execute_reply.started":"2024-12-29T17:35:37.152562Z","shell.execute_reply":"2024-12-29T17:35:37.157844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img,label = aug_dataset[10]\nprint(\"Image shape: \", img.shape)\nprint(\"Label shape: \",label.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:37.159923Z","iopub.execute_input":"2024-12-29T17:35:37.160119Z","iopub.status.idle":"2024-12-29T17:35:37.425898Z","shell.execute_reply.started":"2024-12-29T17:35:37.160101Z","shell.execute_reply":"2024-12-29T17:35:37.425165Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.manual_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:37.426772Z","iopub.execute_input":"2024-12-29T17:35:37.427073Z","iopub.status.idle":"2024-12-29T17:35:37.443443Z","shell.execute_reply.started":"2024-12-29T17:35:37.427043Z","shell.execute_reply":"2024-12-29T17:35:37.44269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_size = 0.9\nvalid_size = 0.1\nbatch_size = 4\ntrain_aug_set, valid_aug_set = random_split(aug_dataset, \n                                    [int(train_size * len(aug_dataset)) , \n                                     int(valid_size * len(aug_dataset))])\n\ntrain_dataloader = DataLoader(train_aug_set, batch_size=batch_size, shuffle=True)\nvalid_dataloader = DataLoader(valid_aug_set, batch_size=batch_size, shuffle=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:37.444158Z","iopub.execute_input":"2024-12-29T17:35:37.444344Z","iopub.status.idle":"2024-12-29T17:35:37.453007Z","shell.execute_reply.started":"2024-12-29T17:35:37.444321Z","shell.execute_reply":"2024-12-29T17:35:37.452397Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install segmentation-models-pytorch\nimport segmentation_models_pytorch as smp\n\nmodel = smp.UnetPlusPlus(\n    encoder_name=\"resnet34\",        \n    encoder_weights=\"imagenet\",     \n    in_channels=3,                  \n    classes=3     \n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:37.453831Z","iopub.execute_input":"2024-12-29T17:35:37.454115Z","iopub.status.idle":"2024-12-29T17:35:51.29224Z","shell.execute_reply.started":"2024-12-29T17:35:37.454083Z","shell.execute_reply":"2024-12-29T17:35:51.291289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\ndevice","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:51.293285Z","iopub.execute_input":"2024-12-29T17:35:51.293642Z","iopub.status.idle":"2024-12-29T17:35:51.368571Z","shell.execute_reply.started":"2024-12-29T17:35:51.293611Z","shell.execute_reply":"2024-12-29T17:35:51.367513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install torchsummary\nmodel = model.to('cuda')\nfrom torchsummary import summary\nsummary(model, input_size=(3, 256, 256), device='cuda')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:51.369518Z","iopub.execute_input":"2024-12-29T17:35:51.369748Z","iopub.status.idle":"2024-12-29T17:35:56.019533Z","shell.execute_reply.started":"2024-12-29T17:35:51.369729Z","shell.execute_reply":"2024-12-29T17:35:56.018495Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class CEDiceLoss(nn.Module):\n    def __init__(self, weights) -> None:\n        super(CEDiceLoss, self).__init__()\n        self.eps: float = 1e-6\n        self.weights: torch.Tensor = weights\n\n    def forward(\n            self,\n            output: torch.Tensor,\n            label: torch.Tensor) -> torch.Tensor:\n\n        # cross entropy loss\n        celoss = nn.CrossEntropyLoss(self.weights)(output,label)\n        \n        # compute softmax over the classes axis\n        output_soft = F.softmax(output, dim=1)\n        label_one_hot = F.one_hot(label, num_classes=output.shape[1])\n        label_one_hot = label_one_hot.permute(0, 3, 1, 2).float()\n         # compute the actual dice score\n        dims = (2, 3)\n        intersection = torch.sum(output_soft * label_one_hot, dims)\n        cardinality = torch.sum(output_soft + label_one_hot, dims)\n\n        dice_score = 2. * intersection / (cardinality + self.eps)\n        \n        dice_score = torch.sum(dice_score * self.weights, dim=1)\n        \n        return torch.mean(1. - dice_score) + celoss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.020722Z","iopub.execute_input":"2024-12-29T17:35:56.020969Z","iopub.status.idle":"2024-12-29T17:35:56.026677Z","shell.execute_reply.started":"2024-12-29T17:35:56.020947Z","shell.execute_reply":"2024-12-29T17:35:56.025959Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"weights = torch.Tensor([[0.4, 0.55, 0.05]]).cuda()\nloss_function = CEDiceLoss(weights)\nlearning_rate = 1e-04\n\noptimizer = torch.optim.Adam(params=model.parameters(), lr=learning_rate)\n\nlearing_rate_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=4, gamma=0.6)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.027699Z","iopub.execute_input":"2024-12-29T17:35:56.027909Z","iopub.status.idle":"2024-12-29T17:35:56.04505Z","shell.execute_reply.started":"2024-12-29T17:35:56.027891Z","shell.execute_reply":"2024-12-29T17:35:56.044268Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train function for each epoch\ndef train(train_dataloader, valid_dataloader,learing_rate_scheduler, epoch, display_step):\n    print(f\"Start epoch #{epoch+1}, learning rate for this epoch: {learing_rate_scheduler.get_last_lr()}\")\n    start_time = time.time()\n    train_loss_epoch = 0\n    test_loss_epoch = 0\n    last_loss = 999999999\n    model.train()\n    for i, (data,targets) in enumerate(train_dataloader):\n        \n        # Load data into GPU\n        data, targets = data.to(device), targets.to(device)\n\n        optimizer.zero_grad()\n        outputs = model(data)\n\n        # Backpropagation, compute gradients\n        loss = loss_function(outputs, targets.long())\n        loss.backward()\n\n        # Apply gradients\n        optimizer.step()\n        \n        # Save loss\n        train_loss_epoch += loss.item()\n        if (i+1) % display_step == 0:\n            print('Train Epoch: {} [{}/{} ({}%)]\\tLoss: {:.4f}'.format(\n                epoch + 1, (i+1) * len(data), len(train_dataloader.dataset), 100 * (i+1) * len(data) / len(train_dataloader.dataset), \n                loss.item()))\n                  \n    print(f\"Done epoch #{epoch+1}, time for this epoch: {time.time()-start_time}s\")\n    train_loss_epoch/= (i + 1)\n    \n    # Evaluate the validation set\n    model.eval()\n    with torch.no_grad():\n        for data, target in valid_dataloader:\n            data, target = data.to(device), target.to(device)\n            test_output = model(data)\n            test_loss = loss_function(test_output, target)\n            test_loss_epoch += test_loss.item()\n            \n    test_loss_epoch/= (i+1)\n    \n    return train_loss_epoch , test_loss_epoch","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.045936Z","iopub.execute_input":"2024-12-29T17:35:56.046151Z","iopub.status.idle":"2024-12-29T17:35:56.060517Z","shell.execute_reply.started":"2024-12-29T17:35:56.046132Z","shell.execute_reply":"2024-12-29T17:35:56.059908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Test function\ndef test(dataloader):\n    test_loss = 0\n    correct = 0\n    with torch.no_grad():\n        for i, (data, targets) in enumerate(dataloader):\n            data, targets = data.to(device), targets.to(device)\n            outputs = model(data)\n            _, pred = torch.max(outputs, 1)\n            test_loss += targets.size(0)\n            correct += torch.sum(pred == targets).item()\n    return 100.0 * correct / test_loss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.061253Z","iopub.execute_input":"2024-12-29T17:35:56.061555Z","iopub.status.idle":"2024-12-29T17:35:56.083139Z","shell.execute_reply.started":"2024-12-29T17:35:56.061519Z","shell.execute_reply":"2024-12-29T17:35:56.082591Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = nn.DataParallel(model)\nmodel.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.083718Z","iopub.execute_input":"2024-12-29T17:35:56.083891Z","iopub.status.idle":"2024-12-29T17:35:56.111466Z","shell.execute_reply.started":"2024-12-29T17:35:56.083876Z","shell.execute_reply":"2024-12-29T17:35:56.110813Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"epochs = 50\ndisplay_step = 50\n# Login to Weights & Biases\nwandb.login(key=\"d4c319e1598294bc49591b5a0cd3a84adcd7aa5e\")  \n\n# Initialize a new W&B run\nwandb.init(\n    project=\"polyp-only-random-gamma\",  \n    name=\"unet-training\",  \n    config={  \n        \"epochs\": epochs,\n        \"batch_size\": batch_size,\n        \"learning_rate\": learning_rate,\n    },\n)\n\ntrain_loss_array = []\ntest_loss_array = []\ntrain_accuracy = []  # List to track training accuracy\nvalid_accuracy = []  # List to track validation accuracy\nlast_loss = 9999999999999\n\n\nfor epoch in range(epochs):\n    train_loss_epoch = 0\n    test_loss_epoch = 0\n    \n    # Train the model and return training and validation losses\n    train_loss_epoch, test_loss_epoch = train(\n        train_dataloader, valid_dataloader, learing_rate_scheduler, epoch, display_step\n    )\n    \n    # Save the best model based on validation loss\n    if test_loss_epoch < last_loss:\n        torch.save(model.state_dict(), \"/kaggle/working/model.pth\")\n        torch.save(optimizer.state_dict(), '/kaggle/working/optimizer.pth')\n        last_loss = test_loss_epoch\n\n    # Step the learning rate scheduler\n    learing_rate_scheduler.step()\n    \n    # Append losses to their respective arrays\n    train_loss_array.append(train_loss_epoch)\n    test_loss_array.append(test_loss_epoch)\n\n    # Compute training and validation accuracy\n    train_acc = test(train_dataloader)  # Compute training accuracy\n    valid_acc = test(valid_dataloader)  # Compute validation accuracy\n    train_accuracy.append(train_acc)\n    valid_accuracy.append(valid_acc)\n\n    # Log metrics to W&B\n    wandb.log({\n        \"epoch\": epoch + 1,\n        \"train_loss\": train_loss_epoch,\n        \"valid_loss\": test_loss_epoch,\n        \"train_accuracy\": train_acc,\n        \"valid_accuracy\": valid_acc,\n    })\n\n    # Print epoch summary\n    print(\n        f\"Epoch {epoch + 1}: train_loss: {train_loss_epoch:.4f}, \"\n        f\"valid_loss: {test_loss_epoch:.4f}, \"\n        f\"train_accuracy: {train_acc:.4f}, valid_accuracy: {valid_acc:.4f}\"\n    )\n\n# Finish the W&B run\nwandb.finish()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-29T17:35:56.112195Z","iopub.execute_input":"2024-12-29T17:35:56.112445Z","execution_failed":"2024-12-29T17:36:36.086Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class UNetTestDataClass(Dataset):\n    def __init__(self, images_path, transform):\n        super(UNetTestDataClass, self).__init__()\n        \n        images_list = os.listdir(images_path)\n        images_list = [images_path+'/'+i for i in images_list]\n        \n        self.images_list = images_list\n        self.transform = transform\n        \n    def __getitem__(self, index):\n        img_path = self.images_list[index]\n        data = Image.open(img_path)\n        h = data.size[1]\n        w = data.size[0]\n        data = self.transform(data) / 255        \n        return data, img_path, h, w\n    \n    def __len__(self):\n        return len(self.images_list)","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_dataset = UNetTestDataClass(test_path, transform=transform)\ntest_dataloader = DataLoader(test_dataset, batch_size=8, shuffle=True)\nfor i, (data, path, h, w) in enumerate(test_dataloader):\n    img = data\n    break","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fig, arr = plt.subplots(7, 2, figsize=(16, 30))\narr[0][0].set_title('Image')\narr[0][1].set_title('Predict')\n\ncheckpoint = torch.load('/kaggle/working/model.pth',weights_only=True)\nmodel.load_state_dict(checkpoint)\n\nmodel.eval()\nwith torch.no_grad():\n    model = model.to(device)\n    img = img.to(device)\n    predict = model(img)\n\nfor i in range(7):\n    arr[i][0].imshow(img[i].permute(1, 2, 0).cpu().numpy())\n    arr[i][1].imshow(F.one_hot(torch.argmax(predict[i], 0).cpu(), num_classes=predict.shape[1]).float())  ","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\nif not os.path.isdir(\"/kaggle/working/predicted_masks\"):\n    os.mkdir(\"/kaggle/working/predicted_masks\")\nmodel = model.to(device)\nfor _, (img, path, h, w) in enumerate(test_dataloader):\n    with torch.no_grad():\n        img = img.to(device)\n        predicted_mask = model(img)\n    for i in range(len(path)):\n        image_id = path[i].split('/')[-1].split('.')[0]\n        filename = image_id + \".png\"\n        mask2img = Resize((h[i].item(), w[i].item()), interpolation=InterpolationMode.NEAREST)(ToPILImage()(F.one_hot(torch.argmax(predicted_mask[i], 0)).permute(2, 0, 1).float()))\n        mask2img.save(os.path.join(\"/kaggle/working/predicted_masks\", filename))","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\nimport cv2","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def rle_to_string(runs):\n    return ' '.join(str(x) for x in runs)\n\ndef rle_encode_one_mask(mask):\n    pixels = mask.flatten()\n    pixels[pixels > 0] = 255\n    use_padding = False\n    if pixels[0] or pixels[-1]:\n        use_padding = True\n        pixel_padded = np.zeros([len(pixels) + 2], dtype=pixels.dtype)\n        pixel_padded[1:-1] = pixels\n        pixels = pixel_padded\n    \n    rle = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    if use_padding:\n        rle = rle - 1\n    rle[1::2] = rle[1::2] - rle[:-1:2]\n    return rle_to_string(rle)\n\ndef mask2string(dir):\n    ## mask --> string\n    strings = []\n    ids = []\n    ws, hs = [[] for i in range(2)]\n    for image_id in os.listdir(dir):\n        id = image_id.split('.')[0]\n        path = os.path.join(dir, image_id)\n        print(path)\n        img = cv2.imread(path)[:,:,::-1]\n        h, w = img.shape[0], img.shape[1]\n        for channel in range(2):\n            ws.append(w)\n            hs.append(h)\n            ids.append(f'{id}_{channel}')\n            string = rle_encode_one_mask(img[:,:,channel])\n            strings.append(string)\n    r = {\n        'ids': ids,\n        'strings': strings,\n    }\n    return r\n\n\nMASK_DIR_PATH = '/kaggle/working/predicted_masks' # change this to the path to your output mask folder\ndir = MASK_DIR_PATH\nres = mask2string(dir)\ndf = pd.DataFrame(columns=['Id', 'Expected'])\ndf['Id'] = res['ids']\ndf['Expected'] = res['strings']\ndf.to_csv(r'output.csv', index=False)\n","metadata":{"trusted":true,"execution":{"execution_failed":"2024-12-29T17:36:36.087Z"}},"outputs":[],"execution_count":null}]}