{"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":"# **Training Notebook**","metadata":{}},{"cell_type":"markdown","source":"https://www.kaggle.com/code/vexxingbanana/hubmap-unet-semantic-approach-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-06-25T06:29:27.658492Z","iopub.execute_input":"2022-06-25T06:29:27.659538Z","iopub.status.idle":"2022-06-25T06:29:28.891675Z","shell.execute_reply.started":"2022-06-25T06:29:27.659425Z","shell.execute_reply":"2022-06-25T06:29:28.890251Z"},"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-06-25T06:29:28.898501Z","iopub.execute_input":"2022-06-25T06:29:28.898908Z","iopub.status.idle":"2022-06-25T06:29:30.509879Z","shell.execute_reply.started":"2022-06-25T06:29:28.898868Z","shell.execute_reply":"2022-06-25T06:29:30.505306Z"},"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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-06-25T06:32:26.897781Z","iopub.execute_input":"2022-06-25T06:32:26.898199Z","iopub.status.idle":"2022-06-25T06:33:08.576073Z","shell.execute_reply.started":"2022-06-25T06:32:26.898163Z","shell.execute_reply":"2022-06-25T06:33:08.574941Z"},"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 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":{"execution":{"iopub.status.busy":"2022-06-25T06:35:32.497853Z","iopub.execute_input":"2022-06-25T06:35:32.498214Z","iopub.status.idle":"2022-06-25T06:35:33.343463Z","shell.execute_reply.started":"2022-06-25T06:35:32.498182Z","shell.execute_reply":"2022-06-25T06:35:33.342331Z"},"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-b0\"\n    img_size = [512, 512]\n    lr = 1e-3\n    scheduler = 'CosineAnnealingLR' #['CosineAnnealingLR']\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 = '../input/hubmap-organ-segmentation'\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_path = '../input/hubmap-unet-semantic-approach-train/last_epoch-00.bin' #Checkpoint path\n    threshold = 0.5","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:33.65101Z","iopub.execute_input":"2022-06-25T06:35:33.651391Z","iopub.status.idle":"2022-06-25T06:35:33.720489Z","shell.execute_reply.started":"2022-06-25T06:35:33.651359Z","shell.execute_reply":"2022-06-25T06:35:33.719311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Helper Functions**","metadata":{}},{"cell_type":"code","source":"# ref: https://www.kaggle.com/paulorzp/run-length-encode-and-decode\ndef rle_decode(mask_rle, shape):\n    '''\n    mask_rle: run-length as string formated (start length)\n    shape: (height,width) 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)  # Needed to align to RLE direction\n\n\n# ref.: https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle_encode(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    pixels = img.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\n#ref: https://www.kaggle.com/code/bguberfain/memory-aware-rle-encoding/notebook\ndef rle_encode_less_memory(img):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    This simplified method requires first and last pixel to be zero\n    '''\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-06-25T06:35:34.95978Z","iopub.execute_input":"2022-06-25T06:35:34.960846Z","iopub.status.idle":"2022-06-25T06:35:34.970743Z","shell.execute_reply.started":"2022-06-25T06:35:34.960802Z","shell.execute_reply":"2022-06-25T06:35:34.969711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_tiff(path, scale=None, verbose=0): #Modified from https://www.kaggle.com/code/abhinand05/hubmap-extensive-eda-what-are-we-hacking\n    image = tifffile.imread(path)\n    if len(image.shape) == 5:\n        image = image.squeeze().transpose(1, 2, 0)\n    \n    if verbose:\n        print(f\"[{path}] Image shape: {image.shape}\")\n    \n    if scale:\n        new_size = (image.shape[1] // scale, image.shape[0] // scale)\n        image = cv2.resize(image, new_size)\n        \n        if verbose:\n            print(f\"[{path}] Resized Image shape: {image.shape}\")\n        \n    mx = np.max(image)\n    image = image.astype(np.float32)\n    if mx:\n        image /= mx # scale image to [0, 1]\n    return image","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:36.713751Z","iopub.execute_input":"2022-06-25T06:35:36.714398Z","iopub.status.idle":"2022-06-25T06:35:36.722467Z","shell.execute_reply.started":"2022-06-25T06:35:36.714354Z","shell.execute_reply":"2022-06-25T06:35:36.721236Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Grab Metadata**","metadata":{}},{"cell_type":"code","source":"df = pd.read_csv(\"../input/hubmap-organ-segmentation/test.csv\")\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:41.262529Z","iopub.execute_input":"2022-06-25T06:35:41.263571Z","iopub.status.idle":"2022-06-25T06:35:41.55919Z","shell.execute_reply.started":"2022-06-25T06:35:41.263523Z","shell.execute_reply":"2022-06-25T06:35:41.558267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Data Processing**","metadata":{}},{"cell_type":"code","source":"df['image_path'] = df['id'].apply(lambda x: os.path.join(CFG.base_path, 'test_images', str(x) + '.tiff'))","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:42.440682Z","iopub.execute_input":"2022-06-25T06:35:42.441383Z","iopub.status.idle":"2022-06-25T06:35:42.451032Z","shell.execute_reply.started":"2022-06-25T06:35:42.441346Z","shell.execute_reply":"2022-06-25T06:35:42.45002Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dataset**","metadata":{}},{"cell_type":"code","source":"class HuBMAP_Dataset(torch.utils.data.Dataset):\n    def __init__(self, df, labeled=True, transforms=None):\n        self.df = df\n        self.labeled = labeled\n        self.transforms = transforms\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, index):\n        img_path = self.df.loc[index, 'image_path']\n        img_height = self.df.loc[index, 'img_height']\n        img_width = self.df.loc[index, 'img_width']\n        id_ = self.df.loc[index, 'id']\n        img = read_tiff(img_path)\n        \n        if self.labeled:\n            rle_mask = self.df.loc[index, 'rle']\n            mask = rle_decode(rle_mask, (img_height, img_width))\n            \n            if self.transforms:\n                data = self.transforms(image=img, mask=mask)\n                img  = data['image']\n                mask  = data['mask']\n            \n            mask = np.expand_dims(mask, axis=0)\n            img = np.transpose(img, (2, 0, 1))\n#             mask = np.transpose(mask, (2, 0, 1))\n            \n            return torch.tensor(img), torch.tensor(mask)\n        \n        else:\n            if self.transforms:\n                data = self.transforms(image=img)\n                img  = data['image']\n                \n            img = np.transpose(img, (2, 0, 1))\n            \n            return torch.tensor(img), img_height, img_width, id_","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:43.172023Z","iopub.execute_input":"2022-06-25T06:35:43.172399Z","iopub.status.idle":"2022-06-25T06:35:43.184669Z","shell.execute_reply.started":"2022-06-25T06:35:43.172367Z","shell.execute_reply":"2022-06-25T06:35:43.183664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Augmentations**","metadata":{}},{"cell_type":"code","source":"data_transforms = {\n    \"inference\": A.Compose([\n        A.Resize(*CFG.img_size, interpolation=cv2.INTER_NEAREST),\n        ], p=1.0)\n}","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:44.160779Z","iopub.execute_input":"2022-06-25T06:35:44.161755Z","iopub.status.idle":"2022-06-25T06:35:44.167433Z","shell.execute_reply.started":"2022-06-25T06:35:44.161705Z","shell.execute_reply":"2022-06-25T06:35:44.166318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Models**","metadata":{}},{"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-25T06:35:45.138253Z","iopub.execute_input":"2022-06-25T06:35:45.139142Z","iopub.status.idle":"2022-06-25T06:35:45.146088Z","shell.execute_reply.started":"2022-06-25T06:35:45.139092Z","shell.execute_reply":"2022-06-25T06:35:45.145007Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Dataloader**","metadata":{}},{"cell_type":"code","source":"def prepare_loaders():\n\n    infer_dataset = HuBMAP_Dataset(df, labeled=False, transforms=data_transforms['inference'])\n\n    infer_loader = torch.utils.data.DataLoader(infer_dataset, batch_size=CFG.batch_size,\n                              num_workers=CFG.num_workers, shuffle=False, pin_memory=True, drop_last=False)\n    \n    return infer_loader","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:35:46.457039Z","iopub.execute_input":"2022-06-25T06:35:46.457737Z","iopub.status.idle":"2022-06-25T06:35:46.463408Z","shell.execute_reply.started":"2022-06-25T06:35:46.457696Z","shell.execute_reply":"2022-06-25T06:35:46.462198Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **Inference**","metadata":{}},{"cell_type":"code","source":"infer_loader = prepare_loaders()\nmodel = load_model(CFG.ckpt_path)\n\npred_ids = []\npred_rles = []\nwith torch.no_grad():\n    for (images, heights, widths, ids) in infer_loader:\n        images = images.to(CFG.device)\n        output = model(images)\n        output = nn.Sigmoid()(output)\n        msks = (output.permute((0,2,3,1))>CFG.threshold).to(torch.uint8).cpu().detach().numpy()\n\n        for idx in range(msks.shape[0]):\n            height = heights[idx].item()\n            width = widths[idx].item()\n            id_ = ids[idx].item()\n            msk = cv2.resize(msks[idx].squeeze(), \n                             dsize=(width, height), \n                             interpolation=cv2.INTER_NEAREST)\n            rle = rle_encode_less_memory(msk)\n            pred_rles.append(rle)\n            pred_ids.append(id_)\n\n        gc.collect()\n        torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:36:07.538119Z","iopub.execute_input":"2022-06-25T06:36:07.538714Z","iopub.status.idle":"2022-06-25T06:37:13.35366Z","shell.execute_reply.started":"2022-06-25T06:36:07.538676Z","shell.execute_reply":"2022-06-25T06:37:13.352428Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(pred_rles)","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:37:21.209011Z","iopub.execute_input":"2022-06-25T06:37:21.209499Z","iopub.status.idle":"2022-06-25T06:37:21.217451Z","shell.execute_reply.started":"2022-06-25T06:37:21.209461Z","shell.execute_reply":"2022-06-25T06:37:21.216387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred_df = pd.DataFrame({\n    \"id\":pred_ids,\n    \"rle\":pred_rles\n})\npred_df.to_csv('submission.csv',index=False)\ndisplay(pred_df.head(5))","metadata":{"execution":{"iopub.status.busy":"2022-06-25T06:37:25.240935Z","iopub.execute_input":"2022-06-25T06:37:25.241531Z","iopub.status.idle":"2022-06-25T06:37:25.427167Z","shell.execute_reply.started":"2022-06-25T06:37:25.241483Z","shell.execute_reply":"2022-06-25T06:37:25.426315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}