{"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":[{"sourceType":"competition","sourceId":61446,"databundleVersionId":6962461,"isSourceIdPinned":false}],"dockerImageVersionId":30627,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"This is an example submission code for [this work](https://www.kaggle.com/code/aniketkolte04/sennet-hoa-seg-pytorch-attention-gated-unet). \n\nAccelerator : GPU T4 x2","metadata":{}},{"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset\nfrom torchvision import transforms\nimport tifffile as tiff\nimport cv2\nimport torch.nn as nn\nimport albumentations as A\nimport numpy as np\nimport os\nimport time\nimport torch.nn.functional as F\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom sklearn.model_selection import train_test_split\nfrom torch.utils.data import DataLoader\n\nfrom pprint import pprint\nimport pandas as pd\nimport time\n\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2026-05-16T07:41:25.540567Z","iopub.execute_input":"2026-05-16T07:41:25.540827Z","iopub.status.idle":"2026-05-16T07:41:31.987274Z","shell.execute_reply.started":"2026-05-16T07:41:25.540804Z","shell.execute_reply":"2026-05-16T07:41:31.986541Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"base_pth = '/kaggle/input/blood-vessel-segmentation/test'  \ndatasets = ['kidney_5', 'kidney_6'] \n\nimg_pths = []\nfor dataset in datasets:\n    img_dir = os.path.join(base_pth, dataset, 'images')\n    img_pths += sorted([os.path.join(img_dir, f) for f in os.listdir(img_dir) if f.endswith('.tif')])\nimg_pths","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:31.988815Z","iopub.execute_input":"2026-05-16T07:41:31.989297Z","iopub.status.idle":"2026-05-16T07:41:32.008129Z","shell.execute_reply.started":"2026-05-16T07:41:31.989272Z","shell.execute_reply":"2026-05-16T07:41:32.007448Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# test dataset","metadata":{}},{"cell_type":"code","source":"def preprocess_image(path):\n    img = cv2.imread(path, cv2.IMREAD_UNCHANGED)\n    org_size = img.shape\n    \n    img = np.tile(img[...,None],[1, 1, 3]) \n    img = img.astype('float32') \n    mx = np.max(img)\n    if mx:\n        img/=mx \n        \n    img = np.transpose(img, (2, 0, 1))\n    img_ten = torch.tensor(img)\n    return img_ten, org_size\n\n\nclass CustomDataset(Dataset):\n    def __init__(self, img_pths, input_size=(256, 256)):\n        self.img_pths = img_pths\n        self.input_size = input_size\n\n    def __len__(self):\n        return len(self.img_pths)\n\n    def __getitem__(self, idx):\n        img_pth = self.img_pths[idx]\n        img, size = preprocess_image(img_pth)\n        \n        #resize\n        image_np = img.permute(1, 2, 0).numpy()\n        transform = A.Compose([\n            A.Resize(512,512, interpolation=cv2.INTER_NEAREST),\n        ])\n        \n        augmented_image = torch.tensor(\n            transform(image=image_np)['image'], dtype=torch.float32\n        ).permute(2, 0, 1)\n        \n        return augmented_image, size\n    \ntest_dataset = CustomDataset(img_pths)\ntest_dataloader = DataLoader(test_dataset, batch_size=1, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:32.009043Z","iopub.execute_input":"2026-05-16T07:41:32.009344Z","iopub.status.idle":"2026-05-16T07:41:32.017053Z","shell.execute_reply.started":"2026-05-16T07:41:32.009315Z","shell.execute_reply":"2026-05-16T07:41:32.016224Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# model architecture","metadata":{}},{"cell_type":"code","source":"class ConvBlock(nn.Module):\n\n    def __init__(self, in_channels, out_channels):\n        super(ConvBlock, self).__init__()\n\n        self.conv = nn.Sequential(\n            nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True),\n            nn.BatchNorm2d(out_channels),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True),\n            nn.BatchNorm2d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        x = self.conv(x)\n        return x\n\n\nclass UpConv(nn.Module):\n\n    def __init__(self, in_channels, out_channels):\n        super(UpConv, self).__init__()\n\n        self.up = nn.Sequential(\n            nn.Upsample(scale_factor=2),\n            nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=True),\n            nn.BatchNorm2d(out_channels),\n            nn.ReLU(inplace=True)\n        )\n\n    def forward(self, x):\n        x = self.up(x)\n        return x\n\n\nclass AttentionBlock(nn.Module):\n    \"\"\"Attention block with learnable parameters\"\"\"\n\n    def __init__(self, F_g, F_l, n_coefficients):\n        \"\"\"\n        :param F_g: number of feature maps (channels) in previous layer\n        :param F_l: number of feature maps in corresponding encoder layer, transferred via skip connection\n        :param n_coefficients: number of learnable multi-dimensional attention coefficients\n        \"\"\"\n        super(AttentionBlock, self).__init__()\n\n        self.W_gate = nn.Sequential(\n            nn.Conv2d(F_g, n_coefficients, kernel_size=1, stride=1, padding=0, bias=True),\n            nn.BatchNorm2d(n_coefficients)\n        )\n\n        self.W_x = nn.Sequential(\n            nn.Conv2d(F_l, n_coefficients, kernel_size=1, stride=1, padding=0, bias=True),\n            nn.BatchNorm2d(n_coefficients)\n        )\n\n        self.psi = nn.Sequential(\n            nn.Conv2d(n_coefficients, 1, kernel_size=1, stride=1, padding=0, bias=True),\n            nn.BatchNorm2d(1),\n            nn.Sigmoid()\n        )\n\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, gate, skip_connection):\n        \"\"\"\n        :param gate: gating signal from previous layer\n        :param skip_connection: activation from corresponding encoder layer\n        :return: output activations\n        \"\"\"\n        g1 = self.W_gate(gate)\n        x1 = self.W_x(skip_connection)\n        psi = self.relu(g1 + x1)\n        psi = self.psi(psi)\n        out = skip_connection * psi\n        return out\n\n\nclass AttentionUNet(nn.Module):\n\n    def __init__(self, img_ch=3, output_ch=1):\n        super(AttentionUNet, self).__init__()\n\n        self.MaxPool = nn.MaxPool2d(kernel_size=2, stride=2)\n\n        self.Conv1 = ConvBlock(img_ch, 64)\n        self.Conv2 = ConvBlock(64, 128)\n        self.Conv3 = ConvBlock(128, 256)\n        self.Conv4 = ConvBlock(256, 512)\n        self.Conv5 = ConvBlock(512, 1024)\n\n        self.Up5 = UpConv(1024, 512)\n        self.Att5 = AttentionBlock(F_g=512, F_l=512, n_coefficients=256)\n        self.UpConv5 = ConvBlock(1024, 512)\n\n        self.Up4 = UpConv(512, 256)\n        self.Att4 = AttentionBlock(F_g=256, F_l=256, n_coefficients=128)\n        self.UpConv4 = ConvBlock(512, 256)\n\n        self.Up3 = UpConv(256, 128)\n        self.Att3 = AttentionBlock(F_g=128, F_l=128, n_coefficients=64)\n        self.UpConv3 = ConvBlock(256, 128)\n\n        self.Up2 = UpConv(128, 64)\n        self.Att2 = AttentionBlock(F_g=64, F_l=64, n_coefficients=32)\n        self.UpConv2 = ConvBlock(128, 64)\n\n        self.Conv = nn.Conv2d(64, output_ch, kernel_size=1, stride=1, padding=0)\n\n    def forward(self, x):\n        \"\"\"\n        e : encoder layers\n        d : decoder layers\n        s : skip-connections from encoder layers to decoder layers\n        \"\"\"\n        e1 = self.Conv1(x)\n\n        e2 = self.MaxPool(e1)\n        e2 = self.Conv2(e2)\n\n        e3 = self.MaxPool(e2)\n        e3 = self.Conv3(e3)\n\n        e4 = self.MaxPool(e3)\n        e4 = self.Conv4(e4)\n\n        e5 = self.MaxPool(e4)\n        e5 = self.Conv5(e5)\n\n        d5 = self.Up5(e5)\n\n        s4 = self.Att5(gate=d5, skip_connection=e4)\n        d5 = torch.cat((s4, d5), dim=1) \n        d5 = self.UpConv5(d5)\n\n        d4 = self.Up4(d5)\n        s3 = self.Att4(gate=d4, skip_connection=e3)\n        d4 = torch.cat((s3, d4), dim=1)\n        d4 = self.UpConv4(d4)\n\n        d3 = self.Up3(d4)\n        s2 = self.Att3(gate=d3, skip_connection=e2)\n        d3 = torch.cat((s2, d3), dim=1)\n        d3 = self.UpConv3(d3)\n\n        d2 = self.Up2(d3)\n        s1 = self.Att2(gate=d2, skip_connection=e1)\n        d2 = torch.cat((s1, d2), dim=1)\n        d2 = self.UpConv2(d2)\n\n        out = self.Conv(d2)\n\n        return out","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:32.018313Z","iopub.execute_input":"2026-05-16T07:41:32.018837Z","iopub.status.idle":"2026-05-16T07:41:32.037574Z","shell.execute_reply.started":"2026-05-16T07:41:32.018802Z","shell.execute_reply":"2026-05-16T07:41:32.036827Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# prediction","metadata":{}},{"cell_type":"code","source":"#Run-Length Encode and Decode\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = img.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    rle = ' '.join(str(x) for x in runs)\n    if rle == '':\n        return '1 0'\n    else:\n        return rle","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:32.038472Z","iopub.execute_input":"2026-05-16T07:41:32.039556Z","iopub.status.idle":"2026-05-16T07:41:32.050753Z","shell.execute_reply.started":"2026-05-16T07:41:32.039534Z","shell.execute_reply":"2026-05-16T07:41:32.049997Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = AttentionUNet()\nmodel.load_state_dict(\n    torch.load('/kaggle/input/training-results/trained_model_512x512.pth')\n)\nmodel.eval() \nmodel.to(device)\n\ncount = 0\ndata = []\nfor sample, size in iter(test_dataloader):\n    inputs = sample.to(device)\n    outputs = model(inputs)    \n    outputs = nn.Softmax(2)(outputs.view(*outputs.size()[:2], -1)).view_as(outputs) \n#     outputs_mask = torch.where(outputs>0.5, 1, 0)\n    outputs_mask = torch.where(outputs>0.00008, 1, 0)\n    \n    inputs_np = inputs[0][0].cpu().detach().numpy()*255.0\n    outputs_np = outputs[0][0].cpu().detach().numpy()\n    outputs_mask_np = outputs_mask[0][0].cpu().detach().numpy()\n    filename = img_pths[count].split('/')\n    \n    #resize back\n    transform_resize_back = A.Compose([\n        A.Resize(int(size[0]),int(size[1]), interpolation=cv2.INTER_NEAREST),\n    ])\n    \n    inputs_np = torch.tensor(transform_resize_back(image=inputs_np)['image']).numpy()\n    outputs_np = torch.tensor(transform_resize_back(image=outputs_np)['image']).numpy()\n    outputs_mask_np = torch.tensor(transform_resize_back(image=outputs_mask_np)['image']).numpy()\n\n    plt.figure(figsize=(15, 10))\n    \n    plt.subplot(2, 4, 1)\n    plt.imshow(inputs_np.astype('uint8'), cmap='gray')\n    plt.title(f\"input-{filename[-3]}/images/{filename[-1]}\")\n    \n    plt.subplot(2, 4, 2)\n    plt.imshow(outputs_np, cmap='hot', interpolation='nearest')\n#     plt.colorbar(shrink=0.5)\n    plt.colorbar()\n    plt.title(f\"output-{filename[-3]}/images/{filename[-1]}\")\n    \n    plt.subplot(2, 4, 3)\n    plt.imshow(outputs_mask_np.astype('uint8')*255, cmap='gray')\n    plt.title(f\"output mask-{filename[-3]}/images/{filename[-1]}\")\n    \n    plt.tight_layout()\n    plt.show()\n    \n    mask_rle = rle_encode(outputs_mask_np)\n    data.append([f'{filename[-3]}_{filename[-1][:-4]}', mask_rle])\n\n    print(f'{filename[-3]}_{filename[-1][:-4]}:', mask_rle)\n    count += 1","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:32.051780Z","iopub.execute_input":"2026-05-16T07:41:32.052068Z","iopub.status.idle":"2026-05-16T07:41:32.979570Z","shell.execute_reply.started":"2026-05-16T07:41:32.052037Z","shell.execute_reply":"2026-05-16T07:41:32.978134Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# sub.","metadata":{}},{"cell_type":"code","source":"df = pd.DataFrame(data, columns=['id', 'rle'])\ndf.to_csv('/kaggle/working/submission.csv', index=False)\n\ndf","metadata":{"execution":{"iopub.status.busy":"2026-05-16T07:41:32.980278Z","iopub.status.idle":"2026-05-16T07:41:32.980588Z","shell.execute_reply.started":"2026-05-16T07:41:32.980435Z","shell.execute_reply":"2026-05-16T07:41:32.980450Z"},"trusted":true},"outputs":[],"execution_count":null}]}