{"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":61446,"databundleVersionId":6962461,"sourceType":"competition"},{"sourceId":154515748,"sourceType":"kernelVersion"}],"dockerImageVersionId":30627,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\n\nimport pandas as pd\nimport torch as tc\nimport torch\nimport torch.nn as nn\nfrom dotenv import load_dotenv\nimport torch.nn.functional as F\nimport cv2\n\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom glob import glob\nfrom tqdm import tqdm\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.cuda.amp import autocast\nfrom torchvision.transforms import functional as F_t\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.metrics import roc_auc_score\nimport segmentation_models_pytorch as smp\nfrom torch.nn import DataParallel\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:12.289567Z","iopub.execute_input":"2023-12-16T19:16:12.289894Z","iopub.status.idle":"2023-12-16T19:16:21.643788Z","shell.execute_reply.started":"2023-12-16T19:16:12.289868Z","shell.execute_reply":"2023-12-16T19:16:21.642643Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nclass CFG:\n    model_name = 'Unet'\n    backbone = 'se_resnext50_32x4d'\n    in_chans = 5\n    image_size = 512\n    input_size = image_size  \n    tile_size = image_size\n    stride = tile_size // 2\n    drop_egde_pixel = 0\n    target_size = 1\n    valid_id = 1\n    batch = 128\n    th_percentile = 0.0021\n    model_path = [\"/kaggle/input/2-5d-cutting-model-baseline-training/se_resnext50_32x4d_9_loss0.01_score0.82_val_loss0.02_val_score0.80.pt\"]\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:12.246856Z","iopub.execute_input":"2023-12-16T19:16:12.247297Z","iopub.status.idle":"2023-12-16T19:16:12.288129Z","shell.execute_reply.started":"2023-12-16T19:16:12.247254Z","shell.execute_reply":"2023-12-16T19:16:12.287150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Cell 2: Model Definition\nimport torch.nn.functional as F\n\nclass CustomModel(nn.Module):\n    def __init__(self, CFG, weight=None):\n        super().__init__()\n        self.CFG = CFG\n        self.encoder = smp.Unet(\n            encoder_name=CFG.backbone, \n            encoder_weights=weight,\n            in_channels=CFG.in_chans,\n            classes=CFG.target_size,\n            activation=None,\n        )\n        self.batch = CFG.batch\n\n    def forward_(self, image):\n        output = self.encoder(image)\n        return output[:, 0]\n    \n    def forward(self, x: tc.Tensor):\n        x = x.to(tc.float32)\n        x = normalization(x, 1)\n        \n        if CFG.input_size != CFG.image_size:\n            x = nn.functional.interpolate(x, size=(CFG.input_size, CFG.input_size), mode='bilinear', align_corners=True)\n        \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        \n        with autocast():\n            with tc.no_grad():\n                x = [self.forward_(x[i * self.batch:(i + 1) * self.batch]) for i in range(x.shape[0] // self.batch + 1)]\n                x = tc.cat(x, dim=0)\n        \n        x = x.sigmoid()\n        x = x.reshape(4, shape[0], *shape[2:])\n        x = [tc.rot90(x[i], k=-i, dims=(-2, -1)) for i in range(4)]\n        x = tc.stack(x, dim=0).mean(0)\n        \n        if CFG.input_size != CFG.image_size:\n            x = nn.functional.interpolate(x[None], size=(CFG.image_size, CFG.image_size), mode='bilinear', align_corners=True)[0]\n        \n        return x\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:21.645786Z","iopub.execute_input":"2023-12-16T19:16:21.646133Z","iopub.status.idle":"2023-12-16T19:16:21.659662Z","shell.execute_reply.started":"2023-12-16T19:16:21.646097Z","shell.execute_reply":"2023-12-16T19:16:21.658706Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef 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 1'\n    return rle\n\ndef normalization(x:tc.Tensor, smooth=1e-7)->tc.Tensor:\n    \"\"\"input.shape=(batch,f1,f2,...)\"\"\"\n    dim = list(range(1, x.ndim))\n    mean = x.mean(dim=dim, keepdim=True)\n    std = x.std(dim=dim, keepdim=True)\n    return (x - mean) / (std + smooth)\n\nclass Data_loader(Dataset):\n    def __init__(self, path, s=\"/images/\"):\n        self.paths = glob(path + f\"{s}*.tif\")\n        self.paths.sort()\n        self.bool = 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 = tc.from_numpy(img)\n        if self.bool:\n            img = img.to(tc.bool)\n        else:\n            img = img.to(tc.uint8)\n        return img\n\ndef load_data(path, s):\n    data_loader = Data_loader(path, s)\n    data_loader = DataLoader(data_loader, 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    return x\n\nclass Pipeline_Dataset(Dataset):\n    def __init__(self, x, path):\n        self.img_paths = glob(path + \"/images/*\")\n        self.img_paths.sort()\n        # assert int(self.img_paths[-1].split(\"/\")[-1][:-4]) + 1 == len(x)  # It seems not the same\n        self.in_chan = CFG.in_chans\n        z = torch.zeros(self.in_chan // 2, *x.shape[1:], dtype=x.dtype)\n        self.x = torch.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_mark(self, index):\n        id = self.img_paths[index].split(\"/\")[-3:]\n        id.pop(1)\n        id = \"_\".join(id)\n        return id[:-4]\n\n    def get_marks(self):\n        ids = []\n        for index in range(len(self)):\n            ids.append(self.get_mark(index))\n        return ids\n\n\ndef 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","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:21.661092Z","iopub.execute_input":"2023-12-16T19:16:21.661475Z","iopub.status.idle":"2023-12-16T19:16:21.682357Z","shell.execute_reply.started":"2023-12-16T19:16:21.661442Z","shell.execute_reply":"2023-12-16T19:16:21.681379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef build_model(weight=None):\n    load_dotenv()\n\n    print('model_name', CFG.model_name)\n    print('backbone', CFG.backbone)\n\n    model = CustomModel(CFG, weight)\n\n    return model.cuda()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:21.684841Z","iopub.execute_input":"2023-12-16T19:16:21.685468Z","iopub.status.idle":"2023-12-16T19:16:21.694565Z","shell.execute_reply.started":"2023-12-16T19:16:21.685434Z","shell.execute_reply":"2023-12-16T19:16:21.693756Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_output(debug=False):\n    outputs = []\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    outputs = [[], []]\n    for path in paths:\n        x = load_data(path, \"/images/\")\n        labels = torch.zeros_like(x, dtype=torch.uint8)\n        mark = Pipeline_Dataset(x, path).get_marks()\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            dataset = Pipeline_Dataset(x_, path)\n            dataloader = DataLoader(dataset, batch_size=1, shuffle=False, num_workers=2)\n            shape = dataset.x.shape[-2:]\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            for img, index in tqdm(dataloader):\n                # img=(1,C,H,W)\n                img = img.to(\"cuda:0\")\n                img = add_edge(img[0], CFG.tile_size // 2)[None]\n\n                mask_pred = torch.zeros_like(img[:, 0], dtype=torch.float32, device=img.device)\n                mask_count = torch.zeros_like(img[:, 0], dtype=torch.float32, device=img.device)\n\n                indexs = []\n                chip = []\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                y_preds = model.forward(torch.cat(chip)).to(device=0)\n\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                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\n                mask_pred = mask_pred[..., CFG.tile_size // 2:-CFG.tile_size // 2, CFG.tile_size // 2:-CFG.tile_size // 2]\n\n                labels_[index] += (mask_pred[0] * 255 / 3).to(torch.uint8).cpu()\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[0].append(labels)\n            outputs[1].extend(mark)\n    return outputs\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:21.695941Z","iopub.execute_input":"2023-12-16T19:16:21.696244Z","iopub.status.idle":"2023-12-16T19:16:21.715443Z","shell.execute_reply.started":"2023-12-16T19:16:21.696219Z","shell.execute_reply":"2023-12-16T19:16:21.714525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the model\nmodel = build_model()\nmodel.load_state_dict(tc.load(CFG.model_path[0], map_location='cpu'), strict=False)\nmodel = DataParallel(model)\n\n# Move the model to the GPU if available\nif tc.cuda.is_available():\n    model = model.cuda()\n    \nis_submit = len(glob(\"/kaggle/input/blood-vessel-segmentation/test/kidney_5/images/*.tif\")) != 3\n\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:21.716586Z","iopub.execute_input":"2023-12-16T19:16:21.716900Z","iopub.status.idle":"2023-12-16T19:16:26.603109Z","shell.execute_reply.started":"2023-12-16T19:16:21.716874Z","shell.execute_reply":"2023-12-16T19:16:26.602205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\noutput, ids = get_output(not is_submit)\n\n\n# Thresholding\nTH = [x.flatten().numpy() for x in output]\nTH = np.concatenate(TH)\nindex = -int(len(TH) * CFG.th_percentile)\nTH = int(np.partition(TH, index)[index])\nprint(TH)\n\n","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:16:26.604325Z","iopub.execute_input":"2023-12-16T19:16:26.604642Z","iopub.status.idle":"2023-12-16T19:19:23.400786Z","shell.execute_reply.started":"2023-12-16T19:16:26.604613Z","shell.execute_reply":"2023-12-16T19:19:23.399641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nsubmission_df = []\ndebug_count = 0\nfor index in range(len(ids)):\n    id = ids[index]\n    i = 0\n    for x in output:\n        if index >= len(x):\n            index -= len(x)\n            i += 1\n        else:\n            break\n    \n    mask_pred = (output[i][index] > TH).numpy()\n    \n    if not is_submit:\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 = rle_encode(mask_pred)\n    \n    submission_df.append(\n        pd.DataFrame(data={\n            'id': id,\n            'rle': rle,\n        }, index=[0])\n    )\n\nsubmission_df = pd.concat(submission_df)\nsubmission_df.to_csv('submission.csv', index=False)\nsubmission_df.head(6)","metadata":{"execution":{"iopub.status.busy":"2023-12-16T19:19:23.402195Z","iopub.execute_input":"2023-12-16T19:19:23.402503Z","iopub.status.idle":"2023-12-16T19:19:26.590456Z","shell.execute_reply.started":"2023-12-16T19:19:23.402476Z","shell.execute_reply":"2023-12-16T19:19:26.589527Z"},"trusted":true},"execution_count":null,"outputs":[]}]}