{"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":"# SIIM COVID-19 detection using icevision\nI am using processed JPG 512x512 image set that is produced by this notebook: https://www.kaggle.com/code/alexanderyyy/siim-covid-19-process-to-jpg-512-with-bboxes\n\nIf you want to see and compare results of the image processing, see in https://www.kaggle.com/code/alexanderyyy/visual-verification\n","metadata":{}},{"cell_type":"markdown","source":"## Trouble installation\nNeed to figure out how to do installation completely offline...","metadata":{}},{"cell_type":"code","source":"%load_ext autoreload\n%autoreload 2\n# these 2 lines above are very important, they enabled automatic reloading of the newly installed packages","metadata":{"execution":{"iopub.status.busy":"2022-12-04T12:09:07.940642Z","iopub.execute_input":"2022-12-04T12:09:07.941156Z","iopub.status.idle":"2022-12-04T12:09:08.005815Z","shell.execute_reply.started":"2022-12-04T12:09:07.941067Z","shell.execute_reply":"2022-12-04T12:09:08.004668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip download setuptools==58.0.4\n#!pip install setuptools==58.0.4","metadata":{"execution":{"iopub.status.busy":"2022-12-04T03:50:41.121730Z","iopub.execute_input":"2022-12-04T03:50:41.122219Z","iopub.status.idle":"2022-12-04T03:51:05.444520Z","shell.execute_reply.started":"2022-12-04T03:50:41.122131Z","shell.execute_reply":"2022-12-04T03:51:05.443085Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# downgrade setuptools to 58.0.4 to solve icevision installation problem\n# !conda install setuptools==58.0.4 -y","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-11-01T09:34:10.522674Z","iopub.execute_input":"2022-11-01T09:34:10.523365Z","iopub.status.idle":"2022-11-01T09:35:07.981178Z","shell.execute_reply.started":"2022-11-01T09:34:10.523313Z","shell.execute_reply":"2022-11-01T09:35:07.979152Z"},"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# install icevision offline\n# thanks to https://www.kaggle.com/datasets/abee82/icevision-essentials\n!bash ../input/icevision-essentials/icevision_kaggle_install.sh","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-12-04T12:09:14.113400Z","iopub.execute_input":"2022-12-04T12:09:14.113834Z","iopub.status.idle":"2022-12-04T12:11:20.317253Z","shell.execute_reply.started":"2022-12-04T12:09:14.113724Z","shell.execute_reply":"2022-12-04T12:11:20.315734Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install -U openmim\n!mim install mmdet","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!conda list","metadata":{"execution":{"iopub.status.busy":"2022-12-04T03:53:32.848171Z","iopub.execute_input":"2022-12-04T03:53:32.848623Z","iopub.status.idle":"2022-12-04T03:53:51.148502Z","shell.execute_reply.started":"2022-12-04T03:53:32.848587Z","shell.execute_reply":"2022-12-04T03:53:51.147409Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Restart kernel after installation\n# import IPython\n# IPython.Application.instance().kernel.do_shutdown(True)","metadata":{"execution":{"iopub.status.busy":"2022-12-04T03:56:18.421729Z","iopub.execute_input":"2022-12-04T03:56:18.422536Z","iopub.status.idle":"2022-12-04T03:56:18.432277Z","shell.execute_reply.started":"2022-12-04T03:56:18.422505Z","shell.execute_reply":"2022-12-04T03:56:18.431078Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from icevision.all import *","metadata":{"execution":{"iopub.status.busy":"2022-12-04T12:13:42.767307Z","iopub.execute_input":"2022-12-04T12:13:42.767733Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from fastai.vision.all import *\nfrom fastai.medical.imaging import *\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport pandas as pd\nimport skimage\nfrom skimage import transform, exposure, io\nimport pathlib","metadata":{"execution":{"iopub.status.busy":"2022-12-04T03:56:49.221083Z","iopub.execute_input":"2022-12-04T03:56:49.221408Z","iopub.status.idle":"2022-12-04T03:56:49.798651Z","shell.execute_reply.started":"2022-12-04T03:56:49.221380Z","shell.execute_reply":"2022-12-04T03:56:49.797283Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from icevision.all import *\n%matplotlib inline\nimport pathlib\nfastai.set_seed(8338)\nimport pandas as pd","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:27.509215Z","iopub.execute_input":"2022-11-05T09:54:27.509823Z","iopub.status.idle":"2022-11-05T09:54:27.521858Z","shell.execute_reply.started":"2022-11-05T09:54:27.509778Z","shell.execute_reply":"2022-11-05T09:54:27.520225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = Path('../input/siim-cov19-processed-jpg-512-with-updated-bboxes')\nTRAIN_PATH = str(data_dir) + '/train/'\ntrain_annotation = data_dir/'train_512_uniqueStudy.csv'","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:30.001533Z","iopub.execute_input":"2022-11-05T09:54:30.003316Z","iopub.status.idle":"2022-11-05T09:54:30.019499Z","shell.execute_reply.started":"2022-11-05T09:54:30.003141Z","shell.execute_reply":"2022-11-05T09:54:30.018479Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(train_annotation)\nlabels = list(df.label_y.unique())\ndist = [sum(df.label_y == lab) for lab in labels]\nprint(dict(zip(labels,dist)))\nexplode = [0.02, 0.1, 0.05, 0.05]\nplt.pie(dist, labels = labels, startangle = 270, explode=explode, autopct='%1.1f%%')\nplt.legend()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:33.467718Z","iopub.execute_input":"2022-11-05T09:54:33.468196Z","iopub.status.idle":"2022-11-05T09:54:33.747068Z","shell.execute_reply.started":"2022-11-05T09:54:33.468118Z","shell.execute_reply":"2022-11-05T09:54:33.743860Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Parser","metadata":{}},{"cell_type":"code","source":"template_record = ObjectDetectionRecord()\nParser.generate_template(template_record)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:37.781658Z","iopub.execute_input":"2022-11-05T09:54:37.782126Z","iopub.status.idle":"2022-11-05T09:54:37.789642Z","shell.execute_reply.started":"2022-11-05T09:54:37.782087Z","shell.execute_reply":"2022-11-05T09:54:37.788456Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# fixed size of the input image\nDSIZE = 512 \n\n# using globals: data_dir, train_annotation\n\nclass SiimCov19Parser(Parser):\n    def __init__(self, template_record, data_dir):\n        super().__init__(template_record=template_record)\n\n        self.data_dir = data_dir\n        self.df = pd.read_csv(train_annotation)\n#        self.class_map = ClassMap(['Typ', 'Atyp', 'Indet'])\n        self.class_map = ClassMap(['opacity'])\n\n    def __iter__(self) -> Any:\n        for o in self.df.itertuples():\n            yield o\n\n    def __len__(self) -> int:\n        return len(self.df)\n\n    def record_id(self, o) -> Hashable:\n        return o.id \n\n    def parse_fields(self, o, record, is_new):\n        if is_new:\n            filepath = self.data_dir / 'train' / f'{o.id}.jpg' \n            record.set_filepath(filepath)\n            record.set_img_size(ImgSize(width = DSIZE, height = DSIZE))\n            # We do not add Negative as a class - it will be 'background'\n            # But we keep negative samples\n            if pd.notnull(o.boxes) and o.label_y != 'Neg': \n                record.detection.set_class_map(self.class_map)\n                bx = eval(o.boxes)\n                record.detection.add_bboxes(\n                    [BBox.from_xywh(d['x'], d['y'], d['w'], d['h']) for d in bx])\n#                record.detection.add_labels([o.label_y for _ in range(len(bx))])\n                record.detection.add_labels(['opacity' for _ in range(len(bx))])                ","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:43.440716Z","iopub.execute_input":"2022-11-05T09:54:43.441105Z","iopub.status.idle":"2022-11-05T09:54:43.452305Z","shell.execute_reply.started":"2022-11-05T09:54:43.441072Z","shell.execute_reply":"2022-11-05T09:54:43.451181Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"parser = SiimCov19Parser(template_record, data_dir)\ndata_splitter = RandomSplitter([0.8, 0.2])\ntrain_records, valid_records = parser.parse(data_splitter)\nprint(f'Train:{len(train_records)}, Validation:{len(valid_records)}, Total:{len(train_records) + len(valid_records)}')","metadata":{"execution":{"iopub.status.busy":"2022-11-05T09:54:50.409259Z","iopub.execute_input":"2022-11-05T09:54:50.409972Z","iopub.status.idle":"2022-11-05T09:55:12.917045Z","shell.execute_reply.started":"2022-11-05T09:54:50.409934Z","shell.execute_reply":"2022-11-05T09:55:12.915959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Transforms","metadata":{}},{"cell_type":"code","source":"import albumentations as A\npresize = 512\nimage_size = 384\n\ntrain_tfms = tfms.A.Adapter([*tfms.A.aug_tfms(size=image_size, presize=presize, rgb_shift=None, crop_fn=None,\n            shift_scale_rotate=A.ShiftScaleRotate(rotate_limit=10)), tfms.A.Normalize()])\nvalid_tfms = tfms.A.Adapter([*tfms.A.resize_and_pad(size=image_size), tfms.A.Normalize()])","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:25.481105Z","iopub.execute_input":"2022-11-05T10:01:25.481908Z","iopub.status.idle":"2022-11-05T10:01:25.489388Z","shell.execute_reply.started":"2022-11-05T10:01:25.481869Z","shell.execute_reply":"2022-11-05T10:01:25.488364Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train and Validation Dataset Objects","metadata":{}},{"cell_type":"code","source":"train_ds = Dataset(train_records, train_tfms)\nvalid_ds = Dataset(valid_records, valid_tfms)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:28.232998Z","iopub.execute_input":"2022-11-05T10:01:28.233523Z","iopub.status.idle":"2022-11-05T10:01:28.242030Z","shell.execute_reply.started":"2022-11-05T10:01:28.233469Z","shell.execute_reply":"2022-11-05T10:01:28.240825Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Augmentation test","metadata":{}},{"cell_type":"code","source":"# Aug Test: display the same sample with different augmentations\nsamples = [train_ds[1] for _ in range(16)]\nshow_samples(samples, ncols=4)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:35.173546Z","iopub.execute_input":"2022-11-05T10:01:35.173906Z","iopub.status.idle":"2022-11-05T10:01:42.853992Z","shell.execute_reply.started":"2022-11-05T10:01:35.173875Z","shell.execute_reply":"2022-11-05T10:01:42.841955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model","metadata":{}},{"cell_type":"code","source":"selection = 1\n\nextra_args = {}\n\nif selection == 0:\n  model_type = models.mmdet.retinanet\n  backbone = model_type.backbones.resnet50_fpn_1x\n  fname_model = 'siim-cov19-mmdet_retinanet.pth'\n\nelif selection == 1:\n  # The Retinanet model is also implemented in the torchvision library\n  model_type = models.torchvision.retinanet\n  backbone = model_type.backbones.resnet50_fpn\n  fname_model = 'siim-cov19-torchvision_retinanet'\n\nelif selection == 2:\n  model_type = models.ross.efficientdet\n  backbone = model_type.backbones.tf_lite0\n  # The efficientdet model requires an img_size parameter\n  extra_args['img_size'] = image_size\n  fname_model = 'siim-cov19-ross-efficientdet'\n\nelif selection == 3:\n  model_type = models.ultralytics.yolov5\n  backbone = model_type.backbones.small\n  # The yolov5 model requires an img_size parameter\n  extra_args['img_size'] = image_size\n  fname_model = 'siim-cov19-yolov5-bbsmall'\n\nelif selection == 4:\n  model_type = models.ultralytics.yolov5\n  backbone = model_type.backbones.medium\n  # The yolov5 model requires an img_size parameter\n  extra_args['img_size'] = image_size\n  fname_model = 'siim-cov19-yolov5-bbmedium'\n\nelif selection == 5:\n  model_type = models.ultralytics.yolov5\n  backbone = model_type.backbones.large\n  # The yolov5 model requires an img_size parameter\n  extra_args['img_size'] = image_size\n  fname_model = 'siim-cov19-yolov5-bblarge'","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:48.643406Z","iopub.execute_input":"2022-11-05T10:01:48.643883Z","iopub.status.idle":"2022-11-05T10:01:48.660636Z","shell.execute_reply.started":"2022-11-05T10:01:48.643841Z","shell.execute_reply":"2022-11-05T10:01:48.659482Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = model_type.model(backbone=backbone(pretrained=True), \n        num_classes=len(parser.class_map), **extra_args) ","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:51.380331Z","iopub.execute_input":"2022-11-05T10:01:51.380784Z","iopub.status.idle":"2022-11-05T10:01:52.336587Z","shell.execute_reply.started":"2022-11-05T10:01:51.380744Z","shell.execute_reply":"2022-11-05T10:01:52.335496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## DataLoaders","metadata":{}},{"cell_type":"code","source":"batch_size=16\n\ntrain_dl = model_type.train_dl(train_ds, batch_size=batch_size, num_workers=4, shuffle=True)\nvalid_dl = model_type.valid_dl(valid_ds, batch_size=batch_size, num_workers=4, shuffle=False)\n\nmodel_type.show_batch(first(train_dl), ncols=4)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:01:54.473556Z","iopub.execute_input":"2022-11-05T10:01:54.474007Z","iopub.status.idle":"2022-11-05T10:02:07.568399Z","shell.execute_reply.started":"2022-11-05T10:01:54.473967Z","shell.execute_reply":"2022-11-05T10:02:07.567242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Metrics and Learner","metadata":{}},{"cell_type":"code","source":"metrics = [COCOMetric(metric_type=COCOMetricType.bbox)]\nlearn = model_type.fastai.learner(dls=[train_dl, valid_dl], model=model, metrics=metrics)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:02:15.650557Z","iopub.execute_input":"2022-11-05T10:02:15.651035Z","iopub.status.idle":"2022-11-05T10:02:15.684380Z","shell.execute_reply.started":"2022-11-05T10:02:15.650989Z","shell.execute_reply":"2022-11-05T10:02:15.683447Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Model Training","metadata":{}},{"cell_type":"code","source":"learn.lr_find()","metadata":{"execution":{"iopub.status.busy":"2022-11-01T09:49:20.289954Z","iopub.execute_input":"2022-11-01T09:49:20.290556Z","iopub.status.idle":"2022-11-01T09:54:27.755780Z","shell.execute_reply.started":"2022-11-01T09:49:20.290472Z","shell.execute_reply":"2022-11-01T09:54:27.753598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.fit_one_cycle(20, 0.0002)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T10:29:15.134598Z","iopub.execute_input":"2022-11-05T10:29:15.135087Z","iopub.status.idle":"2022-11-05T11:21:22.382818Z","shell.execute_reply.started":"2022-11-05T10:29:15.135040Z","shell.execute_reply":"2022-11-05T11:21:22.381323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"learn.save(fname_model)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Visualize Results","metadata":{}},{"cell_type":"code","source":"model_type.show_results(model, valid_ds) ","metadata":{"execution":{"iopub.status.busy":"2022-11-05T11:21:22.386208Z","iopub.execute_input":"2022-11-05T11:21:22.387261Z","iopub.status.idle":"2022-11-05T11:21:24.577853Z","shell.execute_reply.started":"2022-11-05T11:21:22.387142Z","shell.execute_reply":"2022-11-05T11:21:24.577000Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Inference pipeline From a Dataloader\ninfer_dl = model_type.infer_dl(valid_ds, batch_size=1, shuffle=False)\npreds = model_type.predict_from_dl(model, infer_dl, detection_threshold=0.25, keep_images=True)\n\nshow_preds(\n    preds=preds[:9],\n    denormalize_fn=denormalize_imagenet,\n    ncols=3\n)","metadata":{"execution":{"iopub.status.busy":"2022-11-05T11:21:24.579290Z","iopub.execute_input":"2022-11-05T11:21:24.579816Z","iopub.status.idle":"2022-11-05T11:22:12.753955Z","shell.execute_reply.started":"2022-11-05T11:21:24.579768Z","shell.execute_reply":"2022-11-05T11:22:12.753115Z"},"trusted":true},"execution_count":null,"outputs":[]}]}