{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"## HuBMAP Inference\n\n### version1,2: legacy version\n\n### version3: [my public train code](https://www.kaggle.com/code/itsuki9180/hubmap-train)\n\n### version4: my code with a few changes. and using dilation. Please read [this discussion on dilation](https://www.kaggle.com/competitions/hubmap-hacking-the-human-vasculature/discussion/416901).","metadata":{"papermill":{"duration":0.005368,"end_time":"2023-06-29T10:00:01.484257","exception":false,"start_time":"2023-06-29T10:00:01.478889","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import os, glob\nimport sys\nimport json\nfrom PIL import Image\nfrom collections import Counter\n\nimport numpy as np\nimport pandas as pd\nimport plotly.express as px\nimport plotly.graph_objects as go\nimport tifffile as tiff\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nimport torch\nimport cv2\nfrom skimage.morphology import binary_dilation\n\nimport pandas as pd\n\nfrom sklearn.model_selection import KFold\n\nsys.path.append(\"/kaggle/input/detection-wheel\")","metadata":{"papermill":{"duration":5.786069,"end_time":"2023-06-29T10:00:07.275167","exception":false,"start_time":"2023-06-29T10:00:01.489098","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:18.771063Z","iopub.execute_input":"2023-07-02T10:46:18.771447Z","iopub.status.idle":"2023-07-02T10:46:18.780178Z","shell.execute_reply.started":"2023-07-02T10:46:18.771411Z","shell.execute_reply":"2023-07-02T10:46:18.779076Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Install pycocotools package\nimport os\n!mkdir /kaggle/working/packages\n!cp -r /kaggle/input/pycocotools/* /kaggle/working/packages\nos.chdir(\"/kaggle/working/packages/pycocotools-2.0.6/\")\n!python setup.py install -q\n!pip install . --no-index --find-links /kaggle/working/packages/ -q\nos.chdir(\"/kaggle/working\")","metadata":{"papermill":{"duration":49.432987,"end_time":"2023-06-29T10:00:56.713456","exception":false,"start_time":"2023-06-29T10:00:07.280469","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:19.400621Z","iopub.execute_input":"2023-07-02T10:46:19.400987Z","iopub.status.idle":"2023-07-02T10:46:58.567462Z","shell.execute_reply.started":"2023-07-02T10:46:19.400956Z","shell.execute_reply":"2023-07-02T10:46:58.566256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nimport typing as t\nimport zlib\n\ndef encode_binary_mask(mask: np.ndarray) -> t.Text:\n  \"\"\"Converts a binary mask into OID challenge encoding ascii text.\"\"\"\n\n  # check input mask --\n  if mask.dtype != np.bool:\n    raise ValueError(\n        \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n        mask.dtype)\n\n  mask = np.squeeze(mask)\n  if len(mask.shape) != 2:\n    raise ValueError(\n        \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n        mask.shape)\n\n  # convert input mask to expected COCO API input --\n  mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n  mask_to_encode = mask_to_encode.astype(np.uint8)\n  mask_to_encode = np.asfortranarray(mask_to_encode)\n\n  # RLE encode mask --\n  encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n  # compress and base64 encoding --\n  binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION)\n  base64_str = base64.b64encode(binary_str)\n  return base64_str","metadata":{"papermill":{"duration":0.023871,"end_time":"2023-06-29T10:00:56.743656","exception":false,"start_time":"2023-06-29T10:00:56.719785","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.570491Z","iopub.execute_input":"2023-07-02T10:46:58.570904Z","iopub.status.idle":"2023-07-02T10:46:58.583714Z","shell.execute_reply.started":"2023-07-02T10:46:58.57086Z","shell.execute_reply":"2023-07-02T10:46:58.582627Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport numpy as np\nimport torch\nfrom PIL import Image\n\n\nclass PennFudanDataset(torch.utils.data.Dataset):\n    def __init__(self, imgs, transforms):\n        self.transforms = transforms\n        # load all image files, sorting them to\n        # ensure that they are aligned\n        self.imgs = imgs\n        self.name_indices = [os.path.splitext(os.path.basename(i))[0] for i in imgs]\n\n    def __getitem__(self, idx):\n        # load images and masks\n        img_path = self.imgs[idx]\n        name = self.name_indices[idx]\n        array = tiff.imread(img_path)\n        img = Image.fromarray(array)\n        \n        img, _ = self.transforms(img, img)\n\n        return img, name\n\n    def __len__(self):\n        return len(self.imgs)","metadata":{"papermill":{"duration":0.016653,"end_time":"2023-06-29T10:00:56.766343","exception":false,"start_time":"2023-06-29T10:00:56.74969","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.585253Z","iopub.execute_input":"2023-07-02T10:46:58.585804Z","iopub.status.idle":"2023-07-02T10:46:58.601638Z","shell.execute_reply.started":"2023-07-02T10:46:58.585771Z","shell.execute_reply":"2023-07-02T10:46:58.600772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection.mask_rcnn import MaskRCNNPredictor\n\ndef get_model_instance_segmentation(num_classes):\n    # load an instance segmentation model pre-trained on COCO\n    model = torchvision.models.detection.maskrcnn_resnet50_fpn_v2(weights=None, weights_backbone=None)\n\n    # get number of input features for the classifier\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\n    # replace the pre-trained head with a new one\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n\n    # now get the number of input features for the mask classifier\n    in_features_mask = model.roi_heads.mask_predictor.conv5_mask.in_channels\n    hidden_layer = 256\n    # and replace the mask predictor with a new one\n    model.roi_heads.mask_predictor = MaskRCNNPredictor(in_features_mask,\n                                                       hidden_layer,\n                                                       num_classes)\n\n    return model","metadata":{"papermill":{"duration":0.237756,"end_time":"2023-06-29T10:00:57.010126","exception":false,"start_time":"2023-06-29T10:00:56.77237","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.605788Z","iopub.execute_input":"2023-07-02T10:46:58.606095Z","iopub.status.idle":"2023-07-02T10:46:58.613678Z","shell.execute_reply.started":"2023-07-02T10:46:58.606068Z","shell.execute_reply":"2023-07-02T10:46:58.612669Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import transforms as T\n\ndef get_transform(train):\n    transforms = []\n    transforms.append(T.PILToTensor())\n    transforms.append(T.ConvertImageDtype(torch.float))\n    return T.Compose(transforms)","metadata":{"papermill":{"duration":0.02538,"end_time":"2023-06-29T10:00:57.042373","exception":false,"start_time":"2023-06-29T10:00:57.016993","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.615235Z","iopub.execute_input":"2023-07-02T10:46:58.615565Z","iopub.status.idle":"2023-07-02T10:46:58.626974Z","shell.execute_reply.started":"2023-07-02T10:46:58.615535Z","shell.execute_reply":"2023-07-02T10:46:58.625912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from engine import train_one_epoch, evaluate\nimport utils","metadata":{"papermill":{"duration":0.034062,"end_time":"2023-06-29T10:00:57.082458","exception":false,"start_time":"2023-06-29T10:00:57.048396","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.630031Z","iopub.execute_input":"2023-07-02T10:46:58.630328Z","iopub.status.idle":"2023-07-02T10:46:58.636739Z","shell.execute_reply.started":"2023-07-02T10:46:58.630305Z","shell.execute_reply":"2023-07-02T10:46:58.635861Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","metadata":{"papermill":{"duration":0.076016,"end_time":"2023-06-29T10:00:57.164596","exception":false,"start_time":"2023-06-29T10:00:57.08858","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.63826Z","iopub.execute_input":"2023-07-02T10:46:58.63865Z","iopub.status.idle":"2023-07-02T10:46:58.645888Z","shell.execute_reply.started":"2023-07-02T10:46:58.63862Z","shell.execute_reply":"2023-07-02T10:46:58.644932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = get_model_instance_segmentation(num_classes=2)\nmodel.to(device)\nmodel.load_state_dict(torch.load('/kaggle/input/hubmap-well-tuned/well_tuned_weight.pth'))\nmodel.eval()\nprint()","metadata":{"papermill":{"duration":5.876511,"end_time":"2023-06-29T10:01:03.047204","exception":false,"start_time":"2023-06-29T10:00:57.170693","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:58.647172Z","iopub.execute_input":"2023-07-02T10:46:58.647634Z","iopub.status.idle":"2023-07-02T10:46:59.591498Z","shell.execute_reply.started":"2023-07-02T10:46:58.647602Z","shell.execute_reply":"2023-07-02T10:46:59.590517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"all_imgs = glob.glob('/kaggle/input/hubmap-hacking-the-human-vasculature/test/*.tif')\ndataset_test = PennFudanDataset(all_imgs, get_transform(train=False))\ntest_dl = torch.utils.data.DataLoader(\n        dataset_test, batch_size=1, shuffle=False, num_workers=os.cpu_count(), pin_memory=True)","metadata":{"papermill":{"duration":0.016843,"end_time":"2023-06-29T10:01:03.070463","exception":false,"start_time":"2023-06-29T10:01:03.05362","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:59.592826Z","iopub.execute_input":"2023-07-02T10:46:59.593499Z","iopub.status.idle":"2023-07-02T10:46:59.600493Z","shell.execute_reply.started":"2023-07-02T10:46:59.593466Z","shell.execute_reply":"2023-07-02T10:46:59.59956Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids = []\nheights = []\nwidths = []\nprediction_strings = []","metadata":{"papermill":{"duration":0.014383,"end_time":"2023-06-29T10:01:03.091316","exception":false,"start_time":"2023-06-29T10:01:03.076933","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:46:59.604805Z","iopub.execute_input":"2023-07-02T10:46:59.605618Z","iopub.status.idle":"2023-07-02T10:46:59.610337Z","shell.execute_reply.started":"2023-07-02T10:46:59.605576Z","shell.execute_reply":"2023-07-02T10:46:59.60918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def TTA(x:torch.Tensor,model):\n    #x.shape=(batch,c,h,w)\n    shape=x.shape\n    x=[x,*[torch.rot90(x,k=i,dims=(-2,-1)) for i in range(1,4)]]\n    x=torch.cat(x,dim=0)\n    x=model(x)\n    return x","metadata":{"execution":{"iopub.status.busy":"2023-07-02T10:49:29.309526Z","iopub.execute_input":"2023-07-02T10:49:29.310526Z","iopub.status.idle":"2023-07-02T10:49:29.318984Z","shell.execute_reply.started":"2023-07-02T10:49:29.310485Z","shell.execute_reply":"2023-07-02T10:49:29.318057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"binary_dilation()函数的默认参数如下：\n\nstructure:用于膨胀操作的结构元素，默认为3x3的矩形结构元素。\n\niterations:膨胀操作的迭代次数，默认为1。\n\nmask:用于指定待处理图像的掩码，如果不指定则使用原始图像。\n\nborder_value:边界像素的值，默认为0。\n\n其中，结构元素是用于定义膨胀操作的形状和大小的二维数组，它可以是一个正方形、矩形、圆形等形状。迭代次数表示膨胀操作需要重复执行的次数，以达到期望的效果。掩码用于指定待处理图像中需要进行膨胀操作的部分，而边界像素的值则表示在膨胀操作过程中未被处理的像素点的值。","metadata":{}},{"cell_type":"code","source":"sample = None\nwith torch.no_grad():\n    for img, idx in test_dl:\n        img = img.to(device)\n        pred = model(img)\n#         img = img.cpu().numpy()\n        pred = TTA(img,model)\n#         print(pred)\n        \n        if sample is None: sample=pred\n        pred_string = ''\n        for m in range(len(pred[0]['masks'])):\n            mask = pred[0]['masks'][m].detach().permute(1,2,0).cpu().numpy()\n            mask = np.where(mask>0.5, 1, 0).astype(np.bool)\n#             mask = binary_dilation(mask)\n            \n            score = pred[0]['scores'][m].detach().cpu().numpy()\n            encoded = encode_binary_mask(mask)\n            if m==0:\n                pred_string += f\"0 {score} {encoded.decode('utf-8')}\"\n\n            else:\n                pred_string += f\" 0 {score} {encoded.decode('utf-8')}\"\n        b, c, h, w = img.shape\n        ids.append(idx[0])\n        heights.append(h)\n        widths.append(w)\n        prediction_strings.append(pred_string)","metadata":{"papermill":{"duration":5.439978,"end_time":"2023-06-29T10:01:08.537509","exception":false,"start_time":"2023-06-29T10:01:03.097531","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:49:30.819083Z","iopub.execute_input":"2023-07-02T10:49:30.819912Z","iopub.status.idle":"2023-07-02T10:49:31.835533Z","shell.execute_reply.started":"2023-07-02T10:49:30.819869Z","shell.execute_reply":"2023-07-02T10:49:31.834476Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"array = tiff.imread('/kaggle/input/hubmap-hacking-the-human-vasculature/test/72e40acccadf.tif')\nplt.imshow(array)\nplt.show()","metadata":{"papermill":{"duration":0.358831,"end_time":"2023-06-29T10:01:08.90296","exception":false,"start_time":"2023-06-29T10:01:08.544129","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:49:33.946611Z","iopub.execute_input":"2023-07-02T10:49:33.947785Z","iopub.status.idle":"2023-07-02T10:49:34.275684Z","shell.execute_reply.started":"2023-07-02T10:49:33.947736Z","shell.execute_reply":"2023-07-02T10:49:34.274783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if len(all_imgs)==1:\n    top20 = [sample[0]['masks'][i].cpu().numpy().reshape(512, 512) for i in range(min(20,len(sample[0]['masks'])))]\n    \n    pred_img = np.zeros((512,512), dtype=np.float32)\n    for i, j in enumerate(top20):\n        pred_img += j * (1 - 1/len(top20)*i)\n        pred_img = np.clip(pred_img, 0, 1)\n        print(sample[0]['scores'][i].cpu().numpy())\n        plt.imshow(j)\n        plt.show()\n        \n    plt.imshow(pred_img)\n    plt.show()","metadata":{"papermill":{"duration":4.935438,"end_time":"2023-06-29T10:01:13.848981","exception":false,"start_time":"2023-06-29T10:01:08.913543","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:49:34.360743Z","iopub.execute_input":"2023-07-02T10:49:34.362977Z","iopub.status.idle":"2023-07-02T10:49:39.464988Z","shell.execute_reply.started":"2023-07-02T10:49:34.362947Z","shell.execute_reply":"2023-07-02T10:49:39.463923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame()\nsubmission['id'] = ids\nsubmission['height'] = heights\nsubmission['width'] = widths\nsubmission['prediction_string'] = prediction_strings\nsubmission = submission.set_index('id')\nsubmission.to_csv(\"submission.csv\")\nsubmission.head()","metadata":{"papermill":{"duration":0.050056,"end_time":"2023-06-29T10:01:13.917769","exception":false,"start_time":"2023-06-29T10:01:13.867713","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-07-02T10:49:39.466953Z","iopub.execute_input":"2023-07-02T10:49:39.467317Z","iopub.status.idle":"2023-07-02T10:49:39.50196Z","shell.execute_reply.started":"2023-07-02T10:49:39.467284Z","shell.execute_reply":"2023-07-02T10:49:39.500978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}