{"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":"gpu","dataSources":[{"sourceId":30892,"databundleVersionId":2715462,"sourceType":"competition"},{"sourceId":6968098,"sourceType":"datasetVersion","datasetId":4003467},{"sourceId":6969605,"sourceType":"datasetVersion","datasetId":4004378},{"sourceId":6971411,"sourceType":"datasetVersion","datasetId":4005449}],"dockerImageVersionId":30580,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## Import neccessary model","metadata":{}},{"cell_type":"code","source":"# !pip install torchinfo\nimport os\nimport pandas as pd\nimport numpy as np\nimport cv2\nfrom torchvision.io import read_image\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset, random_split, DataLoader, ConcatDataset, random_split\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom torch.optim.lr_scheduler import StepLR\nfrom torchvision.transforms import ToTensor\nfrom PIL import Image\nimport os\n# from torchsummary import summary\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torchvision \nfrom torchvision import transforms\nfrom torchinfo import summary\nimport timm\nimport random","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-11-16T06:18:18.814433Z","iopub.execute_input":"2023-11-16T06:18:18.814907Z","iopub.status.idle":"2023-11-16T06:18:25.399083Z","shell.execute_reply.started":"2023-11-16T06:18:18.814875Z","shell.execute_reply":"2023-11-16T06:18:25.398150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing Dataset: Conver mask to BRG, Override get_item,..","metadata":{}},{"cell_type":"code","source":"class TransformDataset(Dataset):\n    def __init__(self, img_dir, label_dir, resize=None, transform=None):\n        self.img_dir = img_dir\n        self.label_dir = label_dir\n        self.resize = resize\n        self.transform = transform\n        self.images = [f for f in os.listdir(self.img_dir) if os.path.isfile(os.path.join(self.img_dir, f))]\n\n    def __len__(self):\n        return len(self.images)\n\n    def read_mask(self, mask_path):\n        image = cv2.imread(mask_path)\n        image = cv2.resize(image, self.resize)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)\n\n        red_mask = self.create_color_mask(image, (0, 100, 20), (10, 255, 255)) + \\\n                   self.create_color_mask(image, (160, 100, 20), (179, 255, 255))\n\n        green_mask = self.create_color_mask(image, (36, 25, 25), (70, 255, 255))\n\n        full_mask = np.bitwise_or(red_mask, green_mask).astype(np.uint8)\n        full_mask = np.expand_dims(full_mask, axis=-1)\n\n        return full_mask\n\n    def create_color_mask(self, image, lower, upper):\n        color_mask = cv2.inRange(image, np.array(lower), np.array(upper))\n        color_mask[color_mask != 0] = 1\n        return color_mask\n\n    def __getitem__(self, idx):\n        img_path = os.path.join(self.img_dir, self.images[idx])\n        label_path = os.path.join(self.label_dir, self.images[idx])\n\n        image = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)\n        label = self.read_mask(label_path)\n        image = cv2.resize(image, self.resize)\n\n        # Apply the same augmentation to both image and label\n        if self.transform:\n            augmented = self.transform(image=image, mask=label)\n            image = augmented['image']\n            label = augmented['mask']\n\n        label = label.permute(2, 0, 1).to(torch.float32) # for training 2,0,1\n\n        return image, label","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:25.400960Z","iopub.execute_input":"2023-11-16T06:18:25.401315Z","iopub.status.idle":"2023-11-16T06:18:25.414344Z","shell.execute_reply.started":"2023-11-16T06:18:25.401282Z","shell.execute_reply":"2023-11-16T06:18:25.413463Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load dataset","metadata":{}},{"cell_type":"code","source":"image_path = []\nTRAIN_DIR = '/kaggle/input/bkai-igh-neopolyp/train/train'\nfor root, dirs, files in os.walk(TRAIN_DIR):\n    # iterate over 1000 images\n    for file in files:\n        # create path\n        path = os.path.join(root,file)\n        # add path to list\n        image_path.append(path)\nlen(image_path)","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:25.415853Z","iopub.execute_input":"2023-11-16T06:18:25.416136Z","iopub.status.idle":"2023-11-16T06:18:25.817087Z","shell.execute_reply.started":"2023-11-16T06:18:25.416112Z","shell.execute_reply":"2023-11-16T06:18:25.816172Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"mask_path = []\nTRAIN_MASK_DIR = '/kaggle/input/bkai-igh-neopolyp/train_gt/train_gt'\nfor root, dirs, files in os.walk(TRAIN_MASK_DIR):\n    #iterate over 1000 masks\n    for file in files:\n        # obtain the path\"\n        path = os.path.join(root,file)\n        # add path to the list\n        mask_path.append(path)\nlen(mask_path)","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:25.819128Z","iopub.execute_input":"2023-11-16T06:18:25.819406Z","iopub.status.idle":"2023-11-16T06:18:26.218644Z","shell.execute_reply.started":"2023-11-16T06:18:25.819381Z","shell.execute_reply":"2023-11-16T06:18:26.217704Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Augmentation: Mix with original data, Normalize, Set batch size","metadata":{}},{"cell_type":"code","source":"# Adjusted values for augmentation\naugment_transform = A.Compose([\n    A.HorizontalFlip(p=0.5),\n    A.VerticalFlip(p=0.5),\n    A.RandomGamma (gamma_limit=(70, 130), eps=None, always_apply=False, p=0.2),\n    A.RGBShift(p=0.3, r_shift_limit=10, g_shift_limit=10, b_shift_limit=10),\n    A.OneOf([A.Blur(), A.GaussianBlur(), A.GlassBlur(), A.MotionBlur(), A.GaussNoise(), A.Sharpen(), A.MedianBlur(), A.MultiplicativeNoise()]),\n    A.CoarseDropout(p=0.2, max_height=35, max_width=35, fill_value=255),\n    A.RandomSnow(snow_point_lower=0.1, snow_point_upper=0.15, brightness_coeff=1.5, p=0.09),\n    A.RandomShadow(p=0.1),\n    A.ShiftScaleRotate(p=0.45, border_mode=cv2.BORDER_CONSTANT, shift_limit=0.15, scale_limit=0.15),\n    A.RandomCrop(256, 256),\n    A.Normalize(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)),\n    ToTensorV2(),\n])\n\nnormal_transform = A.Compose([\n    A.Normalize(mean=(0.485, 0.456, 0.406),std=(0.229, 0.224, 0.225)),\n    ToTensorV2(),\n])\n\ncustom_dataset = TransformDataset(img_dir=TRAIN_DIR,\n                                          label_dir=TRAIN_MASK_DIR,\n                                          resize=(256, 256),\n                                          transform=normal_transform)\n\n\n# Set a random seed for reproducibility\nrandom_seed = 42\nrandom.seed(random_seed)\nnp.random.seed(random_seed)\ntorch.manual_seed(random_seed)\n# Define the ratio of the dataset to be used for validation\nvalidation_ratio = 0.1\n\n# Calculate the number of samples for each split\ndataset_size = len(custom_dataset)\nvalidation_size = int(validation_ratio * dataset_size)\ntrain_size = dataset_size - validation_size\n\n# Split the dataset into training and validation sets\ntrain_dataset, val_dataset = random_split(custom_dataset, [train_size, validation_size])\n\n# Create DataLoaders for training and validation\nbatch_size = 4\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n# Augment\n# AUG_train_dataset = TransformDataset(img_dir=TRAIN_DIR,\n#                                       label_dir=TRAIN_MASK_DIR,\n#                                       resize=(256, 256),\n#                                       transform=augment_transform)\n# aug_train_dataset, _ = random_split(AUG_train_dataset, [train_size, validation_size])\n# new_train_dataset = ConcatDataset([train_dataset, aug_train_dataset])\n\nnew_train_dataset = train_dataset\n\ntrain_loader = DataLoader(new_train_dataset, batch_size=batch_size, shuffle=True)\n\nprint('Augmented Trainset: ',new_train_dataset.__len__(),'/',train_dataset.__len__(),'\\n', 'Valid Dataset: ',val_dataset.__len__())","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:26.219764Z","iopub.execute_input":"2023-11-16T06:18:26.220044Z","iopub.status.idle":"2023-11-16T06:18:26.264592Z","shell.execute_reply.started":"2023-11-16T06:18:26.220019Z","shell.execute_reply":"2023-11-16T06:18:26.263717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image,label = val_dataset[2]\nprint('Image: ', image.shape, 'Label: ', label.shape) \n\nlabel_array = label.permute(1, 2, 0).numpy() # set 1,2,0 for show image\nimage_array = image.permute(1, 2, 0).numpy()\n# Create a figure with 2 subplots (1 row, 2 columns)\nfig, axs = plt.subplots(1, 2, figsize=(10, 12))\n\naxs[0].imshow(image_array)\naxs[0].set_title('Image')\naxs[0].axis('off')  \n\naxs[1].imshow(label_array)\naxs[1].set_title('Label')\naxs[1].axis('off')  \n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:26.265875Z","iopub.execute_input":"2023-11-16T06:18:26.266226Z","iopub.status.idle":"2023-11-16T06:18:26.729813Z","shell.execute_reply.started":"2023-11-16T06:18:26.266195Z","shell.execute_reply":"2023-11-16T06:18:26.728947Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Encoder Block","metadata":{}},{"cell_type":"markdown","source":"## Decoder Block","metadata":{}},{"cell_type":"markdown","source":"## Bottleneck Block","metadata":{}},{"cell_type":"markdown","source":"## Full Unet","metadata":{}},{"cell_type":"markdown","source":"### Init Model Unet","metadata":{}},{"cell_type":"code","source":"!pip install segmentation-models-pytorch","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:26.731174Z","iopub.execute_input":"2023-11-16T06:18:26.731540Z","iopub.status.idle":"2023-11-16T06:18:45.706033Z","shell.execute_reply.started":"2023-11-16T06:18:26.731508Z","shell.execute_reply":"2023-11-16T06:18:45.704902Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"torch.cuda.empty_cache()\n# model = UNet(3)\nimport segmentation_models_pytorch as smp\nmodel = smp.UnetPlusPlus(\n    encoder_name=\"resnet50\",      \n    encoder_weights=\"imagenet\",     \n    in_channels=3,                 \n    classes=3                       \n)","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:45.707879Z","iopub.execute_input":"2023-11-16T06:18:45.708293Z","iopub.status.idle":"2023-11-16T06:18:49.178348Z","shell.execute_reply.started":"2023-11-16T06:18:45.708254Z","shell.execute_reply":"2023-11-16T06:18:49.177573Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Setup hyperparameter for optimizer: Adam Optimizer","metadata":{}},{"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(), lr=0.0001) ","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:49.179473Z","iopub.execute_input":"2023-11-16T06:18:49.179725Z","iopub.status.idle":"2023-11-16T06:18:49.185607Z","shell.execute_reply.started":"2023-11-16T06:18:49.179702Z","shell.execute_reply":"2023-11-16T06:18:49.184767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Load before continue training. Change something if needed","metadata":{}},{"cell_type":"code","source":"# checkpoint = torch.load('/kaggle/input/trained-model-2/colorization_model X.pth')\n# model.load_state_dict(checkpoint['model'])\n# device = torch.device('cuda' if torch.cuda.is_available() else \"cpu\")\n# model.to(device)\n\n# optimizer = torch.optim.Adam(model.parameters(), lr=checkpoint['learning_rate'])  # Thay đổi các tham số theo cấu hình của bạn\n# # Nạp trạng thái của optimizer từ checkpoint\n# optimizer.load_state_dict(checkpoint['optimizer'])\n\n# optimizer.param_groups[0]['lr'] = 0.0001\n# # weight_decay = 0.0002  # Adjust as needed\n# # for param_group in optimizer.param_groups:\n# #     param_group['weight_decay'] = weight_decay\n# # Sau khi nạp trạng thái, đưa cả model và optimizer lên device\n# model.to(device)\n# for state in optimizer.state.values():\n#     for k, v in state.items():\n#         if isinstance(v, torch.Tensor):\n#             state[k] = v.to(device)\n# loss_value = checkpoint['loss']\n# # print('Old optimizer: ',checkpoint['optimizer'])\n\n# print(f\"The loss from the checkpoint is: {loss_value:.10f}\")","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:49.188698Z","iopub.execute_input":"2023-11-16T06:18:49.188963Z","iopub.status.idle":"2023-11-16T06:18:49.205934Z","shell.execute_reply.started":"2023-11-16T06:18:49.188940Z","shell.execute_reply":"2023-11-16T06:18:49.205128Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Setup WanDB","metadata":{}},{"cell_type":"code","source":"import wandb\n!wandb login '39dfa65a7ff4076b9db7aaeed60ce25894d086b6'\n\nwandb.init(\n    # set the wandb project where this run will be logged\n    project=\"Polyp-DL\",\n    \n    # track hyperparameters and run metadata\n    config={\n    \"learning_rate\": 0.0001,\n    \"architecture\": \"UNet++\",\n    \"dataset\": \"Polyp\",\n    \"epochs\": 250,\n    }\n)","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:18:49.206980Z","iopub.execute_input":"2023-11-16T06:18:49.207334Z","iopub.status.idle":"2023-11-16T06:19:26.881513Z","shell.execute_reply.started":"2023-11-16T06:18:49.207310Z","shell.execute_reply":"2023-11-16T06:19:26.880630Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Training Model","metadata":{}},{"cell_type":"code","source":"# Set the number of training epochs\nnum_epochs = 50\n\n# Define the learning rate scheduler\n# scheduler = StepLR(optimizer, step_size= 4, gamma=0.65)\n\n# Move the model to the device (e.g., GPU)\ndevice = torch.device('cuda' if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n#Set the loss function\ncriterion = nn.CrossEntropyLoss()\n\n# criterion = \n# best_loss = checkpoint['loss']\n# best_loss = float('inf')\n\nearly_stopping_threshold = 10  # Stop if validation loss doesn't improve for this many epoch\nearly_stopping_counter = 0\nbest_val_loss = float('inf')\n\n# change_learning_rate_threshold = 5\n# learning_rate_counter = 0\n# n=1\n\nfor epoch in range(num_epochs):\n    model.train() # turn train mode\n    total_loss = 0\n    for images, labels in train_loader:\n        images = images.to(device)\n        labels = labels.to(device)\n        # Forward pass\n        labels = labels.squeeze(dim=1).long()\n\n        outputs = model(images)\n\n        loss = criterion(outputs, labels)\n        \n#         l2_regularization = torch.tensor(0., device=device)\n#         for param in model.parameters():\n#             l2_regularization += torch.norm(param, 2)\n#         loss += weight_decay * l2_regularization\n        \n        # Backward pass and optimization\n        loss.backward()\n        optimizer.step()\n        optimizer.zero_grad() # reset for new gradient \n        total_loss += loss.item()  # Accumulate the loss\n        wandb.log({'loss_batch': loss.item()})\n    # Update the learning rate\n#     scheduler.step()\n    \n#     if learning_rate_counter > change_learning_rate_threshold:\n# #         scheduler.step()\n#         optimizer.param_groups[0]['lr'] = 0.0001*0.7**n\n#         n+=1\n#         learning_rate_counter = 0\n\n    # Calculate average loss for the epoch\n    epoch_loss = total_loss / len(train_loader)\n    print(f\"Epoch [{epoch+1}/{num_epochs}], Loss: {epoch_loss:.10f}\")\n    wandb.log({'loss': epoch_loss, 'learning rate': optimizer.param_groups[0]['lr']})\n    \n    model.eval()\n    with torch.no_grad():\n        # Compute validation loss\n        val_loss = 0\n        for val_images, val_labels in val_loader:\n            val_images = val_images.to(device)\n            val_labels = val_labels.to(device)\n            val_labels = val_labels.squeeze(dim=1).long()\n            val_outputs = model(val_images)\n            val_loss += criterion(val_outputs, val_labels).item()\n\n        epoch_val_loss = val_loss / len(val_loader)\n        print(f\"Validation Loss: {epoch_val_loss:.10f}\", f\"Best Validation Loss:{best_val_loss:.10f}\")\n        wandb.log({\"validation loss\": epoch_val_loss})\n\n        # Early stopping check\n        if epoch_val_loss < best_val_loss:\n            best_val_loss = epoch_val_loss\n            checkpoint = { \n                'epoch': epoch,\n                'model': model.state_dict(),\n                'optimizer': optimizer.state_dict(),\n                'loss': loss,\n                'learning_rate': optimizer.param_groups[0]['lr']\n            }\n            save_path = f'colorization_model.pth'\n            torch.save(checkpoint, save_path)\n            print('Saved best model')\n            early_stopping_counter = 0\n        else:\n            early_stopping_counter += 1\n#             learning_rate_counter += 1\n\n        # If validation loss doesn't improve for a certain number of epochs, stop training\n        if early_stopping_counter >= early_stopping_threshold:\n            print(f\"Early stopping after {epoch+1} epochs. Best Validation Loss: {best_val_loss:.10f}\")\n            break\n","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:19:26.883011Z","iopub.execute_input":"2023-11-16T06:19:26.884033Z","iopub.status.idle":"2023-11-16T06:38:31.023991Z","shell.execute_reply.started":"2023-11-16T06:19:26.883993Z","shell.execute_reply":"2023-11-16T06:38:31.022799Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Save Ouput","metadata":{}},{"cell_type":"code","source":"!mkdir predict_mask\n# !mkdir test_overlapmask","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:38:31.025172Z","iopub.execute_input":"2023-11-16T06:38:31.025552Z","iopub.status.idle":"2023-11-16T06:38:32.027267Z","shell.execute_reply.started":"2023-11-16T06:38:31.025512Z","shell.execute_reply":"2023-11-16T06:38:32.025880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"trainsize = 256\ncolor_dict= {0: (0, 0, 0),\n             1: (255, 0, 0),\n             2: (0, 255, 0)}\ndef mask_to_rgb(mask, color_dict):\n    output = np.zeros((mask.shape[0], mask.shape[1], 3))\n    for k in color_dict.keys():\n        output[mask==k] = color_dict[k]\n    return np.uint8(output)    \nmodel.eval()\nfor i in os.listdir(\"/kaggle/input/bkai-igh-neopolyp/test/test\"):\n    img_path = os.path.join(\"/kaggle/input/bkai-igh-neopolyp/test/test\", i)\n    ori_img = cv2.imread(img_path)\n    ori_img = cv2.cvtColor(ori_img, cv2.COLOR_BGR2RGB)\n    ori_w = ori_img.shape[0]\n    ori_h = ori_img.shape[1]\n    img = cv2.resize(ori_img, (trainsize, trainsize))\n    transformed = normal_transform(image=img)\n    input_img = transformed[\"image\"]\n    input_img = input_img.unsqueeze(0).to(device)\n    with torch.no_grad():\n        output_mask = model.forward(input_img).squeeze(0).cpu().numpy().transpose(1,2,0)\n    mask = cv2.resize(output_mask, (ori_h, ori_w))\n    mask = np.argmax(mask, axis=2)\n    new_rgb_mask = np.zeros((*mask.shape, 3)).astype(np.uint8)\n    mask_rgb = mask_to_rgb(mask, color_dict)\n    mask_rgb_true = cv2.cvtColor(mask_rgb, cv2.COLOR_BGR2RGB)\n    mask_rgb = cv2.cvtColor(mask_rgb, cv2.COLOR_RGB2BGR)\n    cv2.imwrite(\"predict_mask/{}\".format(i), mask_rgb)\n#     print(\"processed \", img_path)\nprint(\"Loaded & Processed Test file\")","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:38:32.029704Z","iopub.execute_input":"2023-11-16T06:38:32.030093Z","iopub.status.idle":"2023-11-16T06:39:00.451048Z","shell.execute_reply.started":"2023-11-16T06:38:32.030053Z","shell.execute_reply":"2023-11-16T06:39:00.449938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport cv2\nimport os\n\ndef 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 > 225] = 255\n    pixels[pixels <= 225] = 0\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 rle2mask(mask_rle, shape=(3,3)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\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/predict_mask' # 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']\n\ndf.to_csv(r'output.csv', index=False)\nprint(\"Saved Output\")","metadata":{"execution":{"iopub.status.busy":"2023-11-16T06:39:00.452923Z","iopub.execute_input":"2023-11-16T06:39:00.453620Z","iopub.status.idle":"2023-11-16T06:39:03.538285Z","shell.execute_reply.started":"2023-11-16T06:39:00.453586Z","shell.execute_reply":"2023-11-16T06:39:03.537276Z"},"trusted":true},"execution_count":null,"outputs":[]}]}