{"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":"In particular, we have made inferences with reference to [HuBMAP fast.ai starter (EfficientNet) by wangkui](https://www.kaggle.com/code/befunny/hubmap-fast-ai-starter-efficientnet)\n\n## Reference\n\n- [HuBMAP fast.ai starter (EfficientNet) by wangkui](https://www.kaggle.com/code/befunny/hubmap-fast-ai-starter-efficientnet)\n- [Converting to 256x256 by The Devastator](https://www.kaggle.com/code/thedevastator/converting-to-256x256)\n- [[Training] - FastAI Baseline by The Devastator](https://www.kaggle.com/code/thedevastator/training-fastai-baseline)\n- [[Inference] - FastAI Baseline by The Devastator](https://www.kaggle.com/code/thedevastator/inference-fastai-baseline)","metadata":{}},{"cell_type":"code","source":"\"\"\"\nLovasz-Softmax and Jaccard hinge loss in PyTorch\nMaxim Berman 2018 ESAT-PSI KU Leuven (MIT License)\n\"\"\"\n\nimport torch\nfrom torch.autograd import Variable\nimport torch.nn.functional as F\nimport numpy as np\ntry:\n    from itertools import  ifilterfalse\nexcept ImportError: # py3k\n    from itertools import  filterfalse\n\n\ndef lovasz_grad(gt_sorted):\n    \"\"\"\n    Computes gradient of the Lovasz extension w.r.t sorted errors\n    See Alg. 1 in paper\n    \"\"\"\n    p = len(gt_sorted)\n    gts = gt_sorted.sum()\n    intersection = gts - gt_sorted.float().cumsum(0)\n    union = gts + (1 - gt_sorted).float().cumsum(0)\n    jaccard = 1. - intersection / union\n    if p > 1: # cover 1-pixel case\n        jaccard[1:p] = jaccard[1:p] - jaccard[0:-1]\n    return jaccard\n\n\ndef iou_binary(preds, labels, EMPTY=1., ignore=None, per_image=True):\n    \"\"\"\n    IoU for foreground class\n    binary: 1 foreground, 0 background\n    \"\"\"\n    if not per_image:\n        preds, labels = (preds,), (labels,)\n    ious = []\n    for pred, label in zip(preds, labels):\n        intersection = ((label == 1) & (pred == 1)).sum()\n        union = ((label == 1) | ((pred == 1) & (label != ignore))).sum()\n        if not union:\n            iou = EMPTY\n        else:\n            iou = float(intersection) / union\n        ious.append(iou)\n    iou = f_mean(ious)    # mean accross images if per_image\n    return 100 * iou\n\n\ndef iou(preds, labels, C, EMPTY=1., ignore=None, per_image=False):\n    \"\"\"\n    Array of IoU for each (non ignored) class\n    \"\"\"\n    if not per_image:\n        preds, labels = (preds,), (labels,)\n    ious = []\n    for pred, label in zip(preds, labels):\n        iou = []    \n        for i in range(C):\n            if i != ignore: # The ignored label is sometimes among predicted classes (ENet - CityScapes)\n                intersection = ((label == i) & (pred == i)).sum()\n                union = ((label == i) | ((pred == i) & (label != ignore))).sum()\n                if not union:\n                    iou.append(EMPTY)\n                else:\n                    iou.append(float(intersection) / union)\n        ious.append(iou)\n    ious = map(f_mean, zip(*ious)) # mean accross images if per_image\n    return 100 * np.array(ious)\n\n\n# --------------------------- BINARY LOSSES ---------------------------\n\n\ndef lovasz_hinge(logits, labels, per_image=True, ignore=None):\n    \"\"\"\n    Binary Lovasz hinge loss\n      logits: [B, H, W] Variable, logits at each pixel (between -\\infty and +\\infty)\n      labels: [B, H, W] Tensor, binary ground truth masks (0 or 1)\n      per_image: compute the loss per image instead of per batch\n      ignore: void class id\n    \"\"\"\n    if per_image:\n        loss = f_mean(lovasz_hinge_flat(*flatten_binary_scores(log.unsqueeze(0), lab.unsqueeze(0), ignore))\n                          for log, lab in zip(logits, labels))\n    else:\n        loss = lovasz_hinge_flat(*flatten_binary_scores(logits, labels, ignore))\n    return loss\n\n\ndef lovasz_hinge_flat(logits, labels):\n    \"\"\"\n    Binary Lovasz hinge loss\n      logits: [P] Variable, logits at each prediction (between -\\infty and +\\infty)\n      labels: [P] Tensor, binary ground truth labels (0 or 1)\n      ignore: label to ignore\n    \"\"\"\n    if len(labels) == 0:\n        # only void pixels, the gradients should be 0\n        return logits.sum() * 0.\n    signs = 2. * labels.float() - 1.\n    errors = (1. - logits * Variable(signs))\n    errors_sorted, perm = torch.sort(errors, dim=0, descending=True)\n    perm = perm.data\n    gt_sorted = labels[perm]\n    grad = lovasz_grad(gt_sorted)\n    #loss = torch.dot(F.relu(errors_sorted), Variable(grad))\n    loss = torch.dot(F.elu(errors_sorted)+1, Variable(grad))\n    return loss\n\n\ndef flatten_binary_scores(scores, labels, ignore=None):\n    \"\"\"\n    Flattens predictions in the batch (binary case)\n    Remove labels equal to 'ignore'\n    \"\"\"\n    scores = scores.view(-1)\n    labels = labels.view(-1)\n    if ignore is None:\n        return scores, labels\n    valid = (labels != ignore)\n    vscores = scores[valid]\n    vlabels = labels[valid]\n    return vscores, vlabels\n\n\nclass StableBCELoss(torch.nn.modules.Module):\n    def __init__(self):\n         super(StableBCELoss, self).__init__()\n    def forward(self, input, target):\n         neg_abs = - input.abs()\n         loss = input.clamp(min=0) - input * target + (1 + neg_abs.exp()).log()\n         return loss.mean()\n\n\ndef binary_xloss(logits, labels, ignore=None):\n    \"\"\"\n    Binary Cross entropy loss\n      logits: [B, H, W] Variable, logits at each pixel (between -\\infty and +\\infty)\n      labels: [B, H, W] Tensor, binary ground truth masks (0 or 1)\n      ignore: void class id\n    \"\"\"\n    logits, labels = flatten_binary_scores(logits, labels, ignore)\n    loss = StableBCELoss()(logits, Variable(labels.float()))\n    return loss\n\n\n# --------------------------- MULTICLASS LOSSES ---------------------------\n\n\ndef lovasz_softmax(probas, labels, only_present=False, per_image=False, ignore=None):\n    \"\"\"\n    Multi-class Lovasz-Softmax loss\n      probas: [B, C, H, W] Variable, class probabilities at each prediction (between 0 and 1)\n      labels: [B, H, W] Tensor, ground truth labels (between 0 and C - 1)\n      only_present: average only on classes present in ground truth\n      per_image: compute the loss per image instead of per batch\n      ignore: void class labels\n    \"\"\"\n    if per_image:\n        loss = f_mean(lovasz_softmax_flat(*flatten_probas(prob.unsqueeze(0), lab.unsqueeze(0), ignore), only_present=only_present)\n                          for prob, lab in zip(probas, labels))\n    else:\n        loss = lovasz_softmax_flat(*flatten_probas(probas, labels, ignore), only_present=only_present)\n    return loss\n\n\ndef lovasz_softmax_flat(probas, labels, only_present=False):\n    \"\"\"\n    Multi-class Lovasz-Softmax loss\n      probas: [P, C] Variable, class probabilities at each prediction (between 0 and 1)\n      labels: [P] Tensor, ground truth labels (between 0 and C - 1)\n      only_present: average only on classes present in ground truth\n    \"\"\"\n    C = probas.size(1)\n    losses = []\n    for c in range(C):\n        fg = (labels == c).float() # foreground for class c\n        if only_present and fg.sum() == 0:\n            continue\n        errors = (Variable(fg) - probas[:, c]).abs()\n        errors_sorted, perm = torch.sort(errors, 0, descending=True)\n        perm = perm.data\n        fg_sorted = fg[perm]\n        losses.append(torch.dot(errors_sorted, Variable(lovasz_grad(fg_sorted))))\n    return f_mean(losses)\n\n\ndef flatten_probas(probas, labels, ignore=None):\n    \"\"\"\n    Flattens predictions in the batch\n    \"\"\"\n    B, C, H, W = probas.size()\n    probas = probas.permute(0, 2, 3, 1).contiguous().view(-1, C)  # B * H * W, C = P, C\n    labels = labels.view(-1)\n    if ignore is None:\n        return probas, labels\n    valid = (labels != ignore)\n    vprobas = probas[valid.nonzero().squeeze()]\n    vlabels = labels[valid]\n    return vprobas, vlabels\n\ndef xloss(logits, labels, ignore=None):\n    \"\"\"\n    Cross entropy loss\n    \"\"\"\n    return F.cross_entropy(logits, Variable(labels), ignore_index=255)\n\n\n# --------------------------- HELPER FUNCTIONS ---------------------------\n\ndef f_mean(l, ignore_nan=False, empty=0):\n    \"\"\"\n    nanmean compatible with generators.\n    \"\"\"\n    l = iter(l)\n    if ignore_nan:\n        l = ifilterfalse(np.isnan, l)\n    try:\n        n = 1\n        acc = next(l)\n    except StopIteration:\n        if empty == 'raise':\n            raise ValueError('Empty mean')\n        return empty\n    for n, v in enumerate(l, 2):\n        acc += v\n    if n == 1:\n        return acc\n    return acc / n","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:53.227880Z","iopub.execute_input":"2022-09-12T09:10:53.228379Z","iopub.status.idle":"2022-09-12T09:10:55.273273Z","shell.execute_reply.started":"2022-09-12T09:10:53.228262Z","shell.execute_reply":"2022-09-12T09:10:55.272176Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport gc\nimport cv2\nimport rasterio\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom tqdm import tqdm\nimport tifffile as tiff\nimport matplotlib.pyplot as plt\nfrom fastai.vision.all import *\nfrom rasterio.windows import Window\nfrom torch.utils.data import Dataset, DataLoader\nimport warnings; warnings.filterwarnings(\"ignore\")","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:55.275464Z","iopub.execute_input":"2022-09-12T09:10:55.276369Z","iopub.status.idle":"2022-09-12T09:10:57.710737Z","shell.execute_reply.started":"2022-09-12T09:10:55.276333Z","shell.execute_reply":"2022-09-12T09:10:57.709686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"bs = 16\nsz = 768    # the size of tiles\nreduce = 2  # reduce the original images by 4 times\nTH = 0.225  # threshold for positive predictions\nDATA = '../input/hubmap-organ-segmentation/test_images/'\nMODELS = [f'../input/conv-origin-768-r2-b4-train-loss-nodropout/model_{i}.pth'for i in range(1)]\n\ndf_sample = pd.read_csv('../input/hubmap-organ-segmentation/sample_submission.csv')\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.712814Z","iopub.execute_input":"2022-09-12T09:10:57.713932Z","iopub.status.idle":"2022-09-12T09:10:57.731269Z","shell.execute_reply.started":"2022-09-12T09:10:57.713876Z","shell.execute_reply":"2022-09-12T09:10:57.730129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data","metadata":{}},{"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":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.735360Z","iopub.execute_input":"2022-09-12T09:10:57.735821Z","iopub.status.idle":"2022-09-12T09:10:57.750644Z","shell.execute_reply.started":"2022-09-12T09:10:57.735780Z","shell.execute_reply":"2022-09-12T09:10:57.749614Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import math\n\n# 768\nmean = np.array([0.78054955,  0.7566257, 0.7735184]) \nstd = np.array([0.25334089, 0.26656769, 0.26202731])\n\n\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, reduce=reduce):\n        self.data = rasterio.open(os.path.join(DATA,idx+'.tiff'), transform = identity,\n                                 num_threads='all_cpus')\n        # some images have issues with their format \n        # and must be saved correctly before reading with rasterio\n        if self.data.count != 3:\n            subdatasets = self.data.subdatasets\n            self.layers = []\n            if len(subdatasets) > 0:\n                for i, subdataset in enumerate(subdatasets, 0):\n                    self.layers.append(rasterio.open(subdataset))\n        self.shape = self.data.shape\n        if self.shape[0] < sz:\n            self.ratio = 1\n        else:\n            self.ratio = math.ceil(self.shape[0] / sz)\n            \n        self.reduce = self.ratio\n        self.sz = self.reduce*sz\n        self.pad0 = (self.sz - self.shape[0]%self.sz)%self.sz\n        self.pad1 = (self.sz - self.shape[1]%self.sz)%self.sz\n        self.n0max = (self.shape[0] + self.pad0)//self.sz\n        self.n1max = (self.shape[1] + self.pad1)//self.sz\n        \n    def __len__(self):\n        return self.n0max*self.n1max\n    \n    def __getitem__(self, idx):\n\n        n0,n1 = idx//self.n1max, idx%self.n1max\n\n        x0,y0 = -self.pad0//2 + n0*self.sz, -self.pad1//2 + n1*self.sz\n\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        \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            for i,layer in enumerate(self.layers):\n                img[(p00-x0):(p01-x0),(p10-y0):(p11-y0),i] =\\\n                  layer.read(1,window=Window.from_slices((p00,p01),(p10,p11)))\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\n        return img2tensor((img/255.0 - mean)/std), idx","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.752695Z","iopub.execute_input":"2022-09-12T09:10:57.753160Z","iopub.status.idle":"2022-09-12T09:10:57.774317Z","shell.execute_reply.started":"2022-09-12T09:10:57.753115Z","shell.execute_reply":"2022-09-12T09:10:57.772918Z"},"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, half:bool=False):\n        self.models = models\n        self.dl = dl\n        self.tta = tta\n        self.half = half\n        self.reduce = reduce\n        \n    def __iter__(self):\n        count=0\n        with torch.no_grad():\n            for x,y in iter(self.dl):\n                if ((y>=0).sum() > 0): #exclude empty images\n                    x = x[y>=0].to(device)\n                    y = y[y>=0]\n                    if self.half: x = x.half()\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).float().cpu()\n                    \n                    batch_size = len(py)\n                    for i in range(batch_size):\n                        yield py[i],y[i]\n                        count += 1\n                    \n    def __len__(self):\n        return len(self.dl.dataset)","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.775772Z","iopub.execute_input":"2022-09-12T09:10:57.777967Z","iopub.status.idle":"2022-09-12T09:10:57.792242Z","shell.execute_reply.started":"2022-09-12T09:10:57.777919Z","shell.execute_reply":"2022-09-12T09:10:57.790939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"class FPN(nn.Module):\n    def __init__(self, input_channels:list, output_channels:list):\n        super().__init__()\n        self.convs = nn.ModuleList(\n            [nn.Sequential(nn.Conv2d(in_ch, out_ch*2, kernel_size=3, padding=1),\n             nn.ReLU(inplace=True), nn.BatchNorm2d(out_ch*2),\n             nn.Conv2d(out_ch*2, out_ch, kernel_size=3, padding=1))\n            for in_ch, out_ch in zip(input_channels, output_channels)])\n        \n    def forward(self, xs:list, last_layer):\n        hcs = [F.interpolate(c(x),scale_factor=2**(len(self.convs)-i),mode='bilinear') \n               for i,(c,x) in enumerate(zip(self.convs, xs))]\n        hcs.append(last_layer)\n        return torch.cat(hcs, dim=1)\n\nclass UnetBlock(Module):\n    def __init__(self, up_in_c:int, x_in_c:int, nf:int=None, blur:bool=False,\n                 self_attention:bool=False, **kwargs):\n        super().__init__()\n        self.shuf = PixelShuffle_ICNR(up_in_c, up_in_c//2, blur=blur, **kwargs)\n        self.bn = nn.BatchNorm2d(x_in_c)\n        ni = up_in_c//2 + x_in_c\n        nf = nf if nf is not None else max(up_in_c//2,32)\n        self.conv1 = ConvLayer(ni, nf, norm_type=None, **kwargs)\n        self.conv2 = ConvLayer(nf, nf, norm_type=None,\n            xtra=SelfAttention(nf) if self_attention else None, **kwargs)\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, up_in:Tensor, left_in:Tensor) -> Tensor:\n        s = left_in\n        up_out = self.shuf(up_in)\n        cat_x = self.relu(torch.cat([up_out, self.bn(s)], dim=1))\n        return self.conv2(self.conv1(cat_x))\n        \nclass _ASPPModule(nn.Module):\n    def __init__(self, inplanes, planes, kernel_size, padding, dilation, groups=1):\n        super().__init__()\n        self.atrous_conv = nn.Conv2d(inplanes, planes, kernel_size=kernel_size,\n                stride=1, padding=padding, dilation=dilation, bias=False, groups=groups)\n        self.bn = nn.BatchNorm2d(planes)\n        self.relu = nn.ReLU()\n\n        self._init_weight()\n\n    def forward(self, x):\n        x = self.atrous_conv(x)\n        x = self.bn(x)\n\n        return self.relu(x)\n\n    def _init_weight(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                torch.nn.init.kaiming_normal_(m.weight)\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()\n\nclass ASPP(nn.Module):\n    def __init__(self, inplanes=512, mid_c=256, dilations=[6, 12, 18, 24], out_c=None):\n        super().__init__()\n        self.aspps = [_ASPPModule(inplanes, mid_c, 1, padding=0, dilation=1)] + \\\n            [_ASPPModule(inplanes, mid_c, 3, padding=d, dilation=d,groups=4) for d in dilations]\n        self.aspps = nn.ModuleList(self.aspps)\n        self.global_pool = nn.Sequential(nn.AdaptiveMaxPool2d((1, 1)),\n                        nn.Conv2d(inplanes, mid_c, 1, stride=1, bias=False),\n                        nn.BatchNorm2d(mid_c), nn.ReLU())\n        out_c = out_c if out_c is not None else mid_c\n        self.out_conv = nn.Sequential(nn.Conv2d(mid_c*(2+len(dilations)), out_c, 1, bias=False),\n                                    nn.BatchNorm2d(out_c), nn.ReLU(inplace=True))\n        self.conv1 = nn.Conv2d(mid_c*(2+len(dilations)), out_c, 1, bias=False)\n        self._init_weight()\n\n    def forward(self, x):\n        x0 = self.global_pool(x)\n        xs = [aspp(x) for aspp in self.aspps]\n        x0 = F.interpolate(x0, size=xs[0].size()[2:], mode='bilinear', align_corners=True)\n        x = torch.cat([x0] + xs, dim=1)\n        return self.out_conv(x)\n    \n    def _init_weight(self):\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                torch.nn.init.kaiming_normal_(m.weight)\n            elif isinstance(m, nn.BatchNorm2d):\n                m.weight.data.fill_(1)\n                m.bias.data.zero_()","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.794219Z","iopub.execute_input":"2022-09-12T09:10:57.794700Z","iopub.status.idle":"2022-09-12T09:10:57.823521Z","shell.execute_reply.started":"2022-09-12T09:10:57.794639Z","shell.execute_reply":"2022-09-12T09:10:57.822143Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pretrained_root = '../input/efficientnet-pytorch/'\nefficient_net_encoders = {\n    \"efficientnet-b0\": {\n        \"out_channels\": (3, 32, 24, 40, 112, 320),\n        \"stage_idxs\": (3, 5, 9, 16),\n        \"weight_path\": pretrained_root + \"efficientnet-b0-08094119.pth\"\n    },\n    \"efficientnet-b1\": {\n        \"out_channels\": (3, 32, 24, 40, 112, 320),\n        \"stage_idxs\": (5, 8, 16, 23),\n        \"weight_path\": pretrained_root + \"efficientnet-b1-dbc7070a.pth\"\n    },\n    \"efficientnet-b2\": {\n        \"out_channels\": (3, 32, 24, 48, 120, 352),\n        \"stage_idxs\": (5, 8, 16, 23),\n        \"weight_path\": pretrained_root + \"efficientnet-b2-27687264.pth\"\n    },\n    \"efficientnet-b3\": {\n        \"out_channels\": (3, 40, 32, 48, 136, 384),\n        \"stage_idxs\": (5, 8, 18, 26),\n        \"weight_path\": pretrained_root + \"efficientnet-b3-c8376fa2.pth\"\n    },\n    \"efficientnet-b4\": {\n        \"out_channels\": (3, 48, 32, 56, 160, 448),\n        \"stage_idxs\": (6, 10, 22, 32),\n        \"weight_path\": pretrained_root + \"efficientnet-b4-e116e8b3.pth\"\n    },\n    \"efficientnet-b5\": {\n        \"out_channels\": (3, 48, 40, 64, 176, 512),\n        \"stage_idxs\": (8, 13, 27, 39),\n        \"weight_path\": pretrained_root + \"efficientnet-b5-586e6cc6.pth\"\n    },\n    \"efficientnet-b6\": {\n        \"out_channels\": (3, 56, 40, 72, 200, 576),\n        \"stage_idxs\": (9, 15, 31, 45),\n        \"weight_path\": pretrained_root + \"efficientnet-b6-c76e70fd.pth\"\n    },\n    \"efficientnet-b7\": {\n        \"out_channels\": (3, 64, 48, 80, 224, 640),\n        \"stage_idxs\": (11, 18, 38, 55),\n        \"weight_path\": pretrained_root + \"efficientnet-b7-dcc49843.pth\"\n    }\n}","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.824959Z","iopub.execute_input":"2022-09-12T09:10:57.826095Z","iopub.status.idle":"2022-09-12T09:10:57.842144Z","shell.execute_reply.started":"2022-09-12T09:10:57.826060Z","shell.execute_reply":"2022-09-12T09:10:57.840560Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nsys.path.insert(0, '../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master')\n\nfrom efficientnet_pytorch import EfficientNet\nfrom efficientnet_pytorch.utils import get_model_params\n\n\nclass EfficientNetEncoder(EfficientNet):\n    def __init__(self, stage_idxs, out_channels, model_name, depth=5):\n\n        blocks_args, global_params = get_model_params(model_name, override_params=None)\n        super().__init__(blocks_args, global_params)\n        \n        cfg = efficient_net_encoders[model_name]\n\n        self._stage_idxs = stage_idxs\n        self._out_channels = out_channels\n        self._depth = depth\n        self._in_channels = 3\n\n        del self._fc\n        self.load_state_dict(torch.load(cfg['weight_path']))\n\n    def get_stages(self):\n        return [\n            nn.Identity(),\n            nn.Sequential(self._conv_stem, self._bn0, self._swish),\n            self._blocks[:self._stage_idxs[0]],\n            self._blocks[self._stage_idxs[0]:self._stage_idxs[1]],\n            self._blocks[self._stage_idxs[1]:self._stage_idxs[2]],\n            self._blocks[self._stage_idxs[2]:],\n        ]\n\n    def forward(self, x):\n        stages = self.get_stages()\n\n        block_number = 0.\n        drop_connect_rate = self._global_params.drop_connect_rate\n\n        features = []\n        for i in range(self._depth + 1):\n\n            # Identity and Sequential stages\n            if i < 2:\n                x = stages[i](x)\n\n            # Block stages need drop_connect rate\n            else:\n                for module in stages[i]:\n                    drop_connect = drop_connect_rate * block_number / len(self._blocks)\n                    block_number += 1.\n                    x = module(x, drop_connect)\n\n            features.append(x)\n\n        return features\n\n    def load_state_dict(self, state_dict, **kwargs):\n        state_dict.pop(\"_fc.bias\")\n        state_dict.pop(\"_fc.weight\")\n        super().load_state_dict(state_dict, **kwargs)  \n        \n\nclass EffUnet(nn.Module):\n    def __init__(self, model_name, stride=1):\n        super().__init__()\n        \n        cfg = efficient_net_encoders[model_name]\n        stage_idxs = cfg['stage_idxs']\n        out_channels = cfg['out_channels']\n        \n        self.encoder = EfficientNetEncoder(stage_idxs, out_channels, model_name)\n\n        #aspp with customized dilatations\n        self.aspp = ASPP(out_channels[-1], 256, out_c=384, \n                         dilations=[stride*1, stride*2, stride*3, stride*4])\n#         self.drop_aspp = nn.Dropout2d(0.5)\n        #decoder\n        self.dec4 = UnetBlock(384, out_channels[-2], 256)\n        self.dec3 = UnetBlock(256, out_channels[-3], 128)\n        self.dec2 = UnetBlock(128, out_channels[-4], 64)\n        self.dec1 = UnetBlock(64, out_channels[-5], 32)\n        self.fpn = FPN([384, 256, 128, 64], [16]*4)\n#         self.drop = nn.Dropout2d(0.1)\n        self.final_conv = ConvLayer(32+16*4, 1, ks=1, norm_type=None, act_cls=None)\n        \n    def forward(self, x):\n        enc0, enc1, enc2, enc3, enc4 = self.encoder(x)[-5:]\n        enc5 = self.aspp(enc4)\n#         dec3 = self.dec4(self.drop_aspp(enc5), enc3)\n        dec3 = self.dec4(enc5, enc3)\n        dec2 = self.dec3(dec3,enc2)\n        dec1 = self.dec2(dec2,enc1)\n        dec0 = self.dec1(dec1,enc0)\n        x = self.fpn([enc5, dec3, dec2, dec1], dec0)\n#         x = self.final_conv(self.drop(x))\n        x = self.final_conv(x)\n        x = F.interpolate(x,scale_factor=2,mode='bilinear')\n        return x\n    \n#split the model to encoder and decoder for fast.ai\nsplit_layers = lambda m: [\n                list(m.encoder.parameters()),\n                list(m.aspp.parameters())+list(m.dec4.parameters())+\n                list(m.dec3.parameters())+list(m.dec2.parameters())+\n                list(m.dec1.parameters())+list(m.fpn.parameters())+\n                list(m.final_conv.parameters())\n            ]","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.844145Z","iopub.execute_input":"2022-09-12T09:10:57.845178Z","iopub.status.idle":"2022-09-12T09:10:57.904275Z","shell.execute_reply.started":"2022-09-12T09:10:57.845138Z","shell.execute_reply":"2022-09-12T09:10:57.903274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nfor path in MODELS:\n    state_dict = torch.load(path,map_location=torch.device('cpu'))\n\n    model = EffUnet('efficientnet-b4')#.cuda()\n    model.load_state_dict(state_dict)\n    model.float()\n    model.eval()\n    model.to(device)\n    models.append(model)\n\ndel state_dict","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:10:57.907940Z","iopub.execute_input":"2022-09-12T09:10:57.908618Z","iopub.status.idle":"2022-09-12T09:11:01.157214Z","shell.execute_reply.started":"2022-09-12T09:10:57.908575Z","shell.execute_reply":"2022-09-12T09:11:01.156047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prediction","metadata":{}},{"cell_type":"code","source":"names,preds = [],[]\nfor idx,row in tqdm(df_sample.iterrows(),total=len(df_sample)):\n    idx = str(row['id'])\n    ds = HuBMAPDataset(idx)\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, ds.reduce)\n    #generate masks\n    mask = torch.zeros(len(ds),ds.sz,ds.sz,dtype=torch.int8)\n    for p,i in iter(mp): mask[i.item()] = p.squeeze(-1) > TH\n    \n    #reshape tiled masks into a single mask and crop padding\n    mask = mask.view(ds.n0max,ds.n1max,ds.sz,ds.sz).\\\n        permute(0,2,1,3).reshape(ds.n0max*ds.sz,ds.n1max*ds.sz)\n    mask = mask[ds.pad0//2:-(ds.pad0-ds.pad0//2) if ds.pad0 > 0 else ds.n0max*ds.sz,\n        ds.pad1//2:-(ds.pad1-ds.pad1//2) if ds.pad1 > 0 else ds.n1max*ds.sz]\n    \n    #convert to rle\n    #https://www.kaggle.com/bguberfain/memory-aware-rle-encoding\n    rle = rle_encode_less_memory(mask.numpy())\n    names.append(idx)\n    preds.append(rle)\n    del mask, ds, dl\n    gc.collect()","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:11:01.158759Z","iopub.execute_input":"2022-09-12T09:11:01.159105Z","iopub.status.idle":"2022-09-12T09:11:08.612919Z","shell.execute_reply.started":"2022-09-12T09:11:01.159073Z","shell.execute_reply":"2022-09-12T09:11:08.612022Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.DataFrame({'id':names,'rle':preds})\ndf.to_csv('submission.csv',index=False)","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:11:08.614133Z","iopub.execute_input":"2022-09-12T09:11:08.614623Z","iopub.status.idle":"2022-09-12T09:11:08.623785Z","shell.execute_reply.started":"2022-09-12T09:11:08.614592Z","shell.execute_reply":"2022-09-12T09:11:08.622484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:11:08.625497Z","iopub.execute_input":"2022-09-12T09:11:08.626336Z","iopub.status.idle":"2022-09-12T09:11:08.645282Z","shell.execute_reply.started":"2022-09-12T09:11:08.626292Z","shell.execute_reply":"2022-09-12T09:11:08.644050Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle2mask(mask_rle, shape=(1600,256)):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (width,height) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0]*shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape).T\n\nimg_1 = tiff.imread('../input/hubmap-organ-segmentation/test_images/10078.tiff')\nmask_1 = rle2mask(df[\"rle\"][0], (img_1.shape[1], img_1.shape[0]))\n\nplt.figure(figsize=(15,15))\nplt.subplot(1,2,1)\nplt.imshow(img_1)\n\nplt.subplot(1,2,2)\nplt.imshow(img_1)\nplt.imshow(mask_1, cmap='coolwarm', alpha=0.5)\nplt.axis(\"off\")\n","metadata":{"execution":{"iopub.status.busy":"2022-09-12T09:11:08.647162Z","iopub.execute_input":"2022-09-12T09:11:08.647606Z","iopub.status.idle":"2022-09-12T09:11:10.581270Z","shell.execute_reply.started":"2022-09-12T09:11:08.647564Z","shell.execute_reply":"2022-09-12T09:11:10.580085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}