{"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":"!pip install --no-index --find-links=\"../input/notebooka1d4bee082/sw\" detectron2\n!pip install --no-index --find-links=\"../input/notebooka1d4bee082/sw\" pycocotools","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:20:38.042542Z","iopub.execute_input":"2021-12-26T16:20:38.043484Z","iopub.status.idle":"2021-12-26T16:23:35.461878Z","shell.execute_reply.started":"2021-12-26T16:20:38.043374Z","shell.execute_reply":"2021-12-26T16:23:35.461037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import logging\nimport os\nfrom collections import OrderedDict\nimport torch\n\nimport detectron2\nimport detectron2.utils.comm as comm\nfrom detectron2.checkpoint import DetectionCheckpointer\nfrom detectron2.config import get_cfg\nfrom detectron2.data import MetadataCatalog\nfrom detectron2.engine import DefaultPredictor\nfrom detectron2.engine import DefaultTrainer, default_argument_parser, default_setup, hooks, launch\nfrom detectron2.modeling import GeneralizedRCNNWithTTA","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:35.464081Z","iopub.execute_input":"2021-12-26T16:23:35.465524Z","iopub.status.idle":"2021-12-26T16:23:36.518222Z","shell.execute_reply.started":"2021-12-26T16:23:35.465467Z","shell.execute_reply":"2021-12-26T16:23:36.517498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import detectron2\nimport torch\nfrom detectron2 import model_zoo\nfrom detectron2.engine import DefaultPredictor\nfrom detectron2.config import get_cfg\nfrom PIL import Image\nimport cv2\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom fastcore.all import *","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.519624Z","iopub.execute_input":"2021-12-26T16:23:36.519858Z","iopub.status.idle":"2021-12-26T16:23:36.552187Z","shell.execute_reply.started":"2021-12-26T16:23:36.519824Z","shell.execute_reply":"2021-12-26T16:23:36.551564Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from pathlib import Path\ndataDir=Path('../input/sartorius-cell-instance-segmentation')","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.55423Z","iopub.execute_input":"2021-12-26T16:23:36.554504Z","iopub.status.idle":"2021-12-26T16:23:36.558499Z","shell.execute_reply.started":"2021-12-26T16:23:36.554469Z","shell.execute_reply":"2021-12-26T16:23:36.557754Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# From https://www.kaggle.com/stainsby/fast-tested-rle\ndef rle_decode(mask_rle, shape=(520, 704)):\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\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)","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.559546Z","iopub.execute_input":"2021-12-26T16:23:36.560061Z","iopub.status.idle":"2021-12-26T16:23:36.571883Z","shell.execute_reply.started":"2021-12-26T16:23:36.560026Z","shell.execute_reply":"2021-12-26T16:23:36.571202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def paste_masks_in_image(masks, boxes, image_shape, threshold=0.5):\n    \"\"\"\n    Copy pasted from detectron2.layers.mask_ops.paste_masks_in_image and deleted thresholding of the mask\n    \"\"\"\n    assert masks.shape[-1] == masks.shape[-2], \"Only square mask predictions are supported\"\n    N = len(masks)\n    if N == 0:\n        return masks.new_empty((0,) + image_shape, dtype=torch.uint8)\n    if not isinstance(boxes, torch.Tensor):\n        boxes = boxes.tensor\n    device = boxes.device\n    assert len(boxes) == N, boxes.shape\n\n    img_h, img_w = image_shape\n\n    # The actual implementation split the input into chunks,\n    # and paste them chunk by chunk.\n    if device.type == \"cpu\":\n        # CPU is most efficient when they are pasted one by one with skip_empty=True\n        # so that it performs minimal number of operations.\n        num_chunks = N\n    else:\n        # GPU benefits from parallelism for larger chunks, but may have memory issue\n        num_chunks = int(np.ceil(N * img_h * img_w * BYTES_PER_FLOAT / GPU_MEM_LIMIT))\n        assert (\n            num_chunks <= N\n        ), \"Default GPU_MEM_LIMIT in mask_ops.py is too small; try increasing it\"\n    chunks = torch.chunk(torch.arange(N, device=device), num_chunks)\n\n    img_masks = torch.zeros(\n        N, img_h, img_w, device=device, dtype=torch.float32\n    )\n    for inds in chunks:\n        masks_chunk, spatial_inds = _do_paste_mask(\n            masks[inds, None, :, :], boxes[inds], img_h, img_w, skip_empty=device.type == \"cpu\"\n        )\n        img_masks[(inds,) + spatial_inds] = masks_chunk\n    return img_masks\n\ndetectron2.layers.mask_ops.paste_masks_in_image.__code__ = paste_masks_in_image.__code__","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.573179Z","iopub.execute_input":"2021-12-26T16:23:36.573749Z","iopub.status.idle":"2021-12-26T16:23:36.58447Z","shell.execute_reply.started":"2021-12-26T16:23:36.573682Z","shell.execute_reply":"2021-12-26T16:23:36.583806Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_masks(fn):\n    im = cv2.imread(str(fn))\n    pred = predictor_main(im)\n    pred_class = pred[\"instances\"].pred_classes.mode().values.item()\n    if pred_class == 1:\n        pred = predictor_sh(im)\n    elif pred_class == 2:\n        pred = predictor_astro(im)\n    else:\n        pred = predictor_main_2(im)\n        \n    ## BB thresh\n    take = pred['instances'].scores >= THRESHOLDS[pred_class]\n    pred_masks = pred['instances'].pred_masks[take]\n    \n    ## Seg thresh\n    pred_masks = pred_masks.cpu().numpy()\n    pred_masks[pred_masks >= THRESHOLDS_SEG[pred_class]] = 1\n    pred_masks[pred_masks < THRESHOLDS_SEG[pred_class]] = 0\n    pred_masks = pred_masks.astype(np.uint8)\n\n    res = []\n    used = np.zeros(im.shape[:2], dtype=int) \n    for mask in pred_masks:\n        mask = mask * (1-used)\n        if mask.sum() >= MIN_PIXELS[pred_class]: # skip predictions with small area\n            used += mask\n            res.append(rle_encode(mask))\n    return res","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.585871Z","iopub.execute_input":"2021-12-26T16:23:36.58616Z","iopub.status.idle":"2021-12-26T16:23:36.597405Z","shell.execute_reply.started":"2021-12-26T16:23:36.586125Z","shell.execute_reply":"2021-12-26T16:23:36.596672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"ids, masks=[],[]\ntest_names = [n for n in (dataDir/'test').iterdir()]\ntrain_names = [n for n in (dataDir/'train').iterdir()]","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.598467Z","iopub.execute_input":"2021-12-26T16:23:36.598765Z","iopub.status.idle":"2021-12-26T16:23:36.641834Z","shell.execute_reply.started":"2021-12-26T16:23:36.59873Z","shell.execute_reply":"2021-12-26T16:23:36.641205Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Initiate a Predictor from our trained model","metadata":{}},{"cell_type":"code","source":"conf_file = \"../input/cas-config/cas_config.yaml\"","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.643113Z","iopub.execute_input":"2021-12-26T16:23:36.64336Z","iopub.status.idle":"2021-12-26T16:23:36.64695Z","shell.execute_reply.started":"2021-12-26T16:23:36.64331Z","shell.execute_reply":"2021-12-26T16:23:36.646351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cfg = get_cfg()\n\ncfg2 = get_cfg()\n\ncfg.merge_from_file(conf_file)\n\ncfg2.merge_from_file(model_zoo.get_config_file(\"COCO-InstanceSegmentation/mask_rcnn_R_50_FPN_3x.yaml\"))\n\n\n","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.649923Z","iopub.execute_input":"2021-12-26T16:23:36.650526Z","iopub.status.idle":"2021-12-26T16:23:36.698536Z","shell.execute_reply.started":"2021-12-26T16:23:36.650488Z","shell.execute_reply":"2021-12-26T16:23:36.697926Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls ../input/seg-models","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:36.699715Z","iopub.execute_input":"2021-12-26T16:23:36.699952Z","iopub.status.idle":"2021-12-26T16:23:37.375926Z","shell.execute_reply.started":"2021-12-26T16:23:36.69992Z","shell.execute_reply":"2021-12-26T16:23:37.375098Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Look at the outputs on a sample test file to sanity check\nI'm encoding here in the competition format and decoding back to bit mask just to make sure everything is fine","metadata":{}},{"cell_type":"code","source":"# cfg.TEST.AUG.MIN_SIZES = [800, 800, 500]\n# cfg.TEST.AUG.MAX_SIZE = 10000\n# cfg.TEST.AUG.FLIP = False\n\nTHRESHOLDS = [.58, .27, .55]\nMIN_PIXELS = [75, 75, 150]\nTHRESHOLDS_SEG = [0.5, 0.45, 0.4]","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:37.377586Z","iopub.execute_input":"2021-12-26T16:23:37.377854Z","iopub.status.idle":"2021-12-26T16:23:37.382728Z","shell.execute_reply.started":"2021-12-26T16:23:37.37782Z","shell.execute_reply":"2021-12-26T16:23:37.381989Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cfg2.INPUT.MASK_FORMAT='bitmask'\n# 3 predictors\n# main one\ncfg2.MODEL.WEIGHTS = os.path.join('../input/detectron2finmodels/', \"model_0005999.pth\")\ncfg2.MODEL.ROI_HEADS.NUM_CLASSES = 3\ncfg2.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.58\npredictor_main_2 = DefaultPredictor(cfg2)\n# predictor_main.model = GeneralizedRCNNWithTTA(cfg, predictor_main.model)\n\ncfg.INPUT.MASK_FORMAT='bitmask'\n# 3 predictors\n# main one\ncfg.MODEL.WEIGHTS = os.path.join('../input/seg-models', \"model_0004999_aug.pth\")\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = 3\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.55\npredictor_main = DefaultPredictor(cfg)\n# predictor_main.model = GeneralizedRCNNWithTTA(cfg, predictor_main.model)\n\n# Astro\ncfg.MODEL.WEIGHTS = os.path.join('../input/seg-models', \"model_0001175_astro_aug1.pth\")\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = 1\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5\npredictor_astro = DefaultPredictor(cfg)\n# predictor_astro.model = GeneralizedRCNNWithTTA(cfg, predictor_astro.model)\n\n# Sh\ncfg.MODEL.WEIGHTS =  os.path.join('../input/seg-models', \"model_0003363_sh_pretrained.pth\")\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = 1\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.27\npredictor_sh = DefaultPredictor(cfg)\n# predictor_sh.model = GeneralizedRCNNWithTTA(cfg, predictor_sh.model)\n\n","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:23:37.384201Z","iopub.execute_input":"2021-12-26T16:23:37.384716Z","iopub.status.idle":"2021-12-26T16:24:18.599917Z","shell.execute_reply.started":"2021-12-26T16:23:37.384679Z","shell.execute_reply":"2021-12-26T16:24:18.599112Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def decode_rle_mask(rle_mask, shape):\n\n    \"\"\"\n    Decode run-length encoded segmentation mask string into 2d array\n\n    Parameters\n    ----------\n    rle_mask (str): Run-length encoded segmentation mask string\n    shape (tuple): Height and width of the mask\n\n    Returns\n    -------\n    mask [numpy.ndarray of shape (height, width)]: Decoded 2d segmentation mask\n    \"\"\"\n\n    rle_mask = rle_mask.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (rle_mask[0:][::2], rle_mask[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n\n    mask = np.zeros((shape[0] * shape[1]), dtype=np.uint8)\n    for start, end in zip(starts, ends):\n        mask[start:end] = 1\n\n    mask = mask.reshape(shape[0], shape[1])\n    return mask","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:24:18.60158Z","iopub.execute_input":"2021-12-26T16:24:18.60185Z","iopub.status.idle":"2021-12-26T16:24:18.609734Z","shell.execute_reply.started":"2021-12-26T16:24:18.601816Z","shell.execute_reply":"2021-12-26T16:24:18.608983Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# idx = 6","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:24:18.610979Z","iopub.execute_input":"2021-12-26T16:24:18.611865Z","iopub.status.idle":"2021-12-26T16:24:18.619028Z","shell.execute_reply.started":"2021-12-26T16:24:18.611798Z","shell.execute_reply":"2021-12-26T16:24:18.618331Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"encoded_masks = get_masks(test_names[0])\n\n_, axs = plt.subplots(1,2, figsize=(40,15))\naxs[1].imshow(cv2.imread(str(test_names[0])))\nfor enc in encoded_masks:\n    dec = rle_decode(enc)\n    axs[0].imshow(np.ma.masked_where(dec==0, dec))","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:24:18.620556Z","iopub.execute_input":"2021-12-26T16:24:18.62084Z","iopub.status.idle":"2021-12-26T16:25:04.152776Z","shell.execute_reply.started":"2021-12-26T16:24:18.620801Z","shell.execute_reply":"2021-12-26T16:25:04.151259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Looks good, so lets generate masks for all the files and create a submission","metadata":{}},{"cell_type":"code","source":"for fn in test_names:\n    encoded_masks = get_masks(fn)\n    for enc in encoded_masks:\n        ids.append(fn.stem)\n        masks.append(enc)","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:25:04.153741Z","iopub.execute_input":"2021-12-26T16:25:04.153952Z","iopub.status.idle":"2021-12-26T16:25:08.50221Z","shell.execute_reply.started":"2021-12-26T16:25:04.153924Z","shell.execute_reply":"2021-12-26T16:25:08.501373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.DataFrame({'id':ids, 'predicted':masks}).to_csv('submission.csv', index=False)\npd.read_csv('submission.csv').head()","metadata":{"execution":{"iopub.status.busy":"2021-12-26T16:25:08.503479Z","iopub.execute_input":"2021-12-26T16:25:08.50375Z","iopub.status.idle":"2021-12-26T16:25:08.649741Z","shell.execute_reply.started":"2021-12-26T16:25:08.503715Z","shell.execute_reply":"2021-12-26T16:25:08.648901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}