{"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":61446,"databundleVersionId":6962461,"sourceType":"competition"},{"sourceId":1807973,"sourceType":"datasetVersion","datasetId":1074109},{"sourceId":7312958,"sourceType":"datasetVersion","datasetId":4229452},{"sourceId":7351547,"sourceType":"datasetVersion","datasetId":4265818},{"sourceId":7565047,"sourceType":"datasetVersion","datasetId":4404878},{"sourceId":7568860,"sourceType":"datasetVersion","datasetId":4405597},{"sourceId":150248402,"sourceType":"kernelVersion"}],"dockerImageVersionId":30588,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Introduction\nThis was my first for computer vision project, and I joined the competition quite late (two weeks before the deadline!). While my highest ranking was 122, it unfortunately dropped to 318 due to inconsistencies between private and public scores. Despite the rank drop, I gained valuable insights thanks to the shared kernels (Special thanks to @misakimatsutomo). Congratulations to everyone who achieved great results!\n\nI've shared my notebook for anyone interested: [[Infer] Segmentation Mask](https://www.kaggle.com/code/minhsienweng/infer-segmentation-mask)\n\nI'd be happy to receive any feedback!\n\n## Competition \n- **Goal:** Develop a model to segment blood vessels in 3D scans of human kidneys (HiP-CT data).\n- **Impact:** Help researchers understand the size, shape, branching angles, and `patterning` of blood vessels in human tissue.\n- **Competition link**: [SenNet + HOA - Hacking the Human Vasculature in 3D](https://www.kaggle.com/competitions/blood-vessel-segmentation)\n\n## Solution summary\nThis notebook loads a pre-trained CNN segmentation model and predicts the run-length encoded (RLE) masks for each test image. RLE masks represent segmentation results for 3D images of human kidneys.\n\nThis notenook leverages an ensemble consisting of a large 1024x1024 model and two smaller 512x512 models. The large model, trained on larger 1024x1024 images, receives a higher weight of 0.75. Conversely, the smaller models, trained on single-channel 512x512 images, have a lower weight of 0.25. This weighting scheme adjusts the individual predictions from each model as follows:\n\n`predictions = 0.75 * large-model  + 0.25 * (0.8 * small-model + 0.2 * small-model2)`\n\nThe predictions are subsequently adjusted using three color channels: channel 0 with weight 0.3288, channel 1 with weight 0.3366, and channel 2 with weight 0.3346.\n\nThe **binary prediction threshold** is set based on the 0.0014109 percentile of predicted results, as mentioned in forum discussions due to its sensitive nature and potential impact on scoring. This choice of threshold has been identified as a potential factor contributing to the unexpected shakeup between private and public scores.\n\n## Models\nThis notebook utilizes one `large` (1024x1024) and two `smaller` (512x512) segmentation models. Two of these models (the large one and one of the smaller ones) were adapted from publicly shared models found in the  discussions. The third, smaller model was specifically trained using this notebook.: [[Train] Segmentation Mask](https://www.kaggle.com/minhsienweng/train-segmentation-mask)\n\nAll three models employed the `Unet` architecture with `se_resnext50_32x4d` backbone, as discussed in the forum. Prior to training, model weights were initialized using ImageNet. The dataset underwent diverse data augmentation (rotation, scaling, cropping, and other techniques like GaussianBlur and adding noise), and splitted into training (`kidney_1_dense`) and validation (`kidney_3_sparse` + `kidney_3_dense`) sets.\n\nTraining loops lasted for 30 epochs using a OneCycleLR scheduler with an initial learning rate of 6e-5. Model performance was evaluated using the surface Dice metric, and the model with the lowest loss was saved for submission.\n\n## Experiement results\nI tried out three different models with varying weights to figure out which one worked best.\n\n| Predictions | Public Score | Private Score |\n| ---  | --- | --- |\n| `0.75* large-model + 0.25 * (0.8 * small-model + 0.2 * small-model2)` | 0.86 | **0.458** | \n| `0.75* large-model + 0.25 * (0.9 * small-model + 0.1 * small-model)` | 0.86 | 0.457 | \n| `0.75* large-model + 0.25 * small-model` | 0.86 | 0.455 |\n| `0.75* large-model + 0.25 * small-model2` | 0.86 | 0.455 |\n\n\n**Reference**\n- [Inference 1024 should have a percentile of 0.00149](https://www.kaggle.com/code/misakimatsutomo/inference-1024-should-have-a-percentile-of-0-00149)\n- [Clean Code 📚| Weighted Ensemble [Inference]](https://www.kaggle.com/code/bhavyadhingra00020/clean-code-weighted-ensemble-inference)\n","metadata":{}},{"cell_type":"markdown","source":"# Copy Imagenet weights \nCopied ImageNet weights to local storage and avoid potential network download issues.","metadata":{}},{"cell_type":"code","source":"!mkdir -p /root/.cache/torch/hub/checkpoints/\n!cp /kaggle/input/se-net-pretrained-imagenet-weights/* /root/.cache/torch/hub/checkpoints/","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Offline install segmentation model (pytorch)\nPython library with Neural Networks for Image Segmentation based on PyTorch\nhttps://segmentation-modelspytorch.readthedocs.io/en/latest/","metadata":{}},{"cell_type":"code","source":"!python -m pip install --no-index --find-links=/kaggle/input/pip-download-for-segmentation-models-pytorch segmentation-models-pytorch","metadata":{"_kg_hide-output":true,"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Import","metadata":{}},{"cell_type":"code","source":"import torch as tc \nimport torch.nn as nn  \nimport numpy as np\nfrom tqdm import tqdm\nfrom torch.cuda.amp import autocast\nimport cv2  #OpenCV\nimport os,sys\nfrom glob import glob\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\n# A Neural Networks for Image Segmentation based on PyTorch\nimport segmentation_models_pytorch as smp\n\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.nn.parallel import DataParallel\nfrom dotenv import load_dotenv","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Ignore warning messages\nimport warnings\nwarnings.filterwarnings('ignore')\nimport torch\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\" \nprint(f\"Device = {DEVICE}\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\n# Seed the same seed to all \ndef seed_everything(seed=42):\n    random.seed(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n\nSEED = 42\nseed_everything(SEED)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import ctypes, gc\nlibc = ctypes.CDLL(\"libc.so.6\")\ndef clear_memory():\n    libc.malloc_trim(0)\n    torch.cuda.empty_cache()\n    gc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Config","metadata":{}},{"cell_type":"code","source":"class CFG:\n    # ============== model =============\n    model_name = 'Unet'\n    backbone = 'se_resnext50_32x4d'\n\n    in_chans = 1 #5 # 65\n    #============== Input image =============\n    image_size = 1024 # (Image size 1024x1024)\n    input_size= 1024 # \n    tile_size = image_size\n    stride = tile_size // 4\n    drop_egde_pixel= 0 # 16 #32\n    \n    target_size = 1\n    chopping_percentile=1e-3\n    # ============== CV fold =============\n    valid_id = 1\n    batch=16 # 16\n    th_percentile = 0.0014109\n    axis_w = [0.328800989, 0.336629584, 0.334569427]\n    axis_second_model = 0\n    # Trained models\n    model_path=[\n        # 1024x1024 images model\n        \"/kaggle/input/segmentation-model-1024x1024-image/se_resnext50_32x4d_26_loss0.10_score0.90_val_loss0.12_val_score0.88_midd_1024.pt/se_resnext50_32x4d_26_loss0.10_score0.90_val_loss0.12_val_score0.88_midd_1024.pt\",\n        \"/kaggle/input/segmentation-model-1024x1024-image/results/best_epoch_1024x1024.bin\", # My trained model\n        # 512x512 images model\n        \"/kaggle/input/sennet-kidney-1-and-3/model_real_23.pt\",\n        \"/kaggle/input/segmentation-model-512x512-image/best_epoch.bin\", # My trained model\n    ]","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Utility Function ","metadata":{}},{"cell_type":"code","source":"class Util():\n    @staticmethod\n    def rle_encode(mask):\n        pixel = mask.flatten()\n        pixel = np.concatenate([[0], pixel, [0]])\n        run = np.where(pixel[1:] != pixel[:-1])[0] + 1\n        run[1::2] -= run[::2]\n        rle = ' '.join(str(r) for r in run)\n        if rle == '':\n            rle = '1 0'\n        return rle\n\n    @staticmethod\n    def min_max_normalization(x:tc.Tensor)->tc.Tensor:\n        \"\"\"input.shape=(batch,f1,...)\"\"\"\n        shape=x.shape\n        if x.ndim>2:\n            x=x.reshape(x.shape[0],-1)\n\n        min_=x.min(dim=-1,keepdim=True)[0]\n        max_=x.max(dim=-1,keepdim=True)[0]\n        if min_.mean()==0 and max_.mean()==1:\n            return x.reshape(shape)\n\n        x=(x-min_)/(max_-min_+1e-9)\n        return x.reshape(shape)\n    \n    @staticmethod\n    def norm_with_clip(x:tc.Tensor, smooth=1e-5):\n        dim = list(range(1, x.ndim))\n        mean = x.mean(dim=dim, keepdim=True)\n        std = x.std(dim=dim, keepdim=True)\n        x = (x-mean)/(std+smooth)\n        x[x>5] = (x[x>5] - 5) * 1e-3 + 5\n        x[x<-3] = (x[x<-3] + 3) * 1e-3 -3\n        return x\n\n    @staticmethod\n    def add_edge(x:tc.Tensor, edge:int):\n        mean_ = int(x.to(tc.float32).mean())\n        x = tc.cat([x, tc.ones([x.shape[0], edge, x.shape[2]], dtype=x.dtype, device=x.device) * mean_], dim=1)\n        x = tc.cat([x, tc.ones([x.shape[0], x.shape[1], edge], dtype=x.dtype, device=x.device) * mean_], dim=2)\n        x = tc.cat([tc.ones([x.shape[0], edge, x.shape[2]], dtype=x.dtype, device=x.device) * mean_, x], dim=1)\n        x = tc.cat([tc.ones([x.shape[0], x.shape[1], edge], dtype=x.dtype, device=x.device) * mean_, x], dim=2)\n        return x\n    \n    @staticmethod\n    # Resize the images to 1024 x 1024\n    def to_1024_1024(img, image_size=1024):\n        if image_size > img.shape[1]:\n            img = np.rot90(img)\n            start1 = (CFG.image_size - img.shape[0])//2 #  \n            top = img[0: start1, 0: img.shape[1] ]\n            bottom = img[img.shape[0]-start1: img.shape[0], 0:img.shape[1] ]\n            img_result = np.concatenate((top,img,bottom ),axis=0)\n            img_result = np.rot90(img_result)\n            img_result = np.rot90(img_result)\n            img_result = np.rot90(img_result)\n        else :\n            img_result = img\n        return img_result\n\n    @staticmethod\n    def to_1024_no_rot(img, image_size=1024):\n        if image_size > img.shape[0]:  \n            start1 = (image_size - img.shape[0])//2\n            top = img[0: start1,   0: img.shape[1] ]\n            bottom = img[img.shape[0]-start1:img.shape[0], 0:img.shape[1] ]\n            img_result = np.concatenate((top,img,bottom ),axis=0)\n        else: \n            img_result = img\n        return img_result\n\n    @staticmethod\n    def to_original_img(im_after, img, image_size=1024):\n        top_ = 0\n        left_ = 0\n        if (im_after.shape[0] > img.shape[0]):\n            top_  = ( image_size - img.shape[0])//2 \n        if    (im_after.shape[1] > img.shape[1]) :\n            left_  = ( image_size - img.shape[1])//2  \n        if (top_>0)or (left_>0) :\n            img_result = im_after[top_  : img.shape[0] + top_,   left_: img.shape[1] + left_ ]\n        else:\n            img_result = im_after\n        return img_result ","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# SegmentationModel \nBy employing the segmentation_models_pytorch library, we load a pre-trained `Unet` model with `se_resnext50_32x4d` backbone, consistent with the training notebook's implementation.\n\nThe `forward` function processes input images layer-by-layer. Each layer involves preprocessing, generating predictions from the model, and post-processing the results.\n- **Preprocessing images:** (1) Normalize and clip the input images using the `norm_with_clip` function, to prevent values from exceeding boundaries (-3 to 5). (2) Images are resized using `bilinear` interpolation. (3) Images are rotated by `90 degrees`.\n- **Predictions:** Obtain model predictions and compute the sigmoid value of predictions, ensuring all values fall within the range of 0 and 1.\n- **Postprocessing images:** (1) Rotate the predictions back to the original image orientation (2) Average all predictions  (3) Resize the averaged predictions to match the original image size using `bilinear` interpolation.","metadata":{}},{"cell_type":"code","source":"class SegModel(nn.Module):\n    def __init__(self, backbone, weights, in_chans, num_classes):\n        super().__init__()\n        print(f\"batch = {CFG.batch}\")\n        # Creating Unet model from segmentation_models_pytorch\n        self.model = smp.Unet(\n            encoder_name=backbone, \n            encoder_weights=weights,\n            in_channels=in_chans,\n            classes=num_classes,\n            activation=None,\n        )\n        # Setting batch size\n        self.batch=CFG.batch\n        \n    def _forward(self, image):\n        output = self.model(image)\n        return output[:, 0] # Extracting the first channel from the output\n    \n    def forward(self, X:tc.Tensor):\n        # Convert tensor to floats\n        X = X.to(tc.float32)\n        X = Util.norm_with_clip(X.reshape(-1, *X.shape[2:])).reshape(X.shape)\n        # Interpolate the images\n        if CFG.input_size!=CFG.image_size:\n            X = nn.functional.interpolate(X, size=(CFG.input_size, CFG.input_size),\n                                          mode='bilinear', align_corners=True)\n        # Data augmentation by rotating \n        shape = X.shape\n        X = [tc.rot90(X, k=i, dims=(-2,-1)) for i in range(4)]\n        X = tc.cat(X, dim=0)\n        # automatic Tensor Casting for infer loop\n        with autocast():\n            with tc.no_grad(): # Set zero gradient\n                # Get the output of the layer for a batch of data\n                X = [self._forward(X[i*self.batch: (i+1)*self.batch]) for i in range(X.shape[0]//self.batch+1)]\n                # Concatenete all the outputs along the batch dimension\n                X = tc.cat(X, dim=0)\n        # Compute the sigmoid value of 'X' between 0 and 1\n        X = X.sigmoid()\n        X = X.reshape(4, shape[0], *shape[2:])\n        \n        # Rotating the tensor back (-i) to the original orientation\n        X = [tc.rot90(X[i], k=-i, dims=(-2,-1)) for i in range(4)]\n        # Join (concatenate) tensors X along a new dimension and get the mean\n        X = tc.stack(X, dim=0).mean(0)\n        # Interpolate\n        if CFG.input_size != CFG.image_size:\n            X=nn.functional.interpolate(X[None], size=(CFG.image_size,CFG.image_size),\n                                        mode='bilinear', align_corners=True)[0]\n        return X","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load models\n\nLoad one models (`model`) trained on 1024x1024 images and two model (`model2` and `model3`) trained on 512x512 images   ","metadata":{}},{"cell_type":"code","source":"def load_model(model_path, strict=True):\n    model = SegModel(backbone='se_resnext50_32x4d', \n                 weights=None,\n                 in_chans=1, \n                 num_classes=1)\n    model.load_state_dict(tc.load(model_path, \"cpu\"), strict=strict) # Load the model weights\n    model = model.cuda() # Move the model to `cuda`\n    model.eval() # Setting the model to evaluation mode\n    model = DataParallel(model) # Move the model to a container for parallel execution\n    return model","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load 1024x1024 Image model\n#model_path = CFG.model_path[9] # se_resnext50_32x4d_26\n# se_resnext50_32x4d_30\nmodel_path = \"/kaggle/input/segmentation-model-1024x1024-image/se_resnext50_32x4d_26_loss0.10_score0.90_val_loss0.12_val_score0.88_midd_1024.pt/se_resnext50_32x4d_26_loss0.10_score0.90_val_loss0.12_val_score0.88_midd_1024.pt\"\nmodel = load_model(model_path)\n# Load 1024x1024 Image model\n# # se_resnext50_32x4d_24 (1024x1024)\n# # model2_path = \"/kaggle/input/blood-vessel-model-1024/se_resnext50_32x4d_24_loss0.91_score0.09_val_loss0.91_val_score0.09_midd_1024.pt\"\n# model2_path = \"/kaggle/input/segmentation-model-1024x1024-image/results/best_epoch_1024x1024.bin\"\n# model2 = load_model(model2_path, strict=False)","metadata":{"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model_real_23 (512x512)\nmodel2_path = \"/kaggle/input/sennet-kidney-1-and-3/model_real_23.pt\"\nmodel2 = load_model(model2_path)","metadata":{"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# se_resnext50_32x4d_24 (512x512)\nmodel3_path = \"/kaggle/input/segmentation-model-512x512-image/best_epoch.bin\"\nmodel3 = load_model(model3_path, strict=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load dataset","metadata":{}},{"cell_type":"code","source":"class SegmentationDataset(Dataset):\n    def __init__(self, path, s=\"/images/\"):\n        self.paths=glob(path+f\"{s}*.tif\")\n        self.paths.sort()\n        self.is_labeled = (s == \"/labels/\")\n    \n    def __len__(self):\n        return len(self.paths)\n    \n    def __getitem__(self,index):\n        img = cv2.imread(self.paths[index], cv2.IMREAD_GRAYSCALE)\n        img = Util.to_1024_1024(img, image_size=CFG.image_size)\n        \n        img = tc.from_numpy(img.copy())\n        if self.is_labeled:\n            img=img.to(tc.bool)\n        else:\n            img=img.to(tc.uint8)\n        return img","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_data(path, s):    \n    segmentation_ds = SegmentationDataset(path, s)\n    data_loader = DataLoader(segmentation_ds, batch_size=16, num_workers=2)\n    data = []\n    for x in tqdm(data_loader):\n        data.append(x)\n    x = tc.cat(data, dim=0)\n\n    # Chopping values above and below a certain percentile\n    TH = x.reshape(-1).numpy()\n    index = -int(len(TH) * CFG.chopping_percentile)\n    TH: int = np.partition(TH, index)[index]\n    x[x > TH] = int(TH)\n\n    TH = x.reshape(-1).numpy()\n    index = -int(len(TH) * CFG.chopping_percentile)\n    TH: int = np.partition(TH, -index)[-index]\n    x[x < TH] = int(TH)\n    return x","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path = \"/kaggle/input/blood-vessel-segmentation/train/kidney_2\"\nx = load_data(path, \"/images/\")","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Pipeline dataset","metadata":{}},{"cell_type":"code","source":"# Custom dataset to load image files\nclass Pipeline_Dataset(Dataset):\n    def __init__(self, x, path, in_chans):\n        self.img_paths  = glob(path+\"/images/*\")\n        self.img_paths.sort()\n        self.in_chan = in_chans\n        z = tc.zeros(self.in_chan // 2, *x.shape[1:], dtype=x.dtype)\n        self.x = tc.cat((z, x, z), dim=0)\n        \n    def __len__(self):\n        return self.x.shape[0]-self.in_chan+1\n    \n    def __getitem__(self, index):\n        x  = self.x[index:index+self.in_chan]\n        return x,index\n           \n    def get_marks(self):\n        ids=[]\n        for index in range(len(self.img_paths)):\n            img_id=self.img_paths[index].split(\"/\")[-3:]\n            img_id.pop(1)\n            img_id=\"_\".join(img_id)\n            _id = img_id[:-4]\n            ids.append(_id)\n        return ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model inference","metadata":{}},{"cell_type":"code","source":"def get_output(model, model2, model3, debug=False):\n    if debug:\n        paths=[\"/kaggle/input/blood-vessel-segmentation/train/kidney_2\"]\n    else:\n        paths=glob(\"/kaggle/input/blood-vessel-segmentation/test/*\")\n\n    # Outputs of image segmentation\n    outputs=[]\n    ids = []\n    for path in paths:\n        x = load_data(path, \"/images/\")\n        labels = tc.zeros_like(x, dtype=tc.uint8)\n        marks = Pipeline_Dataset(x, path, in_chans=1).get_marks()\n        # Go three dimension \n        for axis in [0,1,2]:\n            debug_count=0\n            if axis==0:\n                x_=x\n                labels_=labels\n            elif axis==1:\n                x_=x.permute(1,2,0)\n                labels_=labels.permute(1,2,0)\n            elif axis==2:\n                x_=x.permute(2,0,1)\n                labels_=labels.permute(2,0,1)\n            if x.shape[0]==3 and axis!=0:\n                break\n\n            # Create dataset and dataloader for processing\n            dataset=Pipeline_Dataset(x_, path, in_chans=1)\n            dataloader=DataLoader(dataset, batch_size=1, shuffle=False, num_workers=1)\n            shape=dataset.x.shape[-2:]\n\n            # Generate indices for processing tiles\n            x1_list = np.arange(0, shape[0]+CFG.tile_size-CFG.tile_size+1, CFG.stride)\n            y1_list = np.arange(0, shape[1]+CFG.tile_size-CFG.tile_size+1, CFG.stride)\n\n            # Loop through each image in the dataloader\n            for img,index in tqdm(dataloader):\n                img=img.to(\"cuda:0\")\n                img=Util.add_edge(img[0], CFG.tile_size//2)[None]\n\n                mask_pred = tc.zeros_like(img[:,0],dtype=tc.float32,device=img.device)\n                mask_count = tc.zeros_like(img[:,0],dtype=tc.float32,device=img.device)\n\n                indexs=[]\n                chip=[]\n                # Loop through each tile\n                for y1 in y1_list:\n                    for x1 in x1_list:\n                        x2 = x1 + CFG.tile_size\n                        y2 = y1 + CFG.tile_size\n                        indexs.append([x1+CFG.drop_egde_pixel, x2-CFG.drop_egde_pixel,\n                                       y1+CFG.drop_egde_pixel, y2-CFG.drop_egde_pixel])\n                        chip.append(img[...,x1:x2,y1:y2])\n\n                # Get predictions from the model (1024x1024)\n                y_preds = model.forward(tc.cat(chip)).to(device=0)\n                # We only apply weighted ensemble with model (512x512) on axis = 0 \n                if axis == CFG.axis_second_model:\n                    y_preds2 = model2.forward(tc.cat(chip)).to(device=0)\n                    y_preds3 = model3.forward(tc.cat(chip)).to(device=0)\n                    y_preds = (0.75 * y_preds + 0.25 * (0.8 * y_preds2 + 0.2 * y_preds3) )\n\n                # Drop the edge pixel\n                if CFG.drop_egde_pixel:\n                    y_preds=y_preds[..., CFG.drop_egde_pixel:-CFG.drop_egde_pixel,\n                                         CFG.drop_egde_pixel:-CFG.drop_egde_pixel]\n                # Drop rop_edge_pixel\n                for i, (x1,x2,y1,y2) in enumerate(indexs):\n                    mask_pred[..., x1:x2, y1:y2] += y_preds[i]\n                    mask_count[..., x1:x2, y1:y2] += 1\n\n                mask_pred /= mask_count\n\n                # Recover the region after processing\n                mask_pred = mask_pred[..., \n                                      CFG.tile_size//2:-CFG.tile_size//2, \n                                      CFG.tile_size//2:-CFG.tile_size//2]\n                # Update labels with the processed mask\n                labels_[index] += (mask_pred[0] * 255 * CFG.axis_w[axis]).to(tc.uint8).cpu()\n                # Visualize the result\n                if debug:\n                    debug_count+=1\n                    plt.subplot(121)\n                    plt.imshow(img[0,CFG.in_chans//2].cpu().detach().numpy())\n                    plt.subplot(122)\n                    plt.imshow(mask_pred[0].cpu().detach().numpy())\n                    plt.show()\n                    if debug_count>3:\n                        break\n        outputs.append(labels)\n        ids.extend(marks)\n        clear_memory()\n    return outputs, ids","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submission","metadata":{}},{"cell_type":"code","source":"# Check if it's for submission based on the presence of test images\n# Debug:  True for visualizing the results. False for submission only. \nis_submit = len(glob(\"/kaggle/input/blood-vessel-segmentation/test/kidney_5/images/*.tif\")) != 3\ndebug = (not is_submit)\nprint(f'is_submit = {is_submit}  debug = {debug}')\n#is_submit=True\n# Get segmentation output and associated ids\noutputs, ids = get_output(model, model2, model3, debug=debug)\n# print(f\" ids = {ids}\")\nclear_memory()\n\n# Calculate threshold for binary predictions\nTH=[x.flatten().numpy() for x in outputs]\nTH=np.concatenate(TH)\nindex = -int(len(TH) * CFG.th_percentile)\nTH:int = np.partition(TH, index)[index]\nprint(TH)\n\nimg = cv2.imread(\"/kaggle/input/blood-vessel-segmentation/test/kidney_5/images/0001.tif\",\n                 cv2.IMREAD_GRAYSCALE)\n\ndebug_count=0\nresults = []\n# Loop through each prediction and generate RLE encoding\nfor index in range(len(ids)):\n    _id = ids[index]\n\n    pos = 0\n    # Find the corresponding output based on the index\n    for x in outputs:\n        if index >= len(x):\n            index -= len(x)\n            pos += 1\n        else:\n            break\n    mask_pred = (outputs[pos][index]>TH).numpy()\n\n    mask_pred2 = Util.to_original_img(mask_pred, img, image_size=1024)\n    mask_pred =  mask_pred2.copy()\n\n    #Visualize the results\n    if debug:\n        plt.subplot(121)\n        plt.imshow(mask_pred)\n        plt.show()\n        debug_count+=1\n        if debug_count>6:\n            break\n\n    rle = Util.rle_encode(mask_pred)\n\n    results.append({\n        'id': _id,\n        'rle': rle,\n    })\n    \n    clear_memory()","metadata":{"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = pd.DataFrame(results)\nsubmission_df.to_csv('submission.csv', index=False)\nsubmission_df.head(6)","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}