{"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":"# **Acknowledgements**","metadata":{}},{"cell_type":"markdown","source":"**This notebook is very heavily based on the copied notebook so make sure to upvote these three notebooks.**\n\nhttps://www.kaggle.com/code/thedevastator/inference-fastai-baseline\n\nhttps://www.kaggle.com/code/iafoss/256x256-images/notebook\n\nhttps://www.kaggle.com/code/realneuralnetwork/fork-of-inference-fastai-baseline","metadata":{}},{"cell_type":"markdown","source":"# **Description**","metadata":{}},{"cell_type":"markdown","source":"This is a notebook combining crops of the train tiffs and the UNet notebooks I have created. This allows you to use segmentation_models_pytorch with cropped images. **Make sure to upvote the cropping notebooks!**\n\nCropping notebooks:\nhttps://www.kaggle.com/code/thedevastator/converting-to-256x256\n\nhttps://www.kaggle.com/iafoss/256x256-images\n\n\nOriginal UNet notebooks:\nhttps://www.kaggle.com/code/vexxingbanana/hubmap-unet-semantic-approach-train/notebook\n\nhttps://www.kaggle.com/code/vexxingbanana/hubmap-unet-semantic-approach-infer","metadata":{}},{"cell_type":"markdown","source":"# **Training Notebook**","metadata":{}},{"cell_type":"markdown","source":"https://www.kaggle.com/code/vexxingbanana/hubmap-unet-w-256x256-crops-train","metadata":{}},{"cell_type":"markdown","source":"# **Install segmentation_models_pytorch**","metadata":{}},{"cell_type":"code","source":"!cp -r ../input/pytorch-segmentation-models-lib/ ./","metadata":{"execution":{"iopub.status.busy":"2022-07-01T07:38:20.309894Z","iopub.execute_input":"2022-07-01T07:38:20.310688Z","iopub.status.idle":"2022-07-01T07:38:21.221309Z","shell.execute_reply.started":"2022-07-01T07:38:20.310598Z","shell.execute_reply":"2022-07-01T07:38:21.219849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip config set global.disable-pip-version-check true","metadata":{"execution":{"iopub.status.busy":"2022-07-01T07:38:21.228767Z","iopub.execute_input":"2022-07-01T07:38:21.229570Z","iopub.status.idle":"2022-07-01T07:38:22.759205Z","shell.execute_reply.started":"2022-07-01T07:38:21.229522Z","shell.execute_reply":"2022-07-01T07:38:22.757734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q ./pytorch-segmentation-models-lib/pretrainedmodels-0.7.4/pretrainedmodels-0.7.4\n!pip install -q ./pytorch-segmentation-models-lib/efficientnet_pytorch-0.6.3/efficientnet_pytorch-0.6.3\n!pip install -q ./pytorch-segmentation-models-lib/timm-0.4.12-py3-none-any.whl\n!pip install -q ./pytorch-segmentation-models-lib/segmentation_models_pytorch-0.2.0-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2022-07-01T07:38:22.765374Z","iopub.execute_input":"2022-07-01T07:38:22.766195Z","iopub.status.idle":"2022-07-01T07:39:05.416259Z","shell.execute_reply.started":"2022-07-01T07:38:22.766145Z","shell.execute_reply":"2022-07-01T07:39:05.415095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Import Libraries**","metadata":{}},{"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.utils.data import Dataset, DataLoader\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport numpy as np\nimport pandas as pd\nimport time\nimport matplotlib.pyplot as plt\nimport cv2\nimport glob\nimport os\nimport shutil\nimport timm\nimport random\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nfrom torch.cuda import amp\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport transformers\nfrom sklearn.model_selection import StratifiedKFold, KFold, StratifiedGroupKFold\nimport multiprocessing as mp\nimport segmentation_models_pytorch as smp\nimport copy\nfrom collections import defaultdict\nimport gc\nfrom tqdm import tqdm\nimport tifffile\nfrom colorama import Fore, Back, Style","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":3.066435,"end_time":"2021-03-12T06:33:17.956368","exception":false,"start_time":"2021-03-12T06:33:14.889933","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-07-01T07:39:05.419832Z","iopub.execute_input":"2022-07-01T07:39:05.420701Z","iopub.status.idle":"2022-07-01T07:39:18.085127Z","shell.execute_reply.started":"2022-07-01T07:39:05.420656Z","shell.execute_reply":"2022-07-01T07:39:18.083986Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Config**","metadata":{}},{"cell_type":"code","source":"class CFG:\n    seed = 0\n    batch_size = 16\n    head = \"UNet\"\n    backbone = \"efficientnet-b3\" #['efficientnet-b0', efficientnet-b1', ... , efficientnet-b7'] and many other backbone architectures\n    img_size = [256, 256] # Or [512, 512]\n    lr = 1e-3\n    scheduler = 'CosineAnnealingLR' #['CosineAnnealingLR', 'ReduceLROnPlateau', 'ExponentialLR']\n    epochs = 20\n    warmup_epochs = 2\n    n_folds = 5\n    folds_to_run = [0]\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    base_path = '/kaggle/input/hubmap-organ-segmentation'\n    crops_path = '/kaggle/input/hubmap-2022-256x256' # Or '/kaggle/input/hubmap-2022-512x512'\n    num_workers = mp.cpu_count()\n    num_classes = 1\n    n_accumulate = max(1, 16//batch_size)\n    loss = 'Dice'\n    optimizer = 'Adam'\n    weight_decay = 1e-6\n    ckpt_paths = ['../input/hubmap-unet-w-256x256-crops-train/best_epoch-00.bin', '../input/hubmap-unet-w-256x256-crops-train/best_epoch-01.bin', '../input/hubmap-unet-w-256x256-crops-train/best_epoch-02.bin', '../input/hubmap-unet-w-256x256-crops-train/best_epoch-03.bin', '../input/hubmap-unet-w-256x256-crops-train/best_epoch-04.bin']\n    thr = 0.225\n    reduce_factor = 4","metadata":{"execution":{"iopub.status.busy":"2022-06-28T11:05:19.927Z","iopub.execute_input":"2022-06-28T11:05:19.928146Z","iopub.status.idle":"2022-06-28T11:05:19.936412Z","shell.execute_reply.started":"2022-06-28T11:05:19.928092Z","shell.execute_reply":"2022-06-28T11:05:19.934966Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# sz = 256   #the size of tiles\n# TH = CFG.thr  #threshold for positive predictions\nDATA = '../input/hubmap-organ-segmentation/test_images/'\n# MODELS = [f'../input/training-fastai-baseline/model_{i}.pth' for i in range(4)]\ndf_sample = pd.read_csv('../input/hubmap-organ-segmentation/sample_submission.csv')\nbs = CFG.batch_size\ndevice = CFG.device","metadata":{"papermill":{"duration":0.024698,"end_time":"2021-03-12T06:33:17.991398","exception":false,"start_time":"2021-03-12T06:33:17.9667","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:19.93889Z","iopub.execute_input":"2022-06-28T11:05:19.939565Z","iopub.status.idle":"2022-06-28T11:05:19.961928Z","shell.execute_reply.started":"2022-06-28T11:05:19.939529Z","shell.execute_reply":"2022-06-28T11:05:19.961095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Helper Functions**","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":{"_kg_hide-input":true,"papermill":{"duration":0.026676,"end_time":"2021-03-12T06:33:18.043775","exception":false,"start_time":"2021-03-12T06:33:18.017099","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:19.963263Z","iopub.execute_input":"2022-06-28T11:05:19.96367Z","iopub.status.idle":"2022-06-28T11:05:19.977868Z","shell.execute_reply.started":"2022-06-28T11:05:19.963629Z","shell.execute_reply":"2022-06-28T11:05:19.975173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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\n\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":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-06-28T11:05:19.979841Z","iopub.execute_input":"2022-06-28T11:05:19.980475Z","iopub.status.idle":"2022-06-28T11:05:20.018221Z","shell.execute_reply.started":"2022-06-28T11:05:19.980438Z","shell.execute_reply":"2022-06-28T11:05:20.017276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dataset**","metadata":{"papermill":{"duration":0.008314,"end_time":"2021-03-12T06:33:18.008555","exception":false,"start_time":"2021-03-12T06:33:18.000241","status":"completed"},"tags":[]}},{"cell_type":"code","source":"# https://www.kaggle.com/datasets/thedevastator/hubmap-2022-256x256\n# mean = np.array([0.7720342, 0.74582646, 0.76392896])\n# std = np.array([0.24745085, 0.26182273, 0.25782376])\nmean = np.array([0.485, 0.456, 0.406])\nstd = np.array([0.229, 0.224, 0.225])\n\ns_th = 40  #saturation blancking threshold\np_th = 1000*(CFG.img_size[0]//256)**2 #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=CFG.img_size[0], reduce=CFG.reduce_factor):\n        self.data = rasterio.open(os.path.join(DATA,idx+'.tiff'), \n                                  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        self.reduce = reduce\n        self.sz = 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#         self.transforms = A.Compose([\n#                                 A.Resize(*CFG.img_size, interpolation=cv2.INTER_NEAREST),\n#                                 A.Normalize(),\n#                             ], p=1.0)\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.sz, -self.pad1//2 + n1*self.sz\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 loade 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            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        #check for empty imges\n        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n        h,s,v = cv2.split(hsv)\n        \n#         if self.transforms:\n#                 data = self.transforms(image=img)\n#                 img  = data['image']\n                \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\n\n        else: return img2tensor((img/255.0 - mean)/std), idx","metadata":{"papermill":{"duration":0.037945,"end_time":"2021-03-12T06:33:18.090462","exception":false,"start_time":"2021-03-12T06:33:18.052517","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:20.01957Z","iopub.execute_input":"2022-06-28T11:05:20.020315Z","iopub.status.idle":"2022-06-28T11:05:20.042098Z","shell.execute_reply.started":"2022-06-28T11:05:20.020279Z","shell.execute_reply":"2022-06-28T11:05:20.041088Z"},"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, tta:bool=True, half:bool=False):\n        self.models = models\n        self.dl = dl\n        self.tta = tta\n        self.half = half\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=CFG.reduce_factor, 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":{"papermill":{"duration":0.030274,"end_time":"2021-03-12T06:33:18.129546","exception":false,"start_time":"2021-03-12T06:33:18.099272","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:20.045595Z","iopub.execute_input":"2022-06-28T11:05:20.046421Z","iopub.status.idle":"2022-06-28T11:05:20.059848Z","shell.execute_reply.started":"2022-06-28T11:05:20.046384Z","shell.execute_reply":"2022-06-28T11:05:20.058917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{"papermill":{"duration":0.008902,"end_time":"2021-03-12T06:33:18.153045","exception":false,"start_time":"2021-03-12T06:33:18.144143","status":"completed"},"tags":[]}},{"cell_type":"code","source":"def build_model():\n    model = smp.Unet(\n        encoder_name=CFG.backbone,      \n        encoder_weights=None,     \n        in_channels=3,            \n        classes=CFG.num_classes,\n        activation=None,\n    )\n    model.to(CFG.device)\n    return model\n\ndef load_model(path):\n    model = build_model()\n    model.load_state_dict(torch.load(path))\n    model.eval()\n    return model","metadata":{"execution":{"iopub.status.busy":"2022-06-28T11:05:20.063552Z","iopub.execute_input":"2022-06-28T11:05:20.064017Z","iopub.status.idle":"2022-06-28T11:05:20.079526Z","shell.execute_reply.started":"2022-06-28T11:05:20.063987Z","shell.execute_reply":"2022-06-28T11:05:20.078436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nfor path in CFG.ckpt_paths:\n    models.append(load_model(path))","metadata":{"papermill":{"duration":13.838863,"end_time":"2021-03-12T06:33:32.093854","exception":false,"start_time":"2021-03-12T06:33:18.254991","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:20.08089Z","iopub.execute_input":"2022-06-28T11:05:20.081603Z","iopub.status.idle":"2022-06-28T11:05:25.237718Z","shell.execute_reply.started":"2022-06-28T11:05:20.081566Z","shell.execute_reply":"2022-06-28T11:05:25.236734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction","metadata":{"papermill":{"duration":0.009141,"end_time":"2021-03-12T06:33:32.112738","exception":false,"start_time":"2021-03-12T06:33:32.103597","status":"completed"},"tags":[]}},{"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)\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) > CFG.thr\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":{"_kg_hide-output":true,"papermill":{"duration":638.710533,"end_time":"2021-03-12T06:44:10.832427","exception":false,"start_time":"2021-03-12T06:33:32.121894","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:25.239057Z","iopub.execute_input":"2022-06-28T11:05:25.239408Z","iopub.status.idle":"2022-06-28T11:05:31.59319Z","shell.execute_reply.started":"2022-06-28T11:05:25.239372Z","shell.execute_reply":"2022-06-28T11:05:31.592074Z"},"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":{"papermill":{"duration":0.419953,"end_time":"2021-03-12T06:44:11.262501","exception":false,"start_time":"2021-03-12T06:44:10.842548","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:31.595233Z","iopub.execute_input":"2022-06-28T11:05:31.596007Z","iopub.status.idle":"2022-06-28T11:05:31.616417Z","shell.execute_reply.started":"2022-06-28T11:05:31.595963Z","shell.execute_reply":"2022-06-28T11:05:31.613835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"papermill":{"duration":0.010126,"end_time":"2021-03-12T06:44:11.283196","exception":false,"start_time":"2021-03-12T06:44:11.27307","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2022-06-28T11:05:31.621939Z","iopub.execute_input":"2022-06-28T11:05:31.622717Z","iopub.status.idle":"2022-06-28T11:05:31.650749Z","shell.execute_reply.started":"2022-06-28T11:05:31.622676Z","shell.execute_reply":"2022-06-28T11:05:31.649762Z"},"trusted":true},"execution_count":null,"outputs":[]}]}