{"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":"# **KDDM 2 SARTORIUS CELL INSTANCE SEGMENTATION CASCADE MASK-RCNN (MMDETECTION) TRAIN AND INFERENCE NOTEBOOK**","metadata":{}},{"cell_type":"markdown","source":"# **INSTALL All DEPENDENCIES**\n* **Install PyTorch version required by MMDetection**\n* **Install MMDetection on and required dependencies**","metadata":{}},{"cell_type":"code","source":"!pip install '/kaggle/input/pytorch-170-cuda-toolkit-110221/torch-1.7.0+cu110-cp37-cp37m-linux_x86_64.whl' --no-deps\n!pip install '/kaggle/input/pytorch-170-cuda-toolkit-110221/torchvision-0.8.1+cu110-cp37-cp37m-linux_x86_64.whl' --no-deps\n!pip install '/kaggle/input/pytorch-170-cuda-toolkit-110221/torchaudio-0.7.0-cp37-cp37m-linux_x86_64.whl' --no-deps","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:06:06.279348Z","iopub.execute_input":"2022-01-26T15:06:06.279651Z","iopub.status.idle":"2022-01-26T15:08:01.627853Z","shell.execute_reply.started":"2022-01-26T15:06:06.279569Z","shell.execute_reply":"2022-01-26T15:08:01.626979Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install '/kaggle/input/mmdetectionv2140/addict-2.4.0-py3-none-any.whl' --no-deps\n!pip install '/kaggle/input/mmdetectionv2140/yapf-0.31.0-py2.py3-none-any.whl' --no-deps\n!pip install '/kaggle/input/mmdetectionv2140/terminal-0.4.0-py3-none-any.whl' --no-deps\n!pip install '/kaggle/input/mmdetectionv2140/terminaltables-3.1.0-py3-none-any.whl' --no-deps\n!pip install '/kaggle/input/mmdetectionv2140/mmcv_full-1_3_8-cu110-torch1_7_0/mmcv_full-1.3.8-cp37-cp37m-manylinux1_x86_64.whl' --no-deps\n\n!cp -r /kaggle/input/mmdetectionv2140/pycocotools-2.0.2/* /kaggle/working/\n!cp -r /kaggle/input/mmdetectionv2140/mmpycocotools-12.0.3/* /kaggle/working/\n\n!pip install '/kaggle/working/mmpycocotools-12.0.3/' --no-deps\n!pip install '/kaggle/working/pycocotools-2.0.2/' --no-deps\n\n!rm -rf /kaggle/working/pycocotools-2.0.2/\n!rm -rf /kaggle/working/mmpycocotools-12.0.3/\n\n!rm -rf mmdetection\n\n!cp -r /kaggle/input/mmdetectionv2140/mmdetection-2.14.0/ /kaggle/working/mmdetection/\n%cd /kaggle/working/mmdetection\n!pip install -e .","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:08:01.630121Z","iopub.execute_input":"2022-01-26T15:08:01.630386Z","iopub.status.idle":"2022-01-26T15:11:37.734623Z","shell.execute_reply.started":"2022-01-26T15:08:01.630348Z","shell.execute_reply":"2022-01-26T15:11:37.733773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* **Check installation**","metadata":{}},{"cell_type":"code","source":"import torch\nprint(torch.__version__, torch.cuda.is_available(),  torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'NO CUDA DEVICE')\n!nvcc --version\n\n# Check MMDetection installation\nimport mmdet\nprint(mmdet.__version__)\n\n# Check mmcv installation\nimport mmcv\nprint(mmcv.__version__)\n\nfrom mmcv.ops import get_compiling_cuda_version, get_compiler_version\nprint(\"Cuda:\", get_compiling_cuda_version(), \"Compiler:\", get_compiler_version())","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:11:37.739395Z","iopub.execute_input":"2022-01-26T15:11:37.741299Z","iopub.status.idle":"2022-01-26T15:11:45.966067Z","shell.execute_reply.started":"2022-01-26T15:11:37.741257Z","shell.execute_reply":"2022-01-26T15:11:45.965254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **TRAINING**\n* **Define model and settings for training**\n* **Execute training**","metadata":{}},{"cell_type":"markdown","source":"* **Set MMDetection model config**","metadata":{}},{"cell_type":"code","source":"import mmcv\n\n#choose a configuration\nmodel_name = \"cascade_mask_rcnn_r50_fpn_1x_coco\"\n#model_name = \"cascade_mask_rcnn_r101_fpn_20e_coco\"\n#model_name = \"cascade_mask_rcnn_x101_64x4d_fpn_1x_coco\"\n\n#load config\ncfg_name = model_name + \".py\"\ncfg_file = \"/kaggle/input/kddm2/mmdet/configs/\" + cfg_name\ncfg = mmcv.Config.fromfile(cfg_file)\n\n###############################################################################################################\n\n#optionally update some parameters in the config\ncfg[\"data\"][\"train\"][\"ann_file\"] = \"/kaggle/input/kddm2/mmdet/annotation/sartorius_coco_train.json\"\ncfg[\"data\"][\"val\"][\"ann_file\"] = \"/kaggle/input/kddm2/mmdet/annotation/sartorius_coco_val.json\"\ncfg[\"data\"][\"test\"][\"ann_file\"] = \"/kaggle/input/kddm2/mmdet/annotation/sartorius_coco_val.json\"\ncfg[\"checkpoint_config\"][\"interval\"] = 1\n\"\"\"\ncfg[\"optimizer\"][\"lr\"] = 0.02 / 8\ncfg[\"runner\"][\"max_epochs\"] = 15\ncfg[\"lr_config\"] = dict(\n    policy='step',\n    warmup='linear',\n    warmup_iters=500,\n    warmup_ratio=0.001,\n    step=[10, 14]\n)\n\"\"\"\n\n###############################################################################################################\n\n#store updated config file\nwith open(cfg_name, \"w\") as f:\n    f.write(cfg.pretty_text)\nprint(cfg.pretty_text)","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:20:11.692500Z","iopub.execute_input":"2022-01-26T15:20:11.692766Z","iopub.status.idle":"2022-01-26T15:20:16.669572Z","shell.execute_reply.started":"2022-01-26T15:20:11.692731Z","shell.execute_reply":"2022-01-26T15:20:16.668711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* **Copy livecell dataset if using auxiliary data**","metadata":{}},{"cell_type":"code","source":"lc_folder = \"/kaggle/input/sartorius-cell-instance-segmentation/LIVECell_dataset_2021/images/livecell_train_val_images/SHSY5Y\"\nsar_folder = \"/kaggle/input/sartorius-cell-instance-segmentation/train\"\ntarget_folder = \"/kaggle/working/data\"\n\n!rm -rf {target_folder}\n!mkdir {target_folder}\n\nimport cv2, os, shutil\nfrom tqdm import tqdm\nif \"_.py\" in cfg_name:\n    files = os.listdir(lc_folder)\n    for i in tqdm(range(len(files))):\n        fname = files[i]\n        img = cv2.imread(os.path.join(lc_folder, fname))\n        out_fname = fname.split('.')[0] + '.png'\n        cv2.imwrite(os.path.join(target_folder, out_fname), img)\n    files = os.listdir(sar_folder)\n    for i in tqdm(range(len(files))):\n        fname = files[i]\n        shutil.copy(os.path.join(sar_folder, fname), os.path.join(target_folder, fname))\nprint(\"files:\", len(os.listdir(target_folder)))","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:12:28.174584Z","iopub.execute_input":"2022-01-26T15:12:28.174891Z","iopub.status.idle":"2022-01-26T15:12:29.518262Z","shell.execute_reply.started":"2022-01-26T15:12:28.174857Z","shell.execute_reply":"2022-01-26T15:12:29.517461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* **Train model**","metadata":{}},{"cell_type":"code","source":"from mmdet.datasets import build_dataset\nfrom mmdet.models import build_detector\nfrom mmdet.apis import train_detector\nimport os\nimport albumentations\n\ndatasets = [build_dataset(cfg.data.train)]\nmodel = build_detector(cfg.model, train_cfg=cfg.get('train_cfg'), test_cfg=cfg.get('test_cfg'))\nmodel.CLASSES = datasets[0].CLASSES\n\nmmcv.mkdir_or_exist(os.path.abspath(cfg.work_dir))\ntrain_detector(model, datasets, cfg, distributed=False, validate=True, meta=dict(config=cfg.pretty_text))","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:20:16.671113Z","iopub.execute_input":"2022-01-26T15:20:16.671772Z","iopub.status.idle":"2022-01-26T15:35:56.471469Z","shell.execute_reply.started":"2022-01-26T15:20:16.671730Z","shell.execute_reply":"2022-01-26T15:35:56.468458Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# **INFERENCE**","metadata":{}},{"cell_type":"code","source":"#https://www.kaggle.com/vexxingbanana/mmdetection-neuron-inference\n#https://www.kaggle.com/qq1623620766/sartorius-mmdetection-infer#Submission\nfrom mmdet.apis import inference_detector, init_detector, show_result_pyplot, set_random_seed\nimport cupy as cp\nimport numpy as np\nimport os\nimport pandas as pd\nfrom pycocotools import mask as cocomask\nfrom tqdm import tqdm\n\n\n#convert masks to run-length-encoded masks\ndef mask2rle(msk):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    msk    = cp.array(msk)\n    pixels = msk.flatten()\n    pad    = cp.array([0])\n    pixels = cp.concatenate([pad, pixels, pad])\n    runs   = cp.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\n\n#remove mask overlaps (not allowed in the competition)\ndef remove_overlapping_pixels(new_mask, old_masks):\n    for old_mask in old_masks:\n        pixel_in_both_masks = np.logical_and(new_mask, old_mask)\n        if np.sum(pixel_in_both_masks) > 0:\n            new_mask[pixel_in_both_masks] = 0\n    return new_mask\n\n\noutput = {\"rles\": [], \"ids\": []}\nconfidence_thresholds = {0: 0.05, 1: 0.5, 2: 0.2} #confidence thresold per cell class\nchkpt_file = cfg[\"work_dir\"] + \"/latest.pth\" #select model checkpoint\nmodel = init_detector(cfg, chkpt_file)\ntest_files = sorted(os.listdir(\"/kaggle/input/sartorius-cell-instance-segmentation/test\"))\n\n#iterate over test images and perform inference\nfor file in test_files:\n    print(\"\\nTEST FILE:\", file)\n    img = mmcv.imread('/kaggle/input/sartorius-cell-instance-segmentation/test/' + file)\n    result = inference_detector(model, img)\n    masks_for_image = []\n    \n    ################################################################################\n    \n    #get class with highest confidence score in this image and use only masks from this class\n    detected_idx = -1\n    highest_cnf = 0\n    for i in range(len(result[0])):\n        print(\"class {:d} has {:d} anns\".format(i, result[0][i].shape[0]))\n        if result[0][i].shape[0] == 0:\n            continue\n        highest_cnf_for_class = result[0][i][0,4] \n        if highest_cnf_for_class > highest_cnf:\n            detected_idx = i\n            highest_cnf = highest_cnf_for_class\n\n    print(\"DETECTED INDEX:\", detected_idx)\n    if detected_idx == -1:\n        print(\"NO MASK DETECTED IN THIS IMAGE?!\")\n        continue\n    ################################################################################\n    \n    #get all predicted masks for current image\n    res_cnfs = result[0][detected_idx][:,4]\n    res_segms = result[1][detected_idx]\n    res_bbox = result[0][detected_idx][:,:4]\n    print(\"cnfs\", res_cnfs.shape, \"res_bbox\", len(res_bbox)) \n\n    for res_idx in range(len(res_bbox)):\n        cnf = res_cnfs[res_idx]\n        bbox = [int(x) for x in res_bbox[res_idx]]\n        if cnf >= confidence_thresholds[i]:\n            new_mask = np.full((img.shape[0], img.shape[1]), False)\n            for aa in range(bbox[1], bbox[3]):\n                for bb in range(bbox[0], bbox[2]):\n                    new_mask[aa, bb] = True\n            new_mask = remove_overlapping_pixels(new_mask, masks_for_image)\n            masks_for_image.append(new_mask)\n            \n    ################################################################################################\n    \n    #convert predictions to rle masks\n    for mask in masks_for_image:\n        rle_mask = mask2rle(mask)\n        output[\"rles\"].append(rle_mask)\n        output[\"ids\"].append(str(file.split('.')[0]))\n\n    \n    #store image with overlayed mask predictions\n    img_mask_overlay = np.full((520, 704), False, bool)\n    for mask in masks_for_image:\n        img_mask_overlay = np.logical_or(img_mask_overlay, mask)\n    for aa in range(img_mask_overlay.shape[0]):\n        for bb in range(img_mask_overlay.shape[1]):\n            if img_mask_overlay[aa, bb]:\n                img[aa, bb, 0] = 255\n                img[aa, bb, 1] = 0\n                img[aa, bb, 2] = 0  \n    mmcv.imwrite(img, \"/kaggle/working/\" + file)\n    \n\n#store predictions in competition format\nindexes = []\nfor i, segm in enumerate(output[\"rles\"]):\n    if segm == '':\n        indexes.append(i)\nfor element in sorted(indexes, reverse = True):\n    del output[\"rles\"][element]\n    del output[\"ids\"][element]\n    \nfiles = pd.Series(output[\"ids\"], name='id')\npreds = pd.Series(output[\"rles\"], name='predicted')\nsubmission_df = pd.concat([files, preds], axis=1)\nprint(submission_df.head())\nsubmission_df.to_csv('/kaggle/working/submission.csv', index=False)\n\nfor file in test_files:\n    print(\"final masks in file '{:s}': {:d}\".format(file, output[\"ids\"].count(str(file.split('.')[0]))))","metadata":{"execution":{"iopub.status.busy":"2022-01-26T15:38:43.828813Z","iopub.execute_input":"2022-01-26T15:38:43.829224Z","iopub.status.idle":"2022-01-26T15:38:50.235816Z","shell.execute_reply.started":"2022-01-26T15:38:43.829188Z","shell.execute_reply":"2022-01-26T15:38:50.234321Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls /kaggle/working\n!echo \"\"\n%cd /kaggle/working\n!mv {cfg[\"work_dir\"]}/* /kaggle/working\n!rm -rf {cfg[\"work_dir\"]}\n!rm -rf /kaggle/working/mmdetection\n!rm -rf /kaggle/working/data\n!echo \"\"\n!ls /kaggle/working","metadata":{"execution":{"iopub.status.busy":"2021-12-08T00:35:17.502772Z","iopub.execute_input":"2021-12-08T00:35:17.503034Z","iopub.status.idle":"2021-12-08T00:35:18.906501Z","shell.execute_reply.started":"2021-12-08T00:35:17.502998Z","shell.execute_reply":"2021-12-08T00:35:18.905685Z"},"trusted":true},"execution_count":null,"outputs":[]}]}