{"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":"# Description\nThis kernel provides a starter Pytorch code for inference that performs dividing the images into tiles([based on this kernel](https://www.kaggle.com/iafoss/256x256-images)), selection of tiles with tissue, evaluation of the predictions of multiple models with TTA, combining the tile masks back into image level masks, and conversion into RLE. The inference is performed based on models trained in the [fast.ai starter kernel](https://www.kaggle.com/iafoss/hubmap-fast-ai-starter), provided by me. I hope it will help you to get started with this competition.\n\n* Update (12/4): Fix problem with submission to private LB using **rasterio** (thanks to @leighplt for suggesting it in [his kernel](https://www.kaggle.com/leighplt/pytorch-fcn-resnet50)). For the prediction on the public part of the test set the predictions are identical except one of the images, where the new method predicts a mask different by several pixels, but the LB is the same. I think the tiles loaded by rasterio may be slightly different from ones loaded by tifffile for some image compressions.","metadata":{"papermill":{"duration":0.013125,"end_time":"2020-12-21T08:53:05.370939","exception":false,"start_time":"2020-12-21T08:53:05.357814","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!pip install --no-deps ../input/hubmap-packages/pretrained-models.pytorch-master/pretrained-models.pytorch-master > /dev/null","metadata":{"_kg_hide-output":true,"papermill":{"duration":30.038691,"end_time":"2020-12-21T08:53:35.421125","exception":false,"start_time":"2020-12-21T08:53:05.382434","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install --no-deps ../input/hubmap-packages/efficientnet_pytorch-0.6.3/efficientnet_pytorch-0.6.3 > /dev/null","metadata":{"_kg_hide-output":true,"papermill":{"duration":28.072931,"end_time":"2020-12-21T08:54:03.508695","exception":false,"start_time":"2020-12-21T08:53:35.435764","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install --no-deps ../input/hubmap-packages/timm-0.4.5-py3-none-any.whl > /dev/null","metadata":{"_kg_hide-output":true,"papermill":{"duration":27.126942,"end_time":"2020-12-21T08:54:30.651843","exception":false,"start_time":"2020-12-21T08:54:03.524901","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install --no-deps ../input/hubmap-packages/segmentation_models.pytorch-master/segmentation_models.pytorch-master > /dev/null","metadata":{"_kg_hide-output":true,"papermill":{"duration":28.355841,"end_time":"2020-12-21T08:54:59.027449","exception":false,"start_time":"2020-12-21T08:54:30.671608","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport tifffile as tiff\nimport cv2\nimport os\nimport gc\nfrom tqdm.notebook import tqdm\nimport rasterio\nfrom rasterio.windows import Window\n\nfrom fastai.vision.all import *\nfrom torch.cuda.amp import autocast\nfrom torch.utils.data import Dataset, DataLoader\nfrom typing import Optional, Union, List\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport timm\nfrom timm.models.layers import ConvBnAct, get_act_layer, create_act_layer, create_attn, create_conv2d\nfrom timm.models.cspnet import _create_cspnet\nimport segmentation_models_pytorch as smp\nimport segmentation_models_pytorch.base.modules as md\n\nimport pytorch_lightning as pl\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":4.409486,"end_time":"2020-12-21T08:55:03.456914","exception":false,"start_time":"2020-12-21T08:54:59.047428","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sz = 512   #the size of tiles\nstep = 176 #step size of sliding window\nreduce = 2 #reduce the original images by 4 times\nTH = 0.4  #threshold for positive predictions\nS_TH = 0.55\nDATA = '../input/hubmap-kidney-segmentation/test/'\ndf_sample = pd.read_csv('../input/hubmap-kidney-segmentation/sample_submission.csv')\nbs = 8\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"papermill":{"duration":0.040025,"end_time":"2020-12-21T08:55:03.516808","exception":false,"start_time":"2020-12-21T08:55:03.476783","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data","metadata":{"papermill":{"duration":0.019649,"end_time":"2020-12-21T08:55:03.555777","exception":false,"start_time":"2020-12-21T08:55:03.536128","status":"completed"},"tags":[]}},{"cell_type":"code","source":"#functions to convert encoding to mask and mask to encoding\ndef enc2mask(encs, shape):\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for m,enc in enumerate(encs):\n        if isinstance(enc,np.float) and np.isnan(enc): continue\n        s = enc.split()\n        for i in range(len(s)//2):\n            start = int(s[2*i]) - 1\n            length = int(s[2*i+1])\n            img[start:start+length] = 1 + m\n    return img.reshape(shape).T\n\ndef mask2enc(mask, n=1):\n    pixels = mask.T.flatten()\n    encs = []\n    for i in range(1,n+1):\n        p = (pixels == i).astype(np.int8)\n        if p.sum() == 0: encs.append(np.nan)\n        else:\n            p = np.concatenate([[0], p, [0]])\n            runs = np.where(p[1:] != p[:-1])[0] + 1\n            runs[1::2] -= runs[::2]\n            encs.append(' '.join(str(x) for x in runs))\n    return encs\n\n#https://www.kaggle.com/bguberfain/memory-aware-rle-encoding\n#with transposed mask\ndef rle_encode_less_memory(img):\n    #the image should be transposed\n    pixels = img.T.flatten()\n    \n    # This simplified method requires first and last pixel to be zero\n    pixels[0] = 0\n    pixels[-1] = 0\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 2\n    runs[1::2] -= runs[::2]\n    \n    return ' '.join(str(x) for x in runs)","metadata":{"_kg_hide-input":true,"papermill":{"duration":0.038021,"end_time":"2020-12-21T08:55:03.613335","exception":false,"start_time":"2020-12-21T08:55:03.575314","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# https://www.kaggle.com/iafoss/256x256-images\nmean = np.array([0.63701425, 0.47097038, 0.68173952])\nstd = np.array([0.15979014, 0.22442915, 0.14194921])\n\ns_th = 40  #saturation blancking threshold\np_th = 200*sz//256 #threshold for the minimum number of pixels\nidentity = rasterio.Affine(1, 0, 0, 0, 1, 0)\n\ndef img2tensor(img,dtype:np.dtype=np.float32):\n    if img.ndim==2 : img = np.expand_dims(img,2)\n    img = np.transpose(img,(2,0,1))\n    return torch.from_numpy(img.astype(dtype, copy=False))\n\nclass HuBMAPDataset(Dataset):\n    def __init__(self, idx, sz=sz, step=step, reduce=reduce):\n        self.data = rasterio.open(os.path.join(DATA,idx+'.tiff'), transform = identity,\n                                  num_threads='all_cpus')\n        if self.data.count != 3:\n            print('Image file with subdatasets as channels')\n            self.layers = [rasterio.open(subd) for subd in self.data.subdatasets]\n        self.shape = self.data.shape\n        self.reduce = reduce\n        self.sz = reduce*sz\n        self.step = reduce*step\n        self.pad0 = (self.sz - self.shape[0]%self.step)%self.step\n        self.pad1 = (self.sz - self.shape[1]%self.step)%self.step\n        self.n0max = (self.shape[0] + self.pad0 - self.sz)//self.step + 1\n        self.n1max = (self.shape[1] + self.pad1 - self.sz)//self.step + 1\n        \n    def __len__(self):\n        return self.n0max*self.n1max\n    \n    def __getitem__(self, idx):\n        # the code below may be a little bit difficult to understand,\n        # but the thing it does is mapping the original image to\n        # tiles created with adding padding, as done in\n        # https://www.kaggle.com/iafoss/256x256-images ,\n        # and then the tiles are loaded with rasterio\n        # n0,n1 - are the x and y index of the tile (idx = n0*self.n1max + n1)\n        n0,n1 = idx//self.n1max, idx%self.n1max\n        # x0,y0 - are the coordinates of the lower left corner of the tile in the image\n        # negative numbers correspond to padding (which must not be loaded)\n        x0,y0 = -self.pad0//2 + n0*self.step, -self.pad1//2 + n1*self.step\n        # make sure that the region to read is within the image\n        p00,p01 = max(0,x0), min(x0+self.sz,self.shape[0])\n        p10,p11 = max(0,y0), min(y0+self.sz,self.shape[1])\n        img = np.zeros((self.sz,self.sz,3),np.uint8)\n        # mapping the loaded region to the tile\n        if self.data.count == 3:\n            img[(p00-x0):(p01-x0),(p10-y0):(p11-y0)] = np.moveaxis(self.data.read([1,2,3],\n                    window=Window.from_slices((p00,p01),(p10,p11))), 0, -1)\n        else:\n            tile = np.zeros((p01-p00, p11-p10, 3), dtype=np.uint8)\n            for fl in range(3):\n                tile[:,:,fl] = self.layers[fl].read(window=Window.from_slices((p00,p01),(p10,p11)))\n            img[(p00-x0):(p01-x0),(p10-y0):(p11-y0)] = tile\n        \n        if self.reduce != 1:\n            img = cv2.resize(img,(self.sz//self.reduce,self.sz//self.reduce),\n                             interpolation = cv2.INTER_AREA)\n        #check for empty imges\n        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n        h,s,v = cv2.split(hsv)\n        if (s>s_th).sum() <= p_th or img.sum() <= p_th:\n            #images with -1 will be skipped\n            return img2tensor((img/255.0 - mean)/std), -1, x0, y0, p00, p01, p10, p11\n        else: return img2tensor((img/255.0 - mean)/std), idx, x0, y0, p00, p01, p10, p11","metadata":{"papermill":{"duration":0.13211,"end_time":"2020-12-21T08:55:03.764827","exception":false,"start_time":"2020-12-21T08:55:03.632717","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#iterator like wrapper that returns predicted masks\nclass Model_pred:\n    def __init__(self, models, dl, reduce, tta:bool=True):\n        self.models = models\n        self.dl = dl\n        self.reduce = reduce\n        self.tta = tta\n        \n    def __iter__(self):\n        count=0\n        with torch.no_grad():\n            for x,y,x0,y0,p00,p01,p10,p11 in iter(self.dl):\n                if ((y>=0).sum() > 0): #exclude empty images\n                    x = x[y>=0].to(device)\n                    x0 = x0[y>=0]\n                    y0 = y0[y>=0]\n                    p00 = p00[y>=0]\n                    p01 = p01[y>=0]\n                    p10 = p10[y>=0]\n                    p11 = p11[y>=0]\n                    y = y[y>=0]\n#                     if self.half: x = x.half()\n                    with autocast(enabled=True):\n                        py = None\n                        for model in self.models:\n                            p = model(x)\n                            p = torch.sigmoid(p).detach()\n                            if py is None: py = p\n                            else: py += p\n                        if self.tta:\n                            #x,y,xy flips as TTA\n                            flips = [[-1],[-2],[-2,-1]]\n                            for f in flips:\n                                xf = torch.flip(x,f)\n                                for model in self.models:\n                                    p = model(xf)\n                                    p = torch.flip(p,f)\n                                    py += torch.sigmoid(p).detach()\n                            py /= (1+len(flips))        \n                        py /= len(self.models)\n\n                    # py = F.upsample(py, scale_factor=self.reduce, mode=\"bilinear\")\n                    py = py.permute(0,2,3,1).half().cpu()\n                    \n                    batch_size = len(py)\n                    for i in range(batch_size):\n                        yield py[i],y[i],x0[i],y0[i],p00[i],p01[i],p10[i],p11[i]\n                        count += 1\n                    \n    def __len__(self):\n        return len(self.dl.dataset)","metadata":{"papermill":{"duration":0.040087,"end_time":"2020-12-21T08:55:03.824926","exception":false,"start_time":"2020-12-21T08:55:03.784839","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"papermill":{"duration":0.019219,"end_time":"2020-12-21T08:55:03.86417","exception":false,"start_time":"2020-12-21T08:55:03.844951","status":"completed"},"tags":[]}},{"cell_type":"code","source":"class FReLU(nn.Module):\n    def __init__(self, c1, k=3):  # ch_in, kernel\n        super().__init__()\n        self.conv = nn.Conv2d(c1, c1, k, 1, 1, groups=c1, bias=False)\n        self.bn = nn.BatchNorm2d(c1)\n\n    def forward(self, x):\n        return torch.max(x, self.bn(self.conv(x)))\n\nclass Conv2dAct(nn.Sequential):\n    def __init__(\n            self,\n            in_channels,\n            out_channels,\n            kernel_size,\n            padding=0,\n            stride=1,\n            use_batchnorm=True,\n            act_layer='relu'\n    ):\n        conv = nn.Conv2d(\n            in_channels,\n            out_channels,\n            kernel_size,\n            stride=stride,\n            padding=padding,\n            bias=not (use_batchnorm),\n        )\n        if act_layer == 'frelu':\n            act = FReLU(out_channels)\n        else:\n            act = create_act_layer(act_layer)\n        if use_batchnorm:\n            bn = nn.BatchNorm2d(out_channels)\n        else:\n            bn = nn.Identity()\n        super(Conv2dAct, self).__init__(conv, bn, act)\n\n\nclass DecoderBlockV2(nn.Module):\n    def __init__(\n            self,\n            in_channels,\n            skip_channels,\n            out_channels,\n            use_batchnorm=True,\n            act_layer='relu',\n            attention_type=None,\n    ):\n        super().__init__()\n        self.conv1 = Conv2dAct(\n            in_channels + skip_channels,\n            out_channels,\n            kernel_size=3,\n            padding=1,\n            use_batchnorm=use_batchnorm,\n            act_layer=act_layer\n        )\n        self.attention1 = md.Attention(attention_type, in_channels=in_channels + skip_channels)\n        self.conv2 = Conv2dAct(\n            out_channels,\n            out_channels,\n            kernel_size=3,\n            padding=1,\n            use_batchnorm=use_batchnorm,\n            act_layer=act_layer\n        )\n        self.attention2 = md.Attention(attention_type, in_channels=out_channels)\n\n    def forward(self, x, skip=None):\n        x = F.interpolate(x, scale_factor=2, mode=\"nearest\")\n        if skip is not None:\n            x = torch.cat([x, skip], dim=1)\n            x = self.attention1(x)\n        x = self.conv1(x)\n        x = self.conv2(x)\n        x = self.attention2(x)\n        return x\n\n\nclass UnetDecoderV2(nn.Module):\n    def __init__(\n            self,\n            encoder_channels,\n            decoder_channels,\n            n_blocks=5,\n            use_batchnorm=True,\n            act_layer='relu',\n            attention_type=None,\n    ):\n        super().__init__()\n\n        if n_blocks != len(decoder_channels):\n            raise ValueError(\n                \"Model depth is {}, but you provide `decoder_channels` for {} blocks.\".format(\n                    n_blocks, len(decoder_channels)\n                )\n            )\n\n        encoder_channels = encoder_channels[1:]  # remove first skip with same spatial resolution\n        encoder_channels = encoder_channels[::-1]  # reverse channels to start from head of encoder\n\n        # computing blocks input and output channels\n        head_channels = encoder_channels[0]\n        in_channels = [head_channels] + list(decoder_channels[:-1])\n        skip_channels = list(encoder_channels[1:]) + [0]\n        out_channels = decoder_channels\n\n        self.center = nn.Identity()\n\n        # combine decoder keyword arguments\n        kwargs = dict(use_batchnorm=use_batchnorm, act_layer=act_layer, attention_type=attention_type)\n        blocks = [\n            DecoderBlockV2(in_ch, skip_ch, out_ch, **kwargs)\n            for in_ch, skip_ch, out_ch in zip(in_channels, skip_channels, out_channels)\n        ]\n        self.blocks = nn.ModuleList(blocks)\n\n    def forward(self, *features):\n\n        features = features[1:]    # remove first skip with same spatial resolution\n        features = features[::-1]  # reverse channels to start from head of encoder\n\n        head = features[0]\n        skips = features[1:]\n\n        x = self.center(head)\n        for i, decoder_block in enumerate(self.blocks):\n            skip = skips[i] if i < len(skips) else None\n            x = decoder_block(x, skip)\n\n        return x","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CSPDarkNet53Encoder(nn.Module):\n    def __init__(self, pretrain=True, act_layer='leaky_relu'):\n        super(CSPDarkNet53Encoder, self).__init__()\n        base = timm.create_model('cspdarknet53', pretrained=pretrain, act_layer=get_act_layer(act_layer))\n        self.stem = base.stem\n        self.layer0 = base.stages[0]\n        self.layer1 = base.stages[1]\n        self.layer2 = base.stages[2]\n        self.layer3 = base.stages[3]\n        self.layer4 = base.stages[4]\n        del base\n        \n        self.depth = 5\n        self.out_channels = (32, 64, 128, 256, 512, 1024)\n        self.in_channels = 3\n        \n        \n    def get_stages(self):\n        return [\n            self.stem,\n            self.layer0,\n            self.layer1,\n            self.layer2,\n            self.layer3,\n            self.layer4,\n        ]\n    \n    def forward(self, x):\n        stages = self.get_stages()\n\n        features = []\n        for i in range(self.depth + 1):\n            x = stages[i](x)\n            features.append(x)\n\n        return features\n\nclass CSPDarkNet53FPN(smp.base.SegmentationModel):\n    def __init__(\n        self,\n        pretrain=True,\n        decoder_pyramid_channels: int = 256,\n        decoder_segmentation_channels: int = 128,\n        decoder_merge_policy: str = \"add\",\n        decoder_dropout: float = 0.2,\n        in_channels: int = 3,\n        classes: int = 1,\n        activation: Optional[str] = None,\n        upsampling: int = 4,\n        aux_params: Optional[dict] = None,\n    ):\n        super().__init__()\n        \n        self.encoder = CSPDarkNet53Encoder(pretrain)\n        \n        self.decoder = smp.fpn.decoder.FPNDecoder(\n            encoder_channels=self.encoder.out_channels,\n            encoder_depth=self.encoder.depth,\n            pyramid_channels=decoder_pyramid_channels,\n            segmentation_channels=decoder_segmentation_channels,\n            dropout=decoder_dropout,\n            merge_policy=decoder_merge_policy,\n        )\n\n        self.segmentation_head = smp.base.SegmentationHead(\n            in_channels=self.decoder.out_channels,\n            out_channels=classes,\n            activation=activation,\n            kernel_size=1,\n            upsampling=upsampling,\n        )\n\n        if aux_params is not None:\n            self.classification_head = smp.base.ClassificationHead(\n                in_channels=self.encoder.out_channels[-1], **aux_params\n            )\n        else:\n            self.classification_head = None\n\n        self.name = \"fpn-cspdarknet53\"\n        self.initialize()\n\n\nclass CSPDarkNet53Unet(smp.base.SegmentationModel):\n    def __init__(\n        self,\n        pretrain=True,\n        act_layer='leaky_relu',\n        decoder_use_batchnorm: bool = True,\n        decoder_channels: List[int] = (256, 128, 64, 32, 16),\n        decoder_attention_type: Optional[str] = None,\n        in_channels: int = 3,\n        classes: int = 1,\n        activation: Optional[str] = None,\n        aux_params: Optional[dict] = None,\n        \n    ):\n        super().__init__()\n        \n        self.encoder = CSPDarkNet53Encoder(pretrain, act_layer)\n        \n        self.decoder = smp.unet.decoder.UnetDecoder(\n            encoder_channels=self.encoder.out_channels,\n            decoder_channels=decoder_channels,\n            n_blocks=self.encoder.depth,\n            use_batchnorm=decoder_use_batchnorm,\n            center=False,\n            attention_type=decoder_attention_type\n        )\n\n        self.segmentation_head = smp.base.SegmentationHead(\n            in_channels=decoder_channels[-1],\n            out_channels=classes,\n            activation=activation,\n            kernel_size=3,\n        )\n\n        if aux_params is not None:\n            self.classification_head = smp.base.ClassificationHead(\n                in_channels=self.encoder.out_channels[-1], **aux_params\n            )\n        else:\n            self.classification_head = None\n\n        self.name = \"unet-cspdarknet53\"\n        self.initialize()\n        \nclass CSPDarkNet53UnetV2(smp.base.SegmentationModel):\n    def __init__(\n        self,\n        pretrain=True,\n        act_layer='leaky_relu',\n        decoder_use_batchnorm: bool = True,\n        decoder_channels: List[int] = (256, 128, 64, 32, 16),\n        decoder_act_layer: str = 'relu',\n        decoder_attention_type: Optional[str] = None,\n        in_channels: int = 3,\n        classes: int = 1,\n        activation: Optional[str] = None,\n        aux_params: Optional[dict] = None,\n        \n    ):\n        super().__init__()\n        \n        self.encoder = CSPDarkNet53Encoder(pretrain, act_layer)\n        \n        self.decoder = UnetDecoderV2(\n            encoder_channels=self.encoder.out_channels,\n            decoder_channels=decoder_channels,\n            n_blocks=self.encoder.depth,\n            use_batchnorm=decoder_use_batchnorm,\n            act_layer=decoder_act_layer,\n            attention_type=decoder_attention_type\n        )\n\n        self.segmentation_head = smp.base.SegmentationHead(\n            in_channels=decoder_channels[-1],\n            out_channels=classes,\n            activation=activation,\n            kernel_size=3,\n        )\n\n        if aux_params is not None:\n            self.classification_head = smp.base.ClassificationHead(\n                in_channels=self.encoder.out_channels[-1], **aux_params\n            )\n        else:\n            self.classification_head = None\n\n        self.name = \"unetv2-cspdarknet53\"\n        self.initialize()","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Lightning model\nclass PlModel(pl.LightningModule):\n    def __init__(self, learning_rate = 1e-3):\n        super(PlModel, self).__init__()\n        self.learning_rate = learning_rate\n        self.model = smp.Unet('timm-efficientnet-b3', decoder_attention_type = None, encoder_weights = None)\n        self.criterion = None\n\n    def forward(self, x):\n        return self.model(x)","metadata":{"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nB3_MODELS = [\n    '../input/nfl-submissions/Mar291351_0_epoch20_val_metric0.940.ckpt',\n    '../input/nfl-submissions/Mar291351_1_epoch20_val_metric0.940.ckpt',\n    '../input/nfl-submissions/Mar291351_2_epoch18_val_metric0.947.ckpt',\n    '../input/nfl-submissions/Mar291351_3_epoch20_val_metric0.939.ckpt',\n]\n\nfor path in B3_MODELS:\n    model = PlModel()\n    model = model.load_from_checkpoint(path)\n    model.float()\n    model.eval()\n    model.to(device)\n    models.append(model)","metadata":{"papermill":{"duration":8.633248,"end_time":"2020-12-21T08:55:12.576982","exception":false,"start_time":"2020-12-21T08:55:03.943734","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"D53_MODELS = [\n    ('../input/hubmap-trained-models/unetv2-d53_sf-672-pseudo5-external_s2.pth', 'frelu'),\n#     ('../input/hubmap-trained-models/unetv2-d53_sf-672-pseudo5-external_f1_s2.pth', 'frelu'),\n    ('../input/hubmap-trained-models/unetv2-d53_sf_valid_8242609fa_best.pth', 'frelu'),\n    ('../input/hubmap-trained-models/unetv2-d53_sf_valid_b2dc8411c_best.pth', 'frelu'),\n    ('../input/hubmap-trained-models/unetv2-d53_sr_valid_4ef6695ce_best.pth', 'relu'),\n    ('../input/hubmap-trained-models/unetv2-d53_sf_valid_2f6ecfcdf_best.pth', 'frelu')\n]\n\nfor path, act in D53_MODELS:\n    state_dict = torch.load(path,map_location=torch.device('cpu'))\n    model = CSPDarkNet53UnetV2(\n        pretrain=False,\n        act_layer='swish',\n        decoder_act_layer=act,\n        in_channels=3, \n        classes=1).cuda()\n    model.load_state_dict(state_dict['model'])\n    model.float()\n    model.eval()\n    model.to(device)\n    models.append(model)\n\ndel state_dict","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Total number of trained models {len(models)}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction","metadata":{"papermill":{"duration":0.019098,"end_time":"2020-12-21T08:55:12.616139","exception":false,"start_time":"2020-12-21T08:55:12.597041","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def get_gauss_filter(half):\n    y,x = np.mgrid[-half:half,-half:half]\n    y = half-abs(y)\n    x = half-abs(x)\n    w = np.minimum(x,y)\n    w = w/w.max()#*2.5\n    w = np.minimum(w,1)\n    return w","metadata":{"papermill":{"duration":0.053551,"end_time":"2020-12-21T08:55:12.705589","exception":false,"start_time":"2020-12-21T08:55:12.652038","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import skimage.measure as ms\n\ndef reduce_fp(predict, shape, s, t=0.4):\n    mask = (predict > t).astype(np.uint8)\n    mask = ms.label(mask)\n    \n    l_probs = []\n    for i in range(1, mask.max()+1):\n        l_probs.append(predict[mask == i].max())\n    l_probs = np.array(l_probs)\n    \n    mask[np.isin(mask, (np.where(l_probs < s)[0] + 1))] = 0\n    return cv2.resize((mask > 0).astype(np.uint8), shape, interpolation=cv2.INTER_NEAREST)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"half = sz//2\nw = get_gauss_filter(half).astype(np.half)\n\nnames,preds = [],[]\nfor idx,row in tqdm(df_sample.iterrows(),total=len(df_sample)):\n    idx = row['id']\n    ds = HuBMAPDataset(idx, sz=sz, step=step, reduce=reduce)\n    #rasterio cannot be used with multiple workers\n    dl = DataLoader(ds,bs,num_workers=0,shuffle=False,pin_memory=True)\n    mp = Model_pred(models,dl,reduce)\n    \n    predict = np.zeros((ds.shape[0]//reduce, ds.shape[1]//reduce), dtype=np.half)\n    count = np.zeros_like(predict)\n    \n    #generate masks\n    for p,i,x0,y0,p00,p01,p10,p11 in iter(mp):\n        tile = p.squeeze(-1).numpy()\n        c = np.array([x0,y0,p00,p01,p10,p11])\n        \n        c = c//reduce\n        x0, y0, p00, p01, p10, p11 = c\n        predict[p00:p01,p10:p11] += tile[(p00-x0):(p01-x0),(p10-y0):(p11-y0)] * w[(p00-x0):(p01-x0),(p10-y0):(p11-y0)]\n        count[p00:p01,p10:p11] += w[(p00-x0):(p01-x0),(p10-y0):(p11-y0)]\n    \n    m = (count != 0)\n    predict[m] /= count[m]\n    \n    del count\n    gc.collect()\n    \n    #convert to rle\n    #https://www.kaggle.com/bguberfain/memory-aware-rle-encoding\n    \n#     predict = cv2.resize((predict > TH).astype(np.uint8), dsize=(ds.shape[1],ds.shape[0]), interpolation=cv2.INTER_NEAREST)\n    predict = reduce_fp(predict, (ds.shape[1],ds.shape[0]), S_TH, t=TH)\n    rle = rle_encode_less_memory(predict)\n    names.append(idx)\n    preds.append(rle)\n    del tile, c, predict, ds, dl\n    gc.collect()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame({'id':names,'predicted':preds})\ndf.to_csv('submission.csv',index=False)","metadata":{"papermill":{"duration":0.923422,"end_time":"2020-12-21T09:10:01.601929","exception":false,"start_time":"2020-12-21T09:10:00.678507","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]}]}