{"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":"2025-01-08T01:12:11.242189Z","iopub.execute_input":"2025-01-08T01:12:11.242484Z","iopub.status.idle":"2025-01-08T01:12:15.392071Z","shell.execute_reply.started":"2025-01-08T01:12:11.242449Z","shell.execute_reply":"2025-01-08T01:12:15.391093Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport wandb","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:15.392958Z","iopub.execute_input":"2025-01-08T01:12:15.393395Z","iopub.status.idle":"2025-01-08T01:12:17.097179Z","shell.execute_reply.started":"2025-01-08T01:12:15.393366Z","shell.execute_reply":"2025-01-08T01:12:17.096483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"input_path = '/kaggle/input/bkai-igh-neopolyp-small/train/train'\nlabel_path = '/kaggle/input/bkai-igh-neopolyp-small/train_gt/train_gt'\ntest_path = '/kaggle/input/bkai-igh-neopolyp-small/test/test'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:17.097826Z","iopub.execute_input":"2025-01-08T01:12:17.098120Z","iopub.status.idle":"2025-01-08T01:12:17.101765Z","shell.execute_reply.started":"2025-01-08T01:12:17.098088Z","shell.execute_reply":"2025-01-08T01:12:17.100886Z"}},"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":"2025-01-08T01:12:17.104080Z","iopub.execute_input":"2025-01-08T01:12:17.104315Z","iopub.status.idle":"2025-01-08T01:12:18.255087Z","shell.execute_reply.started":"2025-01-08T01:12:17.104295Z","shell.execute_reply":"2025-01-08T01:12:18.254169Z"}},"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":"2025-01-08T01:12:18.256370Z","iopub.execute_input":"2025-01-08T01:12:18.256712Z","iopub.status.idle":"2025-01-08T01:12:18.413722Z","shell.execute_reply.started":"2025-01-08T01:12:18.256692Z","shell.execute_reply":"2025-01-08T01:12:18.412782Z"}},"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":"2025-01-08T01:12:18.414637Z","iopub.execute_input":"2025-01-08T01:12:18.414906Z","iopub.status.idle":"2025-01-08T01:12:18.616919Z","shell.execute_reply.started":"2025-01-08T01:12:18.414862Z","shell.execute_reply":"2025-01-08T01:12:18.616269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from transformers import SegformerImageProcessor\n\nclass SegDataClass(Dataset):\n    def __init__(self, inputs_path,labels_path, transform, processor):\n        super(SegDataClass, self).__init__()\n        \n        self.images_list = inputs_path\n        self.masks_list = labels_path\n        self.transform = transform\n        self.processor = image_processor\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        mask = self.transform(mask) / 255\n        \n        mask = torch.where(mask > 0.65, 1.0, 0.0)\n        mask[2, :, :] = 0.0001\n        mask = np.array(torch.argmax(mask, 0)).astype(np.uint8)\n        segmentation_map = Image.fromarray(mask)\n        encoded_inputs = self.processor(image, segmentation_map, return_tensors=\"pt\")\n        for k,v in encoded_inputs.items():\n          encoded_inputs[k].squeeze_() # remove batch dimension\n        return encoded_inputs\n    def __len__(self):\n        return len(self.images_list)\n\ntransform = PILToTensor()\nimage_processor = SegformerImageProcessor(reduce_labels=False)\n\naug_dataset = SegDataClass(inputs_path, labels_path, transform=transform, processor=image_processor)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:18.617737Z","iopub.execute_input":"2025-01-08T01:12:18.618063Z","iopub.status.idle":"2025-01-08T01:12:26.645580Z","shell.execute_reply.started":"2025-01-08T01:12:18.618031Z","shell.execute_reply":"2025-01-08T01:12:26.644621Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"torch.manual_seed(42)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:26.646570Z","iopub.execute_input":"2025-01-08T01:12:26.647245Z","iopub.status.idle":"2025-01-08T01:12:26.659084Z","shell.execute_reply.started":"2025-01-08T01:12:26.647212Z","shell.execute_reply":"2025-01-08T01:12:26.658184Z"}},"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":"2025-01-08T01:12:26.660388Z","iopub.execute_input":"2025-01-08T01:12:26.660611Z","iopub.status.idle":"2025-01-08T01:12:26.695184Z","shell.execute_reply.started":"2025-01-08T01:12:26.660592Z","shell.execute_reply":"2025-01-08T01:12:26.694295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from transformers import SegformerForSemanticSegmentation\nimport json\n\n\nid2label = {\n    0: \"neoplastic\",\n    1: \"non-neoplastic\",\n    2: \"background\"\n}\nlabel2id = {v: k for k, v in id2label.items()}\n\n# define model\nmodel = SegformerForSemanticSegmentation.from_pretrained(\"nvidia/mit-b5\",\n                                                         num_labels=3,\n                                                         id2label=id2label,\n                                                         label2id=label2id,\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:26.696102Z","iopub.execute_input":"2025-01-08T01:12:26.696614Z","iopub.status.idle":"2025-01-08T01:12:30.229064Z","shell.execute_reply.started":"2025-01-08T01:12:26.696592Z","shell.execute_reply":"2025-01-08T01:12:30.228087Z"}},"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":"2025-01-08T01:12:30.230245Z","iopub.execute_input":"2025-01-08T01:12:30.230598Z","iopub.status.idle":"2025-01-08T01:12:30.310390Z","shell.execute_reply.started":"2025-01-08T01:12:30.230564Z","shell.execute_reply":"2025-01-08T01:12:30.309408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install evaluate","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:30.311312Z","iopub.execute_input":"2025-01-08T01:12:30.311563Z","iopub.status.idle":"2025-01-08T01:12:35.358028Z","shell.execute_reply.started":"2025-01-08T01:12:30.311543Z","shell.execute_reply":"2025-01-08T01:12:35.357153Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import evaluate\n\nmetric = evaluate.load(\"mean_iou\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:35.360974Z","iopub.execute_input":"2025-01-08T01:12:35.361242Z","iopub.status.idle":"2025-01-08T01:12:37.254366Z","shell.execute_reply.started":"2025-01-08T01:12:35.361220Z","shell.execute_reply":"2025-01-08T01:12:37.253392Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nfrom torch import nn\nfrom sklearn.metrics import accuracy_score\nfrom tqdm.notebook import tqdm\nimport os\n\n# define optimizer\noptimizer = torch.optim.AdamW(model.parameters(), lr=0.00006)\n\n# move model to GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nmodel.to(device)\n\n# Create directory for saving the best model\nsave_dir = \"best_model\"\nos.makedirs(save_dir, exist_ok=True)\n\n# Initialize the best metric for tracking\nbest_mean_iou = float('-inf')  # Start with a very low value\n\nmodel.train()\nfor epoch in range(25):  # loop over the dataset multiple times\n    print(f\"Epoch: {epoch}\")\n    \n    # Training phase\n    for idx, batch in enumerate(tqdm(train_dataloader)):\n        pixel_values = batch[\"pixel_values\"].to(device)\n        labels = batch[\"labels\"].to(device)\n\n        # zero the parameter gradients\n        optimizer.zero_grad()\n\n        # forward + backward + optimize\n        outputs = model(pixel_values=pixel_values, labels=labels)\n        loss, logits = outputs.loss, outputs.logits\n\n        loss.backward()\n        optimizer.step()\n\n        # Evaluate within training loop\n        with torch.no_grad():\n            upsampled_logits = nn.functional.interpolate(logits, size=labels.shape[-2:], mode=\"bilinear\", align_corners=False)\n            predicted = upsampled_logits.argmax(dim=1)\n\n            # Note that the metric expects predictions + labels as numpy arrays\n            metric.add_batch(predictions=predicted.detach().cpu().numpy(), references=labels.detach().cpu().numpy())\n\n        # Print loss and metrics every 100 batches\n        if idx % 100 == 0:\n            # Currently using _compute instead of compute\n            metrics = metric._compute(\n                predictions=predicted.cpu(),\n                references=labels.cpu(),\n                num_labels=len(id2label),\n                ignore_index=255,\n                reduce_labels=False,  # We've already reduced the labels ourselves\n            )\n\n            print(f\"Loss: {loss.item()}\")\n            print(f\"Mean_iou: {metrics['mean_iou']}\")\n            print(f\"Mean accuracy: {metrics['mean_accuracy']}\")\n\n    # Evaluate on validation dataset after each epoch\n    model.eval()  # Set model to evaluation mode\n    val_metrics = {\"mean_iou\": 0, \"mean_accuracy\": 0}\n    val_batches = len(valid_dataloader)\n    \n    with torch.no_grad():\n        for idx, batch in enumerate(tqdm(valid_dataloader)):\n            pixel_values = batch[\"pixel_values\"].to(device)\n            labels = batch[\"labels\"].to(device)\n\n            # Forward pass\n            outputs = model(pixel_values=pixel_values, labels=labels)\n            logits = outputs.logits\n\n            # Upsample and get predictions\n            upsampled_logits = nn.functional.interpolate(logits, size=labels.shape[-2:], mode=\"bilinear\", align_corners=False)\n            predicted = upsampled_logits.argmax(dim=1)\n\n            # Add to metric for validation\n            metric.add_batch(predictions=predicted.detach().cpu().numpy(), references=labels.detach().cpu().numpy())\n\n        # Compute the final metrics for validation\n        val_metrics = metric._compute(\n            predictions=predicted.cpu(),\n            references=labels.cpu(),\n            num_labels=len(id2label),\n            ignore_index=255,\n            reduce_labels=False,\n        )\n\n    print(f\"Validation Mean IoU: {val_metrics['mean_iou']}\")\n    print(f\"Validation Mean Accuracy: {val_metrics['mean_accuracy']}\")\n\n    # Check if this epoch's validation metrics are the best\n    if val_metrics[\"mean_iou\"] > best_mean_iou:\n        best_mean_iou = val_metrics[\"mean_iou\"]\n        # Save the model checkpoint\n        torch.save(model.state_dict(), os.path.join(save_dir, f\"best_model.pth\"))\n        print(\"Best model saved!\")\n\n    model.train()  # Switch back to training mode\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-08T01:12:37.255458Z","iopub.execute_input":"2025-01-08T01:12:37.256194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\nfrom tqdm import tqdm\nif not os.path.isdir(\"/kaggle/working/predicted_masks\"):\n    os.mkdir(\"/kaggle/working/predicted_masks\")\nmodel = model.to(device)\nfor path in tqdm(tests_path):\n    image = Image.open(tests_path[0])\n    pixel_values = image_processor(image, return_tensors=\"pt\").pixel_values.to(device)\n    with torch.no_grad():\n      outputs = model(pixel_values=pixel_values)\n    logits = outputs.logits.cpu()\n    predicted_segmentation_map = image_processor.post_process_semantic_segmentation(outputs, target_sizes=[image.size[::-1]])[0]\n    predicted_segmentation_map = predicted_segmentation_map.cpu().numpy()\n    image_id = path.split('/')[-1].split('.')[0]\n    filename = image_id + \".png\"\n    mask2img = ToPILImage()(F.one_hot(torch.tensor(predicted_segmentation_map)).permute(2, 0, 1).float())\n    mask2img.save(os.path.join(\"/kaggle/working/predicted_masks\", filename))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import cv2\nimport pandas as pd\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 > 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)\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 > 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\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_v1.csv', index=False)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}