{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":52279,"databundleVersionId":5822112,"sourceType":"competition"},{"sourceId":5905549,"sourceType":"datasetVersion","datasetId":3391298},{"sourceId":6056210,"sourceType":"datasetVersion","datasetId":3465237},{"sourceId":6085957,"sourceType":"datasetVersion","datasetId":3484793},{"sourceId":6225321,"sourceType":"datasetVersion","datasetId":3575473},{"sourceId":6225623,"sourceType":"datasetVersion","datasetId":3575833},{"sourceId":6225706,"sourceType":"datasetVersion","datasetId":3575870},{"sourceId":6226761,"sourceType":"datasetVersion","datasetId":3575901},{"sourceId":7079640,"sourceType":"datasetVersion","datasetId":3876808}],"dockerImageVersionId":30528,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -q --no-index /kaggle/input/mmdetv3-env/archive/addict-2.4.0-py3-none-any.whl\n# !pip install -q --no-index /kaggle/input/mmdetv3-env/archive/mmengine-0.7.4-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/vasculature-packages/mmengine-0.8.3-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/mmdetv3-env/archive/mmcv-2.0.0-cp310-cp310-linux_x86_64.whl\n!pip install -q --no-index /kaggle/input/mmdetv3-env/archive/terminaltables-3.1.10-py2.py3-none-any.whl\n!pip install -q --no-index /kaggle/input/pycocotools-206/wheels/pycocotools-2.0.6-cp310-cp310-linux_x86_64.whl\n!pip install -q --no-index /kaggle/input/mmdetection-3-1-evn/src/mmdet-3.1.0-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/vasculature-packages/ensemble_boxes-1.0.9-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:20:57.370184Z","iopub.execute_input":"2023-11-29T06:20:57.370455Z","iopub.status.idle":"2023-11-29T06:22:20.342361Z","shell.execute_reply.started":"2023-11-29T06:20:57.370429Z","shell.execute_reply":"2023-11-29T06:22:20.34122Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -q --no-index /kaggle/input/vasculature-packages/ordered_set-4.1.0-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/vasculature-packages/model_index-0.1.11-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/vasculature-packages/einops-0.6.1-py3-none-any.whl\n!pip install -q --no-index /kaggle/input/vasculature-packages/mat4py-0.5.0-py2.py3-none-any.whl\n!pip install --no-deps --no-index /kaggle/input/vasculature-packages/mmpretrain-1.0.1-py2.py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:22:40.166984Z","iopub.execute_input":"2023-11-29T06:22:40.16791Z","iopub.status.idle":"2023-11-29T06:23:28.639708Z","shell.execute_reply.started":"2023-11-29T06:22:40.167875Z","shell.execute_reply":"2023-11-29T06:23:28.638435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import glob\nimport os\n\nimport mmengine\n\n\ndef prepare_dataset():\n    coco = {\n        'info': {},\n        'categories': [{\n            'id': 0,\n            'name': 'blood_vessel',\n        },{\n            'id': 1,\n            'name': 'glomerulus',\n        },{\n            'id': 2,\n            'name': 'unsure'\n        }],\n        'annotations': []\n    }\n    test_imgs = glob.glob('/kaggle/input/hubmap-hacking-the-human-vasculature/test/*.tif')\n    img_infos = []\n    img_id = 0\n    for path in test_imgs:\n        filename = os.path.basename(path)\n        img_info = dict(\n            id=img_id,\n            width=512,\n            height=512,\n            file_name=filename,\n        )\n        img_infos.append(img_info)\n        img_id += 1\n    coco['images'] = img_infos\n    return coco\n\n\nmmengine.dump(prepare_dataset(), '/kaggle/working/test.json')","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:23:31.891246Z","iopub.execute_input":"2023-11-29T06:23:31.891636Z","iopub.status.idle":"2023-11-29T06:23:32.118706Z","shell.execute_reply.started":"2023-11-29T06:23:31.891601Z","shell.execute_reply":"2023-11-29T06:23:32.117708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile test.py\n\n# Copyright (c) OpenMMLab. All rights reserved.\nimport argparse\nimport os\nimport os.path as osp\nimport warnings\nfrom copy import deepcopy\n\nfrom mmengine import ConfigDict\nfrom mmengine.config import Config, DictAction\nfrom mmengine.runner import Runner\n\nfrom mmdet.engine.hooks.utils import trigger_visualization_hook\nfrom mmdet.evaluation import DumpDetResults\nfrom mmdet.registry import RUNNERS\nfrom mmdet.utils import setup_cache_size_limit_of_dynamo\n\n\n# TODO: support fuse_conv_bn and format_only\ndef parse_args():\n    parser = argparse.ArgumentParser(\n        description='MMDet test (and eval) a model')\n    parser.add_argument('config', help='test config file path')\n    parser.add_argument('checkpoint', help='checkpoint file')\n    parser.add_argument(\n        '--work-dir',\n        help='the directory to save the file containing evaluation metrics')\n    parser.add_argument(\n        '--out',\n        type=str,\n        help='dump predictions to a pickle file for offline evaluation')\n    parser.add_argument(\n        '--show', action='store_true', help='show prediction results')\n    parser.add_argument(\n        '--show-dir',\n        help='directory where painted images will be saved. '\n        'If specified, it will be automatically saved '\n        'to the work_dir/timestamp/show_dir')\n    parser.add_argument(\n        '--wait-time', type=float, default=2, help='the interval of show (s)')\n    parser.add_argument(\n        '--cfg-options',\n        nargs='+',\n        action=DictAction,\n        help='override some settings in the used config, the key-value pair '\n        'in xxx=yyy format will be merged into config file. If the value to '\n        'be overwritten is a list, it should be like key=\"[a,b]\" or key=a,b '\n        'It also allows nested list/tuple values, e.g. key=\"[(a,b),(c,d)]\" '\n        'Note that the quotation marks are necessary and that no white space '\n        'is allowed.')\n    parser.add_argument(\n        '--launcher',\n        choices=['none', 'pytorch', 'slurm', 'mpi'],\n        default='none',\n        help='job launcher')\n    parser.add_argument('--tta', action='store_true')\n    # When using PyTorch version >= 2.0.0, the `torch.distributed.launch`\n    # will pass the `--local-rank` parameter to `tools/train.py` instead\n    # of `--local_rank`.\n    parser.add_argument('--local_rank', '--local-rank', type=int, default=0)\n    args = parser.parse_args()\n    if 'LOCAL_RANK' not in os.environ:\n        os.environ['LOCAL_RANK'] = str(args.local_rank)\n    return args\n\n\ndef main():\n    args = parse_args()\n\n    # Reduce the number of repeated compilations and improve\n    # testing speed.\n    setup_cache_size_limit_of_dynamo()\n\n    # load config\n    cfg = Config.fromfile(args.config)\n    cfg.launcher = args.launcher\n    if args.cfg_options is not None:\n        cfg.merge_from_dict(args.cfg_options)\n\n    # work_dir is determined in this priority: CLI > segment in file > filename\n    if args.work_dir is not None:\n        # update configs according to CLI args if args.work_dir is not None\n        cfg.work_dir = args.work_dir\n    elif cfg.get('work_dir', None) is None:\n        # use config filename as default work_dir if cfg.work_dir is None\n        cfg.work_dir = osp.join('./work_dirs',\n                                osp.splitext(osp.basename(args.config))[0])\n\n    if args.checkpoint != 'none':\n        cfg.load_from = args.checkpoint\n\n    if args.show or args.show_dir:\n        cfg = trigger_visualization_hook(cfg, args)\n\n    if args.tta:\n\n        if 'tta_model' not in cfg:\n            warnings.warn('Cannot find ``tta_model`` in config, '\n                          'we will set it as default.')\n            cfg.tta_model = dict(\n                type='DetTTAModel',\n                tta_cfg=dict(\n                    nms=dict(type='nms', iou_threshold=0.5), max_per_img=100))\n        if 'tta_pipeline' not in cfg:\n            warnings.warn('Cannot find ``tta_pipeline`` in config, '\n                          'we will set it as default.')\n            test_data_cfg = cfg.test_dataloader.dataset\n            while 'dataset' in test_data_cfg:\n                test_data_cfg = test_data_cfg['dataset']\n            cfg.tta_pipeline = deepcopy(test_data_cfg.pipeline)\n            flip_tta = dict(\n                type='TestTimeAug',\n                transforms=[\n                    [\n                        dict(type='RandomFlip', prob=1.),\n                        dict(type='RandomFlip', prob=0.)\n                    ],\n                    [\n                        dict(\n                            type='PackDetInputs',\n                            meta_keys=('img_id', 'img_path', 'ori_shape',\n                                       'img_shape', 'scale_factor', 'flip',\n                                       'flip_direction'))\n                    ],\n                ])\n            cfg.tta_pipeline[-1] = flip_tta\n        cfg.model = ConfigDict(**cfg.tta_model, module=cfg.model)\n        cfg.test_dataloader.dataset.pipeline = cfg.tta_pipeline\n\n    # build the runner from config\n    if 'runner_type' not in cfg:\n        # build the default runner\n        runner = Runner.from_cfg(cfg)\n    else:\n        # build customized runner from the registry\n        # if 'runner_type' is set in the cfg\n        runner = RUNNERS.build(cfg)\n\n    # add `DumpResults` dummy metric\n    if args.out is not None:\n        assert args.out.endswith(('.pkl', '.pickle')), \\\n            'The dump file must be a pkl file.'\n        runner.test_evaluator.metrics.append(\n            DumpDetResults(out_file_path=args.out))\n\n    # start testing\n    runner.test()\n\n\nif __name__ == '__main__':\n    main()\n","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:23:36.887452Z","iopub.execute_input":"2023-11-29T06:23:36.887825Z","iopub.status.idle":"2023-11-29T06:23:36.897785Z","shell.execute_reply.started":"2023-11-29T06:23:36.887795Z","shell.execute_reply":"2023-11-29T06:23:36.896856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cp -r /kaggle/input/hubmap-2023-modules /kaggle/working/hubmap_modules","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:23:43.496519Z","iopub.execute_input":"2023-11-29T06:23:43.496893Z","iopub.status.idle":"2023-11-29T06:23:44.457499Z","shell.execute_reply.started":"2023-11-29T06:23:43.496863Z","shell.execute_reply":"2023-11-29T06:23:44.456222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls /kaggle/working/hubmap_modules/","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:23:47.210261Z","iopub.execute_input":"2023-11-29T06:23:47.21119Z","iopub.status.idle":"2023-11-29T06:23:48.152139Z","shell.execute_reply.started":"2023-11-29T06:23:47.21115Z","shell.execute_reply":"2023-11-29T06:23:48.150864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python test.py \\\n    /kaggle/input/hubmap-2023-configs/m0i.py \\\n    /kaggle/input/hubmap/m0i.pth \\\n    --out /kaggle/working/m0i.pkl","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:23:52.539901Z","iopub.execute_input":"2023-11-29T06:23:52.540378Z","iopub.status.idle":"2023-11-29T06:24:32.885571Z","shell.execute_reply.started":"2023-11-29T06:23:52.540336Z","shell.execute_reply":"2023-11-29T06:24:32.884543Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python test.py \\\n    /kaggle/input/hubmap-2023-configs/r0i.py \\\n    /kaggle/input/hubmap/r0i.pth \\\n    --out /kaggle/working/r0i.pkl","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:24:46.689294Z","iopub.execute_input":"2023-11-29T06:24:46.689692Z","iopub.status.idle":"2023-11-29T06:25:12.520073Z","shell.execute_reply.started":"2023-11-29T06:24:46.689658Z","shell.execute_reply":"2023-11-29T06:25:12.519044Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport mmengine\nfrom ensemble_boxes import weighted_boxes_fusion\n\nresults = [\n    mmengine.load(f'/kaggle/working/{name}.pkl') for name in\n    ['r0i', 'm0i']\n]\nweights = [\n    2, 1\n]\n\nSCALER = 10000\nIOU_THR = 0.7\n\nfor rs in zip(*results):\n    boxes_list = [(r['pred_instances']['bboxes'] / SCALER).tolist() for r in rs]\n    scores_list = [r['pred_instances']['scores'].tolist() for r in rs]\n    labels_list = [r['pred_instances']['labels'].tolist() for r in rs]\n    boxes, scores, labels = weighted_boxes_fusion(boxes_list,\n                                                scores_list,\n                                                labels_list,\n                                                weights=weights,\n                                                iou_thr=IOU_THR,\n                                                conf_type='avg')\n    pred_instances = dict(\n        bboxes=torch.from_numpy(boxes).float() * SCALER,\n        scores=torch.from_numpy(scores).float(),\n        labels=torch.from_numpy(labels).long(),\n    )\n    rs[0]['pred_instances'] = pred_instances\n\nensemble_result = results[0]\n\nmmengine.dump(ensemble_result, 'ensemble.pkl')","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:25:37.569492Z","iopub.execute_input":"2023-11-29T06:25:37.57041Z","iopub.status.idle":"2023-11-29T06:25:40.020198Z","shell.execute_reply.started":"2023-11-29T06:25:37.570374Z","shell.execute_reply":"2023-11-29T06:25:40.019255Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile predict_mask.py\n\nimport mmcv\nimport mmengine\nimport torch\nfrom mmengine.runner import load_checkpoint\nfrom mmengine.structures.instance_data import InstanceData\nfrom mmdet.registry import MODELS\nfrom mmdet.structures import DetDataSample\nfrom mmdet.structures.mask import encode_mask_results\nfrom mmdet.utils import register_all_modules\n\nregister_all_modules()\ncfg = mmengine.Config.fromfile('/kaggle/input/hubmap-2023-configs/m0i.py')\nmodel = MODELS.build(cfg.model)\nload_checkpoint(model, '/kaggle/input/hubmap/m0i.pth')\nmodel.eval()\nmodel.cuda()\n\n\n@torch.no_grad()\ndef predict_mask(result, input_size=(1440, 1440)):\n    img = mmcv.imread(result['img_path'])\n    img = mmcv.imresize(img, input_size)\n    batch_data = dict(\n        inputs=torch.from_numpy(img).permute(2, 0, 1).unsqueeze(0).cuda(),\n        data_samples=[\n            DetDataSample(metainfo=dict(img_id=result['img_id'],\n                                        ori_shape=(512, 512),\n                                        img_shape=(1440, 1440),\n                                        img_path=result['img_path'],\n                                        scale_factor=(1440 / 512, 1440 / 512)))\n        ])\n    batch_data = model.data_preprocessor(batch_data, False)\n    batch_data_inputs = batch_data['inputs']\n    batch_data_samples = batch_data['data_samples']\n    batch_img_metas = [\n        data_samples.metainfo for data_samples in batch_data_samples\n    ]\n    img_feats = model.extract_feat(batch_data_inputs)\n\n    img_result = InstanceData()\n    for k, v in result['pred_instances'].items():\n        img_result[k] = v.cuda()\n    img_result.bboxes *= 1440 / 512\n    results_list = model.roi_head.predict_mask(img_feats,\n                                               batch_img_metas, [img_result],\n                                               rescale=True)\n    out = results_list[0].cpu()\n    ret = dict(img_id=result['img_id'],\n               ori_shape=(512, 512),\n               img_shape=(1440, 1440),\n               img_path=result['img_path'],\n               scale_factor=(1440 / 512, 1440 / 512))\n    ret['pred_instances'] = dict(\n        bboxes=out['bboxes'],\n        labels=out['labels'],\n        scores=out['scores'],\n        masks=encode_mask_results(out['masks'])\n    )\n    return ret\n\n\nresults = mmengine.load('/kaggle/working/ensemble.pkl')\noutputs = []\nfor result in results:\n    output = predict_mask(result)\n    outputs.append(output)\nmmengine.dump(outputs, '/kaggle/working/ensemble_results.pkl')","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:25:46.616765Z","iopub.execute_input":"2023-11-29T06:25:46.617631Z","iopub.status.idle":"2023-11-29T06:25:46.625516Z","shell.execute_reply.started":"2023-11-29T06:25:46.617594Z","shell.execute_reply":"2023-11-29T06:25:46.624446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python predict_mask.py","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:25:53.111005Z","iopub.execute_input":"2023-11-29T06:25:53.111397Z","iopub.status.idle":"2023-11-29T06:26:11.645102Z","shell.execute_reply.started":"2023-11-29T06:25:53.111367Z","shell.execute_reply":"2023-11-29T06:26:11.644078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import base64\nimport numpy as np\nfrom pycocotools import _mask as coco_mask\nimport typing as t\nimport zlib\n\n\ndef encode_binary_mask(mask: np.ndarray) -> t.Text:\n  \"\"\"Converts a binary mask into OID challenge encoding ascii text.\"\"\"\n\n  # check input mask --\n  if mask.dtype != np.bool:\n    raise ValueError(\n        \"encode_binary_mask expects a binary mask, received dtype == %s\" %\n        mask.dtype)\n\n  mask = np.squeeze(mask)\n  if len(mask.shape) != 2:\n    raise ValueError(\n        \"encode_binary_mask expects a 2d mask, received shape == %s\" %\n        mask.shape)\n\n  # convert input mask to expected COCO API input --\n  mask_to_encode = mask.reshape(mask.shape[0], mask.shape[1], 1)\n  mask_to_encode = mask_to_encode.astype(np.uint8)\n  mask_to_encode = np.asfortranarray(mask_to_encode)\n\n  # RLE encode mask --\n  encoded_mask = coco_mask.encode(mask_to_encode)[0][\"counts\"]\n\n  # compress and base64 encoding --\n  binary_str = zlib.compress(encoded_mask, zlib.Z_BEST_COMPRESSION)\n  base64_str = base64.b64encode(binary_str)\n  return base64_str\n","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:26:17.703509Z","iopub.execute_input":"2023-11-29T06:26:17.703912Z","iopub.status.idle":"2023-11-29T06:26:17.715626Z","shell.execute_reply.started":"2023-11-29T06:26:17.70388Z","shell.execute_reply":"2023-11-29T06:26:17.714628Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport mmcv\nimport mmengine\nimport pandas as pd\nimport pycocotools.mask as mask_utils\n\nresults = mmengine.load('/kaggle/working/ensemble_results.pkl')\nids = []\nHEIGHT = 512\nWIDTH = 512\nprediction_strings = []\nfor result in results:\n    img_path = result['img_path']\n    filename = os.path.basename(img_path)\n    ids.append(filename[:-4])\n    pred_instances = result['pred_instances']\n    bboxes = pred_instances['bboxes']\n    scores = pred_instances['scores'].tolist()\n    labels = pred_instances['labels'].tolist()\n    masks = pred_instances['masks']\n    instance_strings = []\n    for label, score, mask in zip(labels, scores, masks):\n        if label != 0:\n            continue\n        mask = mask_utils.decode(mask).astype(bool)\n        mask_string = encode_binary_mask(mask).decode('utf-8')\n        \n        instance_string = f'{label} {score} {mask_string}'\n        instance_strings.append(instance_string)\n    prediction_strings.append(' '.join(instance_strings))\n","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:26:25.408469Z","iopub.execute_input":"2023-11-29T06:26:25.409186Z","iopub.status.idle":"2023-11-29T06:26:25.662173Z","shell.execute_reply.started":"2023-11-29T06:26:25.409152Z","shell.execute_reply":"2023-11-29T06:26:25.661167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub = pd.DataFrame(dict(\n    id=ids,\n    height=[HEIGHT] * len(ids),\n    width=[WIDTH] * len(ids),\n    prediction_string=prediction_strings\n))","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:26:38.168059Z","iopub.execute_input":"2023-11-29T06:26:38.168455Z","iopub.status.idle":"2023-11-29T06:26:38.177776Z","shell.execute_reply.started":"2023-11-29T06:26:38.168426Z","shell.execute_reply":"2023-11-29T06:26:38.17688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub.to_csv('submission.csv', index=False)","metadata":{"execution":{"iopub.status.busy":"2023-11-29T06:26:40.77889Z","iopub.execute_input":"2023-11-29T06:26:40.779307Z","iopub.status.idle":"2023-11-29T06:26:40.792891Z","shell.execute_reply.started":"2023-11-29T06:26:40.779272Z","shell.execute_reply":"2023-11-29T06:26:40.791809Z"},"trusted":true},"execution_count":null,"outputs":[]}]}