{"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":"code","source":"!mkdir -p /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/pretrainedmodels-0.7.4.xyz /tmp/pip/cache/pretrainedmodels-0.7.4.tar.gz\n!cp ../input/segmentation-models-pytorch/torch-1.10.1-cp37-cp37m-manylinux1_x86_64.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/segmentation_models_pytorch-0.2.1-py3-none-any.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/tqdm-4.62.3.xyz /tmp/pip/cache/tqdm-4.62.3.tar.gz\n!cp ../input/segmentation-models-pytorch/torchvision-0.11.2-cp37-cp37m-manylinux1_x86_64.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/timm-0.4.12-py3-none-any.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/typing_extensions-4.0.1-py3-none-any.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/munch-2.5.0-py2.py3-none-any.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/numpy-1.21.4-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/six-1.16.0-py2.py3-none-any.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl /tmp/pip/cache/\n!cp ../input/segmentation-models-pytorch/efficientnet_pytorch-0.6.3.xyz /tmp/pip/cache/efficientnet_pytorch-0.6.3.tar.gz\n!cp ../input/segmentation-models-pytorch/Pillow-8.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl /tmp/pip/cache/","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:52:37.043623Z","iopub.execute_input":"2022-07-18T18:52:37.044042Z","iopub.status.idle":"2022-07-18T18:52:52.170545Z","shell.execute_reply.started":"2022-07-18T18:52:37.043997Z","shell.execute_reply":"2022-07-18T18:52:52.169001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install --no-index --find-links /tmp/pip/cache/ segmentation-models-pytorch","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:52:52.173290Z","iopub.execute_input":"2022-07-18T18:52:52.173756Z","iopub.status.idle":"2022-07-18T18:53:03.068002Z","shell.execute_reply.started":"2022-07-18T18:52:52.173718Z","shell.execute_reply":"2022-07-18T18:53:03.066475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!mkdir -p /root/.cache/torch/hub/checkpoints/\n!cp ../input/segmentation-models-pytorch/resnet34-333f7ec4.pth /root/.cache/torch/hub/checkpoints/","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:03.070261Z","iopub.execute_input":"2022-07-18T18:53:03.070759Z","iopub.status.idle":"2022-07-18T18:53:04.865026Z","shell.execute_reply.started":"2022-07-18T18:53:03.070702Z","shell.execute_reply":"2022-07-18T18:53:04.863622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import segmentation_models_pytorch  as smp","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:04.868285Z","iopub.execute_input":"2022-07-18T18:53:04.868912Z","iopub.status.idle":"2022-07-18T18:53:04.874076Z","shell.execute_reply.started":"2022-07-18T18:53:04.868870Z","shell.execute_reply":"2022-07-18T18:53:04.872881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset\nfrom torch.utils.data import DataLoader\nimport torch.nn.functional as F\nimport torchvision\n\nimport pandas as pd\nimport numpy as np\nimport cv2\nimport zipfile\nimport rasterio\nfrom rasterio.windows import Window\n\nimport os\nimport tqdm\nimport math\nimport time\nimport gc\nimport random","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-07-18T18:57:13.104179Z","iopub.execute_input":"2022-07-18T18:57:13.105971Z","iopub.status.idle":"2022-07-18T18:57:13.118708Z","shell.execute_reply.started":"2022-07-18T18:57:13.105905Z","shell.execute_reply":"2022-07-18T18:57:13.117364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ENV","metadata":{}},{"cell_type":"code","source":"class config():\n    # ENVIRONMENT\n    \n    DEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    \n    KAGGLE = True\n    DS_PATH = \"../input/hubmap-organ-segmentation/\" if KAGGLE else \"./\"\n    TEST_IMGS_PATH = os.path.join(DS_PATH, \"test_images\")\n    \n    #Imagenet parameters\n    MEAN = np.array([0.485, 0.456, 0.406])\n    STD = np.array([0.229, 0.224, 0.225])\n    \n    #INFERENCE\n    BATCH_SIZE=32\n    TILES_SIZE = 256\n    \n    REDUCE = 4\n    PRED_VALUE_TRESHOLD = 0.3\n    PRED_SAT_THRESHOLD = 0.4\n    PRED_PX_THRESHOLD = 1000\n    \n    \ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    #the following line gives ~10% speedup\n    #but may lead to some stochasticity in the results \n    torch.backends.cudnn.benchmark = True\n    \nconfig()\nseed_everything(353)","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:57:13.531899Z","iopub.execute_input":"2022-07-18T18:57:13.532339Z","iopub.status.idle":"2022-07-18T18:57:13.546725Z","shell.execute_reply.started":"2022-07-18T18:57:13.532290Z","shell.execute_reply":"2022-07-18T18:57:13.545743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"test_df = pd.read_csv(os.path.join(config.DS_PATH, \"test.csv\"))\nsub_df = pd.read_csv(os.path.join(config.DS_PATH, \"sample_submission.csv\"))","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:05.175329Z","iopub.execute_input":"2022-07-18T18:53:05.176045Z","iopub.status.idle":"2022-07-18T18:53:05.191741Z","shell.execute_reply.started":"2022-07-18T18:53:05.175998Z","shell.execute_reply":"2022-07-18T18:53:05.190639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_img(img_path, resize_shape = None):\n    img = cv2.imread(img_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    \n    if resize_shape:\n        img = cv2.resize(img, resize_shape, interpolation = cv2.INTER_NEAREST)\n    return img\n\ndef img2tensor(img, dtype = np.float32):\n    \n    if img.ndim==2 :\n        img = np.expand_dims(img,2)\n        \n    img = np.transpose(img,(2,0,1))\n    return torch.from_numpy(img.astype(dtype, copy=False))","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:05.194489Z","iopub.execute_input":"2022-07-18T18:53:05.195334Z","iopub.status.idle":"2022-07-18T18:53:05.204006Z","shell.execute_reply.started":"2022-07-18T18:53:05.195282Z","shell.execute_reply":"2022-07-18T18:53:05.203057Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_decode(mask_rle, shape, color=1):\n    s = np.array(mask_rle.split(), dtype=int)\n\n    starts = s[0::2] - 1\n    lengths = s[1::2]\n    ends = starts + lengths\n\n    if len(shape)==3:\n        h, w, d = shape\n        img = np.zeros((h * w, d), dtype=np.float32)\n    else:\n        h, w = shape\n        img = np.zeros((h * w,), dtype=np.float32)\n\n    for lo, hi in zip(starts, ends):\n        img[lo : hi] = color\n        \n    return img.reshape(shape).T\n\ndef rle_encode(x):\n    out=[]\n    x=x.flatten()\n    for i in range(0,x.shape[0]-1):\n        if(x[i]==1):\n            count=1\n            out.append(str(i))\n            i+=1\n            while(x[i]==1):\n                count+=1\n                i+=1\n            out.append(str(count))\n    return \" \".join(out)","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:05.205155Z","iopub.execute_input":"2022-07-18T18:53:05.205516Z","iopub.status.idle":"2022-07-18T18:53:05.217484Z","shell.execute_reply.started":"2022-07-18T18:53:05.205484Z","shell.execute_reply":"2022-07-18T18:53:05.216345Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Preprocessing","metadata":{}},{"cell_type":"markdown","source":"### Tiled Dataset","metadata":{}},{"cell_type":"markdown","source":"TILING DS CODE BY [IAFOSS NOTEBOOK](https://www.kaggle.com/code/iafoss/256x256-images/notebook)","metadata":{}},{"cell_type":"code","source":"identity = rasterio.Affine(1, 0, 0, 0, 1, 0)","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:05.220617Z","iopub.execute_input":"2022-07-18T18:53:05.220964Z","iopub.status.idle":"2022-07-18T18:53:05.232211Z","shell.execute_reply.started":"2022-07-18T18:53:05.220934Z","shell.execute_reply":"2022-07-18T18:53:05.231370Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class HuBMAPDataset(Dataset):\n    def __init__(self, idx, reduce = config.REDUCE):\n        \n        self.data = rasterio.open(os.path.join(config.TEST_IMGS_PATH, idx +'.tiff'), transform = identity, num_threads='all_cpus')\n        \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                    \n        self.shape = self.data.shape\n        self.reduce = reduce\n        self.sz = self.reduce * config.TILES_SIZE\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        # 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        # 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], 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), interpolation = cv2.INTER_AREA)\n            \n        #check for empty imges\n        hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n        h,s,v = cv2.split(hsv)\n        if (s > config.PRED_SAT_THRESHOLD).sum() <= config.PRED_PX_THRESHOLD or img.sum() <= config.PRED_PX_THRESHOLD:\n            #images with -1 will be skipped\n            return img2tensor((img/255.0 - config.MEAN) / config.STD), -1\n        else: return img2tensor((img/255.0 - config.MEAN) / config.STD), idx","metadata":{"execution":{"iopub.status.busy":"2022-07-18T18:53:05.233533Z","iopub.execute_input":"2022-07-18T18:53:05.234117Z","iopub.status.idle":"2022-07-18T18:53:05.259950Z","shell.execute_reply.started":"2022-07-18T18:53:05.234084Z","shell.execute_reply":"2022-07-18T18:53:05.258719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"model = torch.load(\"../input/hubmap-dlv3plus-model/best_model.pth\")\nmodel.eval()","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-07-18T18:53:05.261437Z","iopub.execute_input":"2022-07-18T18:53:05.261841Z","iopub.status.idle":"2022-07-18T18:53:05.373611Z","shell.execute_reply.started":"2022-07-18T18:53:05.261809Z","shell.execute_reply":"2022-07-18T18:53:05.372467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prediction","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)\n\nclass Model_pred:\n    def __init__(self, models, dl, tta:bool=True, half:bool=False):\n        self.model = model\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(config.DEVICE)\n                    y = y[y>=0]\n                    if self.half: x = x.half()\n                    py = None\n                    p = self.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                            p = model(xf)\n                            p = torch.flip(p,f)\n                            py += torch.sigmoid(p).detach()\n                        py /= (1+len(flips))\n                        \n                    py = F.upsample(py, scale_factor=config.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-07-18T18:57:38.609353Z","iopub.execute_input":"2022-07-18T18:57:38.609781Z","iopub.status.idle":"2022-07-18T18:57:38.634867Z","shell.execute_reply.started":"2022-07-18T18:57:38.609743Z","shell.execute_reply":"2022-07-18T18:57:38.633644Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"names,preds = [],[]\nfor idx,row in tqdm.tqdm(sub_df.iterrows(),total=len(sub_df)):\n    idx = str(row['id'])\n    ds = HuBMAPDataset(idx)\n    #rasterio cannot be used with multiple workers\n    dl = DataLoader(ds,config.BATCH_SIZE,num_workers=0,shuffle=False,pin_memory=True)\n    mp = Model_pred(model,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) > config.PRED_VALUE_TRESHOLD\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-07-18T18:58:00.164449Z","iopub.execute_input":"2022-07-18T18:58:00.164882Z","iopub.status.idle":"2022-07-18T18:58:03.563752Z","shell.execute_reply.started":"2022-07-18T18:58:00.164832Z","shell.execute_reply":"2022-07-18T18:58:03.562595Z"},"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-07-18T18:58:35.345233Z","iopub.execute_input":"2022-07-18T18:58:35.345744Z","iopub.status.idle":"2022-07-18T18:58:35.359793Z","shell.execute_reply.started":"2022-07-18T18:58:35.345706Z","shell.execute_reply":"2022-07-18T18:58:35.358736Z"},"trusted":true},"execution_count":null,"outputs":[]}]}