{"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":"Thanks [Yiheng Wang](https://www.kaggle.com/competitions/uw-madison-gi-tract-image-segmentation/discussion/325646)\n","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nsys.path.append(\"../input/segmentation-models-pytorch/segmentation_models.pytorch-0.2.1\")\nsys.path.append(\"../input/pretrainedmodels/pretrainedmodels-0.7.4\")\nsys.path.append(\"../input/efficientnet-pytorch/EfficientNet-PyTorch-master\")\n\n!pip install ../input/mmdetection/addict-2.4.0-py3-none-any.whl > /dev/null\n!pip install ../input/mmdetection/yapf-0.31.0-py2.py3-none-any.whl > /dev/null\n!pip install ../input/mmdetection/terminaltables-3.1.0-py3-none-any.whl > /dev/null\n!pip install ../input/mmdetection/einops* > /dev/null\n!pip install ../input/mmdetection/mmcv_full-1.3.17-cp37-cp37m-linux_x86_64.whl > /dev/null","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:21:22.984645Z","iopub.execute_input":"2022-07-14T02:21:22.985051Z","iopub.status.idle":"2022-07-14T02:23:44.207905Z","shell.execute_reply.started":"2022-07-14T02:21:22.984887Z","shell.execute_reply":"2022-07-14T02:23:44.207084Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r ../input/uwmgitt-mmseg/Kaggle-UWMGIT-kaggle_tractseg ./ && cd Kaggle-UWMGIT-kaggle_tractseg  && pip install -e ","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:44.209928Z","iopub.execute_input":"2022-07-14T02:23:44.210202Z","iopub.status.idle":"2022-07-14T02:23:50.114232Z","shell.execute_reply.started":"2022-07-14T02:23:44.210166Z","shell.execute_reply":"2022-07-14T02:23:50.113394Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport numpy as np\nimport pandas as pd\n\nimport cv2\nfrom PIL import Image\nfrom tqdm.auto import tqdm\nfrom matplotlib import pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:50.116177Z","iopub.execute_input":"2022-07-14T02:23:50.116433Z","iopub.status.idle":"2022-07-14T02:23:50.516930Z","shell.execute_reply.started":"2022-07-14T02:23:50.116399Z","shell.execute_reply":"2022-07-14T02:23:50.515944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load Libs","metadata":{}},{"cell_type":"code","source":"import sys\n\nsys.path.append('../input/monai-v081/')","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:50.531426Z","iopub.execute_input":"2022-07-14T02:23:50.535301Z","iopub.status.idle":"2022-07-14T02:23:50.549049Z","shell.execute_reply.started":"2022-07-14T02:23:50.534242Z","shell.execute_reply":"2022-07-14T02:23:50.547167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\nfrom glob import glob\nimport os\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom torch import nn\nfrom monai.inferers import sliding_window_inference\nfrom monai.data import decollate_batch\nfrom monai.handlers.utils import from_engine\nfrom monai.networks.nets import UNet\nfrom torch.cuda.amp import GradScaler, autocast\nfrom tqdm import tqdm\nimport json","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:50.563928Z","iopub.execute_input":"2022-07-14T02:23:50.564200Z","iopub.status.idle":"2022-07-14T02:23:58.504340Z","shell.execute_reply.started":"2022-07-14T02:23:50.564166Z","shell.execute_reply":"2022-07-14T02:23:58.503547Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from monai.data import CacheDataset, DataLoader\nfrom monai.transforms import (\n    Compose,\n    Activations,\n    AsDiscrete,\n    Activationsd,\n    AsDiscreted,\n    KeepLargestConnectedComponentd,\n    Invertd,\n    LoadImage,\n    Transposed,\n    LoadImaged,\n    AddChanneld,\n    CastToTyped,\n    Lambdad,\n    Resized,\n    EnsureTyped,\n    SpatialPadd,\n    EnsureChannelFirstd,\n)","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:58.507569Z","iopub.execute_input":"2022-07-14T02:23:58.507778Z","iopub.status.idle":"2022-07-14T02:23:58.515059Z","shell.execute_reply.started":"2022-07-14T02:23:58.507752Z","shell.execute_reply":"2022-07-14T02:23:58.513711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"markdown","source":"## Prepare mmseg","metadata":{}},{"cell_type":"code","source":"sys.path.append('./Kaggle-UWMGIT-kaggle_tractseg')\n\nfrom mmseg.apis import init_segmentor, inference_segmentor\nfrom mmcv.utils import config","metadata":{"execution":{"iopub.status.busy":"2022-07-14T02:23:58.516258Z","iopub.execute_input":"2022-07-14T02:23:58.518415Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cfgs = [\n    \"../input/uwm-b3final/b3-final/config.py\",\n    \"../input/uwm-b3final/b3-final/config.py\",\n    \"../input/uwm-b3final/b3-final/config.py\",\n    \"../input/uwm-b3final/b3-final/config.py\",\n    \"../input/uwm-b3final/b3-final/config.py\",\n]\n\n# remember to change your weight\nckpts = [\n    \"../input/uwm-b3final/b3-final/iter_30000_fold0.pth\",\n    '../input/uwm-b3final/b3-final/iter_30000_fold1.pth',\n    '../input/uwm-b3final/b3-final/iter_30000_fold2.pth',\n    '../input/uwm-b3final/b3-final/iter_30000_fold3.pth',   \n    '../input/uwm-b3final/b3-final/iter_30000_fold4.pth',\n]\n\nassert len(cfgs) == len(ckpts)\n\nmodels = []\nfor cfg, ckpt in zip(cfgs, ckpts):\n    cfg = config.Config.fromfile(cfg)\n    cfg.model.backbone.pretrained = None\n    cfg.model.test_cfg.logits = True\n    cfg.data.test.pipeline[1].transforms.insert(2, dict(type=\"Normalize\", mean=[0,0,0], std=[1,1,1], to_rgb=False))\n\n    model = init_segmentor(cfg, ckpt)\n    models.append(model)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(models)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def rle_encode(img):\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","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classes = ['large_bowel', 'small_bowel', 'stomach']\ndata_dir = \"../input/uw-madison-gi-tract-image-segmentation\"\ntest_dir = os.path.join(data_dir, \"test\")\nsub = pd.read_csv(os.path.join(data_dir, \"sample_submission.csv\"))\ntest_images = glob(os.path.join(test_dir, \"**\", \"*.png\"), recursive = True)\n\nif len(test_images) == 0:\n    test_dir = os.path.join(data_dir, \"train\")\n    sub = pd.read_csv(os.path.join(data_dir, \"train.csv\"))[[\"id\", \"class\"]].iloc[:100 * 3]\n    sub[\"predicted\"] = \"\"\n    test_images = glob(os.path.join(test_dir, \"**\", \"*.png\"), recursive = True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"id2img = {_.rsplit(\"/\", 4)[2] + \"_\" + \"_\".join(_.rsplit(\"/\", 4)[4].split(\"_\")[:2]): _ for _ in test_images}\nsub[\"file_name\"] = sub.id.map(id2img)\nsub[\"days\"] = sub.id.apply(lambda x: \"_\".join(x.split(\"_\")[:2]))\nfname2index = {f + c: i for f, c, i in zip(sub.file_name, sub[\"class\"], sub.index)}\nsub","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def mm_tta(type_augment, model, input):\n    if type_augment == 'horizontal_flip':\n        augmented_img = np.flip(input, axis=1)\n        output = inference_segmentor(model, augmented_img)[0]\n        output = np.flip(output, axis=1)\n    elif type_augment == 'vertical_flip':\n        augmented_img = np.flip(input, axis=0)\n        output = inference_segmentor(model, augmented_img)[0]\n        output = np.flip(output, axis=0)\n    elif type_augment == 'horizontal_vertical_flip':\n        augmented_img = np.flip(input, axis=[0, 1])\n        output = inference_segmentor(model, augmented_img)[0]\n        output = np.flip(output, axis=[1, 0])\n\n    return output","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare 3d","metadata":{}},{"cell_type":"markdown","source":"### Thanks awsaf49, this section refers to:\nhttps://www.kaggle.com/code/awsaf49/uwmgi-2-5d-infer-pytorch","metadata":{}},{"cell_type":"code","source":"def get_metadata(row):\n    data = row['id'].split('_')\n    case = int(data[0].replace('case',''))\n    day = int(data[1].replace('day',''))\n    slice_ = int(data[-1])\n    row['case'] = case\n    row['day'] = day\n    row['slice'] = slice_\n    return row\n\ndef path2info(row):\n    path = row['image_path']\n    data = path.split('/')\n    slice_ = int(data[-1].split('_')[1])\n    case = int(data[-3].split('_')[0].replace('case',''))\n    day = int(data[-3].split('_')[1].replace('day',''))\n    width = int(data[-1].split('_')[2])\n    height = int(data[-1].split('_')[3])\n    row['height'] = height\n    row['width'] = width\n    row['case'] = case\n    row['day'] = day\n    row['slice'] = slice_\n    return row","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('../input/uw-madison-gi-tract-image-segmentation/sample_submission.csv')\nif not len(sub_df):\n    debug = True\n    sub_df = pd.read_csv('../input/uw-madison-gi-tract-image-segmentation/train.csv')[:500*3]\n    sub_df = sub_df.drop(columns=['class','segmentation']).drop_duplicates()\nelse:\n    debug = False\n    sub_df = sub_df.drop(columns=['class','predicted']).drop_duplicates()\nsub_df = sub_df.apply(lambda x: get_metadata(x),axis=1)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"if debug:\n    paths = glob(f'/kaggle/input/uw-madison-gi-tract-image-segmentation/train/**/*png',recursive=True)\n#     paths = sorted(paths)\nelse:\n    paths = glob(f'/kaggle/input/uw-madison-gi-tract-image-segmentation/test/**/*png',recursive=True)\n#     paths = sorted(paths)\npath_df = pd.DataFrame(paths, columns=['image_path'])\npath_df = path_df.apply(lambda x: path2info(x),axis=1)\npath_df.head()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = sub_df.merge(path_df, on=['case','day','slice'], how='left')\ntest_df[\"case_id_str\"] = test_df[\"id\"].apply(lambda x: x.split(\"_\", 2)[0])\ntest_df[\"day_num_str\"] = test_df[\"id\"].apply(lambda x: x.split(\"_\", 2)[1])\ntest_df[\"slice_id\"] = test_df[\"id\"].apply(lambda x: x.split(\"_\", 2)[2])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data = []\n\nfor group in test_df.groupby([\"case_id_str\", \"day_num_str\"]):\n\n    case_id_str, day_num_str = group[0]\n    group_id = case_id_str + \"_\" + day_num_str\n    group_df = group[1].sort_values(\"slice_id\", ascending=True)\n    n_slices = group_df.shape[0]\n    group_slices, group_ids = [], []\n    for idx in range(n_slices):\n        slc = group_df.iloc[idx]\n        group_slices.append(slc.image_path)\n        group_ids.append(slc.id)\n    test_data.append({\"image\": group_slices, \"id\": group_ids})","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class cfg_3d:\n    img_size = (224, 224, 80)\n    in_channels = 1\n    out_channels = 3\n    device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    weights = ['../input/uwmadison-gi-tract-image-segmentation-weights/best_weights_fold_0.pth', \n               '../input/uwmadison-gi-tract-image-segmentation-weights/best_weights_fold_1.pth']\n    batch_size = 1\n    sw_batch_size = 4","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_transforms = Compose(\n    [\n        LoadImaged(keys=\"image\"), # d, h, w\n        AddChanneld(keys=\"image\"), # c, d, h, w\n        Transposed(keys=\"image\", indices=[0, 2, 3, 1]), # c, w, h, d\n        Lambdad(keys=\"image\", func=lambda x: x / x.max()),\n#         SpatialPadd(keys=\"image\", spatial_size=cfg_3d.img_size),  # in case less than 80 slices\n        EnsureTyped(keys=\"image\", dtype=torch.float32),\n    ]\n)\n\ntest_ds = CacheDataset(\n        data=test_data,\n        transform=test_transforms,\n        cache_rate=0.0,\n        num_workers=2,\n    )\n\ntest_dataloader = DataLoader(\n    test_ds,\n    batch_size=cfg_3d.batch_size,\n    num_workers=2,\n    pin_memory=True,\n)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_3d = UNet(\n    spatial_dims=3,\n    in_channels=cfg_3d.in_channels,\n    out_channels=cfg_3d.out_channels,\n    channels=(32, 64, 128, 256, 512),\n    strides=(2, 2, 2, 2),\n    kernel_size=3,\n    up_kernel_size=3,\n    num_res_units=2,\n    act=\"PRELU\",\n    norm=\"BATCH\",\n    dropout=0.2,\n    bias=True,\n    dimensions=None,\n).to(cfg_3d.device)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Infer","metadata":{}},{"cell_type":"code","source":"# ref.: https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle_encode(img):\n    \"\"\" TBD\n    \n    Args:\n        img (np.array): \n            - 1 indicating mask\n            - 0 indicating background\n    \n    Returns: \n        run length as string formated\n    \"\"\"\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)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def pred_mmseg_single_img(filename):\n        img = cv2.imread(file_name, cv2.IMREAD_ANYDEPTH)\n        old_size = img.shape[:2]\n        s = int(os.path.basename(file_name).split(\"_\")[1])\n        file_names = [file_name.replace(f\"slice_{s:04d}\", f\"slice_{s + i:04d}\") for i in range(-2, 3)]\n        file_names = [_ for _ in file_names if os.path.exists(_)]\n#         start = time()\n        imgs = [cv2.imread(file_names[0], cv2.IMREAD_ANYDEPTH)] + [img] + [cv2.imread(file_names[-1], cv2.IMREAD_ANYDEPTH)]\n\n#         print(time() - start)\n#         start = time()\n        \n        new_img = np.stack(imgs, -1)\n        new_img = new_img.astype(np.float32) / new_img.max()\n\n        # res = [inference_segmentor(model, new_img)[0] for model in models]\n#         print(time() - start)\n#         start = time()\n        \n        def agg_tta(model, new_img):\n            tta_ouputs = [inference_segmentor(model, new_img)[0],\n                          mm_tta('horizontal_flip', model, new_img),\n                          mm_tta('vertical_flip', model, new_img),\n                          mm_tta('horizontal_vertical_flip', model, new_img)]\n            return sum(tta_ouputs)/len(tta_ouputs)\n\n        res = [agg_tta(model, new_img) for model in models]\n        res = (sum(res) / len(res))\n        res = cv2.resize(res, old_size[::-1], interpolation = cv2.INTER_NEAREST)\n        return new_img, res","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"list_imgs = []\nlist_msks = []\n\noutputs = []\n\npost_pred = Compose([\n    Activations(sigmoid=True),\n    # AsDiscrete(threshold=0.5),\n])\n\nmodel_3d.eval()\ntorch.set_grad_enabled(False)\nprogress_bar = tqdm(range(len(test_dataloader)))\nval_it = iter(test_dataloader)\nfor itr in progress_bar:\n    batch = next(val_it)\n    test_inputs = batch[\"image\"].to(cfg_3d.device)\n\n    pred_all = []\n    for weights in cfg_3d.weights:\n        model_3d.load_state_dict(torch.load(weights)['model'])\n        pred = sliding_window_inference(test_inputs, cfg_3d.img_size, cfg_3d.sw_batch_size, model_3d)\n        pred_all.append(pred)\n        # do 4 tta\n        for dims in [[2], [3], [2, 3]]:\n            flip_pred = sliding_window_inference(torch.flip(test_inputs, dims=dims), cfg_3d.img_size, cfg_3d.sw_batch_size, model_3d)\n            flip_pred = torch.flip(flip_pred, dims=dims)\n            pred_all.append(flip_pred)\n    \n    pred_all = torch.mean(torch.stack(pred_all), dim=0)[0]\n    pred_all = post_pred(pred_all)\n    # c, w, h, d to d, c, h, w\n    pred_all = torch.permute(pred_all, [3, 2, 1, 0]).cpu().numpy()\n    # pred_all = pred_all.cpu().numpy()\n    # .astype(np.uint8)\n    # print(pred_all.shape)\n    id_outputs = from_engine([\"id\"])(batch)[0]\n    # print(pd.Series(id_outputs).map(id2img))\n\n    res_all = np.zeros_like(pred_all)\n    twodplus_all = np.zeros_like(res_all)\n    file_names = pd.Series([id_output[0] for id_output in id_outputs]).map(id2img).values\n    for (i, file_name) in enumerate(file_names):\n        twodplus_all[i], res_all[i] = pred_mmseg_single_img(file_name)\n\n    pred_all = 0.3*pred_all + 0.7*res_all\n\n    # large_bowel\n    pred_all[..., 0] = pred_all[..., 0] > 0.425\n    # small_bowel\n    pred_all[..., 1] = pred_all[..., 1] > 0.4\n    # stomach\n    pred_all[..., 2] = pred_all[..., 2] > 0.45\n    pred_all = pred_all.astype(np.uint8)    \n\n    for i, (test_output, id_output) in enumerate(zip(pred_all, id_outputs)):\n        id_name = id_output[0]\n        lb, sb, st = test_output[..., 0], test_output[..., 1], test_output[..., 2]\n        outputs.append([id_name, \"large_bowel\", rle_encode(lb)])\n        outputs.append([id_name, \"small_bowel\", rle_encode(sb)])\n        outputs.append([id_name, \"stomach\", rle_encode(st)])\n\n#         if len(list_imgs) < 50 and np.random.random()<0.3:\n#             list_imgs.append(twodplus_all[i])\n#             list_msks.append(test_output)\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# if debug:\n#     for img, msk in zip(list_imgs[:20], list_msks[:20]):\n#         plt.figure(figsize=(12, 7))\n#         plt.subplot(1, 3, 1); plt.imshow(img, cmap='bone');\n# #         plt.axis('OFF'); \n#         plt.title('image')\n#         plt.subplot(1, 3, 2); plt.imshow(msk*255); plt.axis('OFF'); plt.title('mask')\n#         plt.subplot(1, 3, 3); plt.imshow(img, cmap='bone'); plt.imshow(msk*255, alpha=0.4);\n# #         plt.axis('OFF'); \n#         plt.title('overlay')\n#         plt.tight_layout()\n#         plt.show()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submit = pd.DataFrame(data=np.array(outputs), columns=[\"id\", \"class\", \"predicted\"])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Fix sub error, refers to: https://www.kaggle.com/competitions/uw-madison-gi-tract-image-segmentation/discussion/320541\nif not debug:\n    sub_df = pd.read_csv('../input/uw-madison-gi-tract-image-segmentation/sample_submission.csv')\n    del sub_df['predicted']\n    sub_df = sub_df.merge(submit, on=['id','class'])\n    sub_df.to_csv('submission.csv',index=False)\nelse:\n    submit.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Removing the remaining files in the output dir since submission errors out if there are other files than submission.csv in the output.","metadata":{}},{"cell_type":"code","source":"!rm -r ./Kaggle-UWMGIT-kaggle_tractseg","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}