{"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":"# Intro\n\nCompetition home page: https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/overview","metadata":{}},{"cell_type":"markdown","source":"# Import library","metadata":{}},{"cell_type":"code","source":"# Install detecton2\n# No pre-build for tocrch 1.9.1 and cuda 11.0. Consider cpu instead.\n#!pip install detectron2 -f \\\n#  https://dl.fbaipublicfiles.com/detectron2/wheels/cpu/torch1.9/index.html\n\n!python -m pip install 'git+https://github.com/facebookresearch/detectron2.git'","metadata":{"_kg_hide-output":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-12-01T13:32:01.020207Z","iopub.execute_input":"2022-12-01T13:32:01.020486Z","iopub.status.idle":"2022-12-01T13:35:05.74508Z","shell.execute_reply.started":"2022-12-01T13:32:01.020455Z","shell.execute_reply":"2022-12-01T13:35:05.744206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"! unzip \"/kaggle/input/vinbigdata-fusing-bboxes-coco-dataset/vinbigdata-coco-dataset-with-wbf-3x-downscaled.zip\"","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:25:43.367673Z","iopub.execute_input":"2022-12-01T13:25:43.368335Z","iopub.status.idle":"2022-12-01T13:25:59.048188Z","shell.execute_reply.started":"2022-12-01T13:25:43.368239Z","shell.execute_reply":"2022-12-01T13:25:59.047358Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"path[:-1]+'_resized/'","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:30:26.18251Z","iopub.execute_input":"2022-12-01T13:30:26.182784Z","iopub.status.idle":"2022-12-01T13:30:26.190283Z","shell.execute_reply.started":"2022-12-01T13:30:26.182751Z","shell.execute_reply":"2022-12-01T13:30:26.189571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\nimport os, sys\n\ndef resize(path):\n    dirs = os.listdir(path)\n    if not os.path.exists(path[:-1]+'_resized/'):\n        os.makedirs(path[:-1]+'_resized/')\n    for item in dirs:\n        #print(path+item)\n        \n        if os.path.isfile(path+item):\n            im = Image.open(path+item)\n            f, e = os.path.splitext(path+item)\n            imResize = im.resize((256,256), Image.ANTIALIAS)\n            #print(path[:-1]+'_resized/'+f.split('/')[-1] + '.jpg')\n            imResize.save(path[:-1]+'_resized/'+f.split('/')[-1] + '.jpg', 'JPEG', quality=90)\n\nresize(\"/kaggle/working/train_images/\")\nresize(\"/kaggle/working/val_images/\")","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:30:37.796682Z","iopub.execute_input":"2022-12-01T13:30:37.797253Z","iopub.status.idle":"2022-12-01T13:31:36.864362Z","shell.execute_reply.started":"2022-12-01T13:30:37.797214Z","shell.execute_reply":"2022-12-01T13:31:36.863502Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convert_coco_json_to_csv_(filename):\n    import pandas as pd\n    import json\n    \n    # COCO2017/annotations/instances_val2017.json\n    s = json.load(open(filename, 'r'))\n    out_file = filename.split('/')[-1][:-5] + '_meta.csv'\n    out = open(out_file, 'w')\n    out.write('image_id, dim0, dim1\\n')\n\n    all_ids = []\n    for im in s['images']:\n        all_ids.append(im['file_name'].split('/')[-1][:-4])\n        all_ids.append(im['height'])\n        all_ids.append(im['width'])\n\n    all_ids_ann = []\n    for ann in s['annotations']:\n        image_id = im['file_name'].split('/')[-1][:-4]\n        height = im['height']\n        width = im['width']\n\n        out.write('{},{},{}\\n'.format(image_id,height,width))\n\n    all_ids = set(all_ids)\n    all_ids_ann = set(all_ids_ann)\n    no_annotations = list(all_ids - all_ids_ann)\n    # Output images without any annotations\n    for image_id in no_annotations:\n        out.write('{},{},{}\\n'.format(image_id,height,width))\n    out.close()\n\n    # Sort file by image id\n    s1 = pd.read_csv(out_file)\n    s1.sort_values('image_id', inplace=True)\n    s1.to_csv(out_file, index=False)\n    \nconvert_coco_json_to_csv_(\"/kaggle/working/train_annotations.json\")\nconvert_coco_json_to_csv_(\"/kaggle/working/val_annotations.json\")","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:31:45.412511Z","iopub.execute_input":"2022-12-01T13:31:45.41277Z","iopub.status.idle":"2022-12-01T13:31:45.739964Z","shell.execute_reply.started":"2022-12-01T13:31:45.412741Z","shell.execute_reply":"2022-12-01T13:31:45.739196Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"labels =  [\n            \"Aortic_enlargement\",\n            \"Atelectasis\",\n            \"Calcification\",\n            \"Cardiomegaly\",\n            \"Consolidation\",\n            \"ILD\",\n            \"Infiltration\",\n            \"Lung_Opacity\",\n            \"Nodule_Mass\",\n            \"Other_lesion\",\n            \"Pleural_effusion\",\n            \"Pleural_thickening\",\n            \"Pneumothorax\",\n            \"Pulmonary_fibrosis\"\n            ]","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:31:46.632727Z","iopub.execute_input":"2022-12-01T13:31:46.63334Z","iopub.status.idle":"2022-12-01T13:31:46.637596Z","shell.execute_reply.started":"2022-12-01T13:31:46.633302Z","shell.execute_reply":"2022-12-01T13:31:46.636735Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convert_coco_json_to_csv(filename):\n    import pandas as pd\n    import json\n    \n    # COCO2017/annotations/instances_val2017.json\n    s = json.load(open(filename, 'r'))\n    out_file = filename.split('/')[-1][:-5] + '.csv'\n    out = open(out_file, 'w')\n    out.write('image_id, class_name, class_id, x_min, y_min, x_max, y_max\\n')\n\n    all_ids = []\n    for im in s['images']:\n        all_ids.append(im['file_name'].split('/')[-1][:-4])\n\n    all_ids_ann = []\n    for ann in s['annotations']:\n        image_id = im['file_name'].split('/')[-1][:-4]\n        #print(image_id)\n        all_ids_ann.append(image_id)\n        x_min = ann['bbox'][0]\n        x_max = ann['bbox'][0] + ann['bbox'][2]\n        y_min = ann['bbox'][1]\n        y_max = ann['bbox'][1] + ann['bbox'][3]\n        label = ann['category_id']\n        class_name = labels[ann['category_id']]\n\n        out.write('{},{},{},{},{},{},{}\\n'.format(image_id,class_name, label, x_min, y_min, x_max, y_max))\n\n    all_ids = set(all_ids)\n    all_ids_ann = set(all_ids_ann)\n    no_annotations = list(all_ids - all_ids_ann)\n    # Output images without any annotations\n    for image_id in no_annotations:\n        out.write('{},{},{},{},{},{},{}\\n'.format(image_id,\"No finding\", 14, -1, -1, -1, -1))\n    out.close()\n\n    # Sort file by image id\n    s1 = pd.read_csv(out_file)\n    s1.sort_values('image_id', inplace=True)\n    s1.to_csv(out_file, index=False)\n    \nconvert_coco_json_to_csv(\"/kaggle/working/train_annotations.json\")\nconvert_coco_json_to_csv(\"/kaggle/working/val_annotations.json\")","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:31:47.448687Z","iopub.execute_input":"2022-12-01T13:31:47.449234Z","iopub.status.idle":"2022-12-01T13:31:47.816075Z","shell.execute_reply.started":"2022-12-01T13:31:47.449195Z","shell.execute_reply":"2022-12-01T13:31:47.815297Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport copy\nimport pickle\nimport argparse\nimport json\nimport random\nimport sys\nimport time\nimport datetime\nimport logging\n\n\nimport pandas as pd\nimport numpy as np\n\nfrom PIL import Image\nimport cv2\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport matplotlib.pyplot as plt\n\nfrom sklearn.model_selection import StratifiedKFold\n\nimport torch\nfrom detectron2 import model_zoo\nfrom detectron2.structures import BoxMode\nimport detectron2.data.transforms as T\nfrom detectron2.data import detection_utils as utils\nfrom detectron2.data import build_detection_test_loader, build_detection_train_loader\nfrom detectron2.engine import DefaultPredictor, DefaultTrainer, launch\nfrom detectron2.evaluation import COCOEvaluator, PascalVOCDetectionEvaluator\nfrom detectron2.config import CfgNode as CN\nfrom detectron2.config import get_cfg\nimport detectron2\nfrom detectron2 import model_zoo\nfrom detectron2.config import get_cfg\nfrom detectron2.data import DatasetCatalog, MetadataCatalog\nfrom detectron2.utils.logger import setup_logger, log_every_n_seconds\nfrom detectron2.utils.visualizer import Visualizer\nfrom detectron2.engine.hooks import HookBase\nimport detectron2.utils.comm as comm\n\n","metadata":{"execution":{"iopub.status.busy":"2022-12-01T13:38:20.445681Z","iopub.execute_input":"2022-12-01T13:38:20.446493Z","iopub.status.idle":"2022-12-01T13:38:21.783183Z","shell.execute_reply.started":"2022-12-01T13:38:20.446449Z","shell.execute_reply":"2022-12-01T13:38:21.782247Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Set configs","metadata":{}},{"cell_type":"code","source":"thingClasses = [\n    \"Aortic enlargement\",\n    \"Atelectasis\",\n    \"Calcification\",\n    \"Cardiomegaly\",\n    \"Consolidation\",\n    \"ILD\",\n    \"Infiltration\",\n    \"Lung Opacity\",\n    \"Nodule/Mass\",\n    \"Other lesion\",\n    \"Pleural effusion\",\n    \"Pleural thickening\",\n    \"Pneumothorax\",\n    \"Pulmonary fibrosis\",\n    \"No finding\"\n]\n\ncfgDict = {\n    \"dicomPath\": \"../input/vinbigdata-chest-xray-abnormalities-detection/train/\",\n    \"orgDataPath\": \"../input/vinbigdata-chest-xray-abnormalities-detection/\",\n    \"newDataPath\": \"../input/vinbigdata-chest-xray-resized-png-256x256/\",\n    \"cachePath\": \"./\",\n    \"trainDataName\": \"vinbigdataTrain\",\n    \"validDataName\": \"vinbigdataValid\",\n    \"sampleSize\": 100,\n    \"imSize\": 256,\n    \"modelName\": \"COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml\",\n    \"debug\": False,\n    \"outdir\": \"./results/\",\n    \"logFile\": \"log.txt\",\n    \"splitMode\": True,\n    \"seed\": 111,\n    \"device\": \"cuda\",\n    \"iter\": 100,\n    \"ims_per_batch\": 16,\n    \"roi_batch_size_per_image\": 512,\n    \"eval_period\": 20,\n    \"lr_scheduler_name\": \"WarmupCosineLR\",\n    \"base_lr\": 0.001,\n    \"checkpoint_period\":500,\n    \"num_workers\": 4,\n    \"score_thresh_test\": 0.05,\n    \"augKwargs\": {\n        \"RandomFlip\": {\"prob\": 0.5},\n        \"RandomRotation\": {\"angle\": [0,360]}\n    }\n}\n\nsetup_logger(os.path.join(cfgDict[\"outdir\"],cfgDict[\"logFile\"]))","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:04.282289Z","iopub.execute_input":"2022-12-01T14:24:04.282679Z","iopub.status.idle":"2022-12-01T14:24:04.30214Z","shell.execute_reply.started":"2022-12-01T14:24:04.282635Z","shell.execute_reply":"2022-12-01T14:24:04.300858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocess data\n\nWe use the dataset [VinBigData Chest X-ray Resized PNG (256x256)](https://www.kaggle.com/xhlulu/vinbigdata-chest-xray-resized-png-256x256).\n\nExample code is provided below.","metadata":{}},{"cell_type":"code","source":"dicomPath = cfgDict[\"dicomPath\"]\nfor file in os.listdir(dicomPath):\n    filePath = os.path.join(dicomPath,file)\n    break\n# Read dicom\ndicom = pydicom.read_file(filePath)\n# Transform raw image to \"human-friendly\" view\nimgArray = apply_voi_lut(dicom.pixel_array,dicom)\n# Fix inverted image\nif dicom.PhotometricInterpretation == \"MONOCHROME1\":\n    imgArray = np.amax(imgArray) - imgArray\n# Scale image value to (0,255)        \nimgArray = imgArray - np.min(imgArray)\nimgArray = imgArray / np.max(imgArray)\nimgArray = (imgArray * 255).astype(np.uint8)\n# Resize image to (imSize x imSize)\nimSize = 256\nim = Image.fromarray(imgArray)\nim = im.resize((imSize,imSize),Image.LANCZOS)\n# Display image\nim","metadata":{"_uuid":"86566ab8-570a-4b8a-9743-7f819bbe790c","_cell_guid":"2b2af0a3-acfc-4b91-89bb-7587ea00405a","execution":{"iopub.status.busy":"2022-12-01T14:24:07.341243Z","iopub.execute_input":"2022-12-01T14:24:07.341537Z","iopub.status.idle":"2022-12-01T14:24:10.523003Z","shell.execute_reply.started":"2022-12-01T14:24:07.341507Z","shell.execute_reply":"2022-12-01T14:24:10.522097Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare datasets","metadata":{}},{"cell_type":"code","source":"def getDatasetDicts(dfTrain,dfMeta,dataType=\"train_images_resized\",imSize=256,cache=False):\n    \"\"\"Function to create dataset dicts\"\"\"\n    \n    cachePath = \"./cache\"+dataType+\".pkl\"\n    datasetDicts = []\n    \n    if not cache and os.path.exists(cachePath):\n        # Load dicts\n        with open(cachePath, mode=\"rb\") as f:\n            datasetDicts = pickle.load(f)\n    else:\n        # Cache dicts\n        for index,metaRow in dfMeta.iterrows():\n            datasetDict = {}\n            annotations = []\n\n            imageId,h,w = metaRow.values\n            filename = os.path.join(newDataPath,dataType,imageId+\".jpg\")\n            datasetDict[\"file_name\"] = filename\n            datasetDict[\"image_id\"] = imageId\n            datasetDict[\"height\"] = imSize\n            datasetDict[\"width\"] = imSize\n            \n            # Add annotations for training data\n            if dataType==\"train_images_resized\":\n                for index2,row in dfTrain[dfTrain[\"image_id\"]==imageId].iterrows():\n                    #print(row)\n                    classId = row[2]\n                    #print(classId)\n                    if classId != 14:\n                        hRatio = imSize/h\n                        wRatio = imSize/w\n                        bboxResized = [ float(row[\"x_min\"])*wRatio,\n                                        float(row[\"y_min\"])*hRatio,\n                                        float(row[\"x_max\"])*wRatio,\n                                        float(row[\"y_max\"])*hRatio ]\n                    else: \n                        bboxResized = [0, 0, imSize, imSize]      \n                    annotation = { \"bbox\": bboxResized,\n                                    \"bbox_mode\": BoxMode.XYXY_ABS,\n                                    \"category_id\": classId }\n                    annotations.append(annotation)\n                datasetDict[\"annotations\"] = annotations\n            \n            datasetDicts.append(datasetDict)\n\n        with open(cachePath, mode=\"wb\") as f:\n            pickle.dump(datasetDicts, f)\n    \n    return datasetDicts","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.524952Z","iopub.execute_input":"2022-12-01T14:24:10.525376Z","iopub.status.idle":"2022-12-01T14:24:10.536497Z","shell.execute_reply.started":"2022-12-01T14:24:10.525339Z","shell.execute_reply":"2022-12-01T14:24:10.535739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare augmentation","metadata":{}},{"cell_type":"code","source":"class AugMapper:\n    \"\"\"Custom mapper class for augmentations\"\"\"\n\n    def __init__(self, cfg, isTrain=True):\n        augKwargs = cfg[\"augKwargs\"]\n        augList = []\n        # Define a sequence of augmentations\n        if isTrain:\n            augList.extend([getattr(T, name)(**kwargs) for name, kwargs in augKwargs.items()])\n        self.augmentations = T.AugmentationList(augList)\n        self.isTrain = isTrain\n\n    def __call__(self, datasetDict):\n        datasetDict = copy.deepcopy(datasetDict)  # it will be modified by code below\n        image = utils.read_image(datasetDict[\"file_name\"], format=\"BGR\")\n        augInput = T.AugInput(image) # the augmentation input\n        transforms = self.augmentations(augInput) # apply the augmentation\n        image = augInput.image # new image\n        imShape = image.shape[:2]  # h, w\n        datasetDict[\"image\"] = torch.as_tensor(image.transpose(2, 0, 1).astype(\"float32\")) # HWC to CHW\n        annos = [ utils.transform_instance_annotations(annotation, transforms, imShape) \n                    for annotation in datasetDict.pop(\"annotations\") \n                    if annotation.get(\"iscrowd\", 0) == 0 ] # apply the augmentation to annotation\n        instances = utils.annotations_to_instances(annos, imShape)\n        datasetDict[\"instances\"] = utils.filter_empty_instances(instances)\n        \n        return datasetDict","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.538502Z","iopub.execute_input":"2022-12-01T14:24:10.539082Z","iopub.status.idle":"2022-12-01T14:24:10.550482Z","shell.execute_reply.started":"2022-12-01T14:24:10.539046Z","shell.execute_reply":"2022-12-01T14:24:10.549674Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare loss eval hook for validation","metadata":{}},{"cell_type":"code","source":"class LossEvalHook(HookBase):\n    def __init__(self, eval_period, model, data_loader):\n        self._model = model\n        self._period = eval_period\n        self._data_loader = data_loader\n    \n    def _do_loss_eval(self):\n        # Copying inference_on_dataset from evaluator.py\n        total = len(self._data_loader)\n        num_warmup = min(5, total - 1)\n            \n        start_time = time.perf_counter()\n        total_compute_time = 0\n        losses = []\n        for idx, inputs in enumerate(self._data_loader):            \n            if idx == num_warmup:\n                start_time = time.perf_counter()\n                total_compute_time = 0\n            start_compute_time = time.perf_counter()\n            if torch.cuda.is_available():\n                torch.cuda.synchronize()\n            total_compute_time += time.perf_counter() - start_compute_time\n            iters_after_start = idx + 1 - num_warmup * int(idx >= num_warmup)\n            seconds_per_img = total_compute_time / iters_after_start\n            if idx >= num_warmup * 2 or seconds_per_img > 5:\n                total_seconds_per_img = (time.perf_counter() - start_time) / iters_after_start\n                eta = datetime.timedelta(seconds=int(total_seconds_per_img * (total - idx - 1)))\n                log_every_n_seconds(\n                    logging.INFO,\n                    \"Loss on Validation  done {}/{}. {:.4f} s / img. ETA={}\".format(\n                        idx + 1, total, seconds_per_img, str(eta)\n                    ),\n                    n=5,\n                )\n            loss_batch = self._get_loss(inputs)\n            losses.append(loss_batch)\n        mean_loss = np.mean(losses)\n        comm.synchronize()\n\n        return mean_loss\n            \n    def _get_loss(self, data):\n        # How loss is calculated on train_loop \n        metrics_dict = self._model(data)\n        metrics_dict = {\n            k: v.detach().cpu().item() if isinstance(v, torch.Tensor) else float(v)\n            for k, v in metrics_dict.items()\n        }\n        total_losses_reduced = sum(loss for loss in metrics_dict.values())\n        return total_losses_reduced\n        \n        \n    def after_step(self):\n        next_iter = self.trainer.iter + 1\n        is_final = next_iter == self.trainer.max_iter\n        if is_final or (self._period > 0 and next_iter % self._period == 0):\n            mean_loss = self._do_loss_eval()\n            self.trainer.storage.put_scalars(validation_loss=mean_loss)\n            print(\"validation do loss eval\", mean_loss)\n","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.55361Z","iopub.execute_input":"2022-12-01T14:24:10.553862Z","iopub.status.idle":"2022-12-01T14:24:10.566602Z","shell.execute_reply.started":"2022-12-01T14:24:10.553808Z","shell.execute_reply":"2022-12-01T14:24:10.565711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Custom DefaultTrainer","metadata":{}},{"cell_type":"code","source":"class MyTrainer(DefaultTrainer):\n    \"\"\"Overwrite DefaultTrainer methods\"\"\"\n    \n    @classmethod\n    def build_train_loader(cls, cfg, sampler=None):\n        return build_detection_train_loader(\n            cfg, mapper=AugMapper(cfg, True), sampler=sampler\n        )\n\n    @classmethod\n    def build_test_loader(cls, cfg, datasetName):\n        return build_detection_test_loader(\n            cfg, datasetName, mapper=AugMapper(cfg, False)\n        )\n\n    @classmethod\n    def build_evaluator(cls, cfg, datasetName, outputFolder=None):\n        if outputFolder is None:\n            outputFolder = os.path.join(cfg.OUTPUT_DIR, \"inference\")\n        return COCOEvaluator(datasetName, (\"bbox\",), False, output_dir=outputFolder)\n    \n    def build_hooks(self):\n        hooks = super(MyTrainer, self).build_hooks()\n        cfg = self.cfg\n        if len(cfg.DATASETS.TEST) > 0:\n            loss_eval_hook = LossEvalHook(\n                cfg.TEST.EVAL_PERIOD,\n                self.model,\n                MyTrainer.build_test_loader(cfg, cfg.DATASETS.TEST[0]),\n            )\n            hooks.insert(-1, loss_eval_hook)\n\n        return hooks","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.567869Z","iopub.execute_input":"2022-12-01T14:24:10.568161Z","iopub.status.idle":"2022-12-01T14:24:10.579435Z","shell.execute_reply.started":"2022-12-01T14:24:10.568128Z","shell.execute_reply":"2022-12-01T14:24:10.578698Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load, split, and register data","metadata":{}},{"cell_type":"code","source":"orgDataPath = \"/kaggle/working/\"\nnewDataPath = \"/kaggle/working/\"\n#trainCSVPath = os.path.join(orgDataPath,\"train.csv\")\ntrainCSVPath = os.path.join(newDataPath,\"train_annotations.csv\")\ntrainMetaCSVPath = os.path.join(newDataPath,\"train_annotations_meta.csv\")\n\ndfTrain = pd.read_csv(trainCSVPath)\ndfTrainMeta = pd.read_csv(trainMetaCSVPath)\n#dfTrainMeta = dfTrainMeta[:cfgDict[\"sampleSize\"]]","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.580428Z","iopub.execute_input":"2022-12-01T14:24:10.580713Z","iopub.status.idle":"2022-12-01T14:24:10.626187Z","shell.execute_reply.started":"2022-12-01T14:24:10.58068Z","shell.execute_reply":"2022-12-01T14:24:10.625535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DatasetCatalog.clear()\nDatasetCatalog.register(\n        cfgDict[\"trainDataName\"],\n        lambda: getDatasetDicts(cfgDict,dfTrain=dfTrain,dfMeta=dfTrainMeta.iloc[trainIdx],dataType=\"train_images_resized\",cache=True)\n    )\nMetadataCatalog.get(cfgDict[\"trainDataName\"]).set(thing_classes=thingClasses)\nDatasetCatalog.register(\n        cfgDict[\"validDataName\"],\n        lambda: getDatasetDicts(cfgDict,dfTrain=dfTrain,dfMeta=dfTrainMeta.iloc[validIdx],dataType=\"val_images_resized\",cache=True)\n    )\nMetadataCatalog.get(cfgDict[\"validDataName\"]).set(thing_classes=thingClasses)","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.627441Z","iopub.execute_input":"2022-12-01T14:24:10.627744Z","iopub.status.idle":"2022-12-01T14:24:10.636031Z","shell.execute_reply.started":"2022-12-01T14:24:10.627666Z","shell.execute_reply":"2022-12-01T14:24:10.635371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"datasetDicts = getDatasetDicts(dfTrain=dfTrain,dfMeta=dfTrainMeta[:cfgDict[\"sampleSize\"]],cache=True)\n\nDatasetCatalog.clear()\nDatasetCatalog.register(\n        \"vinbigdataTrain\",\n        lambda: getDatasetDicts(dfTrain=dfTrain,dfMeta=dfTrainMeta[:cfgDict[\"sampleSize\"]])\n    )\n\nDatasetCatalog.register(\n        \"vinbigdataValid\",\n        lambda: getDatasetDicts(dfTrain=dfTrain,dfMeta=dfTrainMeta[:cfgDict[\"sampleSize\"]])\n    )\nMetadataCatalog.get(\"vinbigdataTrain\").set(thing_classes=thingClasses)","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.637288Z","iopub.execute_input":"2022-12-01T14:24:10.637708Z","iopub.status.idle":"2022-12-01T14:24:10.844928Z","shell.execute_reply.started":"2022-12-01T14:24:10.637674Z","shell.execute_reply":"2022-12-01T14:24:10.844027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualize data","metadata":{}},{"cell_type":"code","source":"vinbigdataMetadata = MetadataCatalog.get(cfgDict[\"validDataName\"])\nd = datasetDicts[3]\nimg = cv2.imread(d[\"file_name\"])\nvisualizer = Visualizer(img[:, :, ::-1], metadata=vinbigdataMetadata, scale=1)\nout = visualizer.draw_dataset_dict(d)\nImage.fromarray(out.get_image()[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.846233Z","iopub.execute_input":"2022-12-01T14:24:10.846493Z","iopub.status.idle":"2022-12-01T14:24:10.909249Z","shell.execute_reply.started":"2022-12-01T14:24:10.846456Z","shell.execute_reply":"2022-12-01T14:24:10.908592Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"vinbigdataMetadata = MetadataCatalog.get(cfgDict[\"validDataName\"])\nd = datasetDicts[3]\nd","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.91228Z","iopub.execute_input":"2022-12-01T14:24:10.912892Z","iopub.status.idle":"2022-12-01T14:24:10.919891Z","shell.execute_reply.started":"2022-12-01T14:24:10.912845Z","shell.execute_reply":"2022-12-01T14:24:10.918361Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Create Yacs config","metadata":{}},{"cell_type":"code","source":"cfg = get_cfg()\n\ncfg.augKwargs = CN(cfgDict[\"augKwargs\"])  # pass augKwargs to cfg as a CN\ncfg.merge_from_file(model_zoo.get_config_file(cfgDict[\"modelName\"]))\ncfg.MODEL.DEVICE = cfgDict[\"device\"]\ncfg.OUTPUT_DIR = cfgDict[\"outdir\"]\ncfg.DATASETS.TRAIN = (cfgDict[\"trainDataName\"],)\nif cfgDict[\"splitMode\"] is None:\n    cfg.DATASETS.TEST = ()\nelse:\n    cfg.DATASETS.TEST = (cfgDict[\"validDataName\"],)\n    cfg.TEST.EVAL_PERIOD = cfgDict[\"eval_period\"]\ncfg.DATALOADER.NUM_WORKERS = cfgDict[\"num_workers\"]\ncfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(cfgDict[\"modelName\"])\ncfg.SOLVER.IMS_PER_BATCH = cfgDict[\"ims_per_batch\"]\ncfg.SOLVER.LR_SCHEDULER_NAME = cfgDict[\"lr_scheduler_name\"]\ncfg.SOLVER.BASE_LR = cfgDict[\"base_lr\"]\ncfg.SOLVER.MAX_ITER = cfgDict[\"iter\"]\ncfg.SOLVER.CHECKPOINT_PERIOD = cfgDict[\"checkpoint_period\"]\ncfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = cfgDict[\"roi_batch_size_per_image\"]\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = len(thingClasses)\n\nos.makedirs(cfg.OUTPUT_DIR, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:10.921251Z","iopub.execute_input":"2022-12-01T14:24:10.921638Z","iopub.status.idle":"2022-12-01T14:24:10.948014Z","shell.execute_reply.started":"2022-12-01T14:24:10.921599Z","shell.execute_reply":"2022-12-01T14:24:10.947395Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train model","metadata":{}},{"cell_type":"code","source":"trainer = MyTrainer(cfg)\ntrainer.resume_or_load(resume=False)\ntrainer.train()","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:24:11.310394Z","iopub.execute_input":"2022-12-01T14:24:11.310656Z","iopub.status.idle":"2022-12-01T14:26:28.947249Z","shell.execute_reply.started":"2022-12-01T14:24:11.310626Z","shell.execute_reply":"2022-12-01T14:26:28.946489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Evaluation","metadata":{}},{"cell_type":"code","source":"os.path.join(cfgDict[\"outdir\"],\"metrics.json\")","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:20.047617Z","iopub.execute_input":"2022-12-01T14:27:20.047937Z","iopub.status.idle":"2022-12-01T14:27:20.054292Z","shell.execute_reply.started":"2022-12-01T14:27:20.047894Z","shell.execute_reply":"2022-12-01T14:27:20.05363Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dfMetrics = pd.read_json(os.path.join(cfgDict[\"outdir\"],\"metrics.json\"), orient=\"records\", lines=True)\ndfMetrics = dfMetrics.sort_values(\"iteration\")\ndfMetrics.head()","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:20.955261Z","iopub.execute_input":"2022-12-01T14:27:20.95581Z","iopub.status.idle":"2022-12-01T14:27:20.999171Z","shell.execute_reply.started":"2022-12-01T14:27:20.955773Z","shell.execute_reply":"2022-12-01T14:27:20.998481Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dfTrainLoss = dfMetrics[~dfMetrics[\"total_loss\"].isna()]\nplt.plot(dfTrainLoss[\"iteration\"], dfTrainLoss[\"total_loss\"], c=\"C0\", label=\"train\")\nif \"validation_loss\" in dfMetrics.columns:\n    dfValidLoss = dfMetrics[~dfMetrics[\"validation_loss\"].isna()]\n    plt.plot(dfValidLoss[\"iteration\"], dfValidLoss[\"validation_loss\"], c=\"C1\", label=\"validation\")\n\nplt.legend()\nplt.title(\"Loss curve\")\nplt.xlabel(\"Iteration\")\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:21.770675Z","iopub.execute_input":"2022-12-01T14:27:21.771243Z","iopub.status.idle":"2022-12-01T14:27:22.069009Z","shell.execute_reply.started":"2022-12-01T14:27:21.771206Z","shell.execute_reply":"2022-12-01T14:27:22.064242Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Predict","metadata":{}},{"cell_type":"code","source":"# Same cfg from trainer and use the final model output to initialize the predictor\ncfg.MODEL.WEIGHTS = os.path.join(cfgDict[\"outdir\"],\"model_final.pth\")\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = cfgDict[\"score_thresh_test\"]\npredictor = DefaultPredictor(cfg)\n\nd = datasetDicts[3]\nim = cv2.imread(d[\"file_name\"])\nif predictor.input_format == \"RGB\":\n    im = im[:, :, ::-1]\nheight, width = im.shape[:2]\nimage = torch.as_tensor(im.astype(\"float32\").transpose(2, 0, 1))\ninputs = [{\"image\": image, \"height\": height, \"width\": width}]\noutputs = predictor.model(inputs)\noutput = outputs[0]\n\nvisualizer = Visualizer(im,metadata=vinbigdataMetadata, scale=1.5)\nout = visualizer.draw_instance_predictions(output[\"instances\"].to(\"cpu\"))\nImage.fromarray(out.get_image()[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:24.907078Z","iopub.execute_input":"2022-12-01T14:27:24.907347Z","iopub.status.idle":"2022-12-01T14:27:26.418325Z","shell.execute_reply.started":"2022-12-01T14:27:24.907318Z","shell.execute_reply":"2022-12-01T14:27:26.417639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"im = cv2.imread(\"/kaggle/input/vinbigdata-chest-xray-resized-png-256x256/test/0168eb925aa6f28a78b16134792f5d0e.png\")\nif predictor.input_format == \"RGB\":\n    im = im[:, :, ::-1]\nheight, width = im.shape[:2]\nimage = torch.as_tensor(im.astype(\"float32\").transpose(2, 0, 1))\ninputs = [{\"image\": image, \"height\": height, \"width\": width}]\noutputs = predictor.model(inputs)\noutput = outputs[0]\n\nvisualizer = Visualizer(im,metadata=vinbigdataMetadata, scale=1.5)\nout = visualizer.draw_instance_predictions(output[\"instances\"].to(\"cpu\"))\nImage.fromarray(out.get_image()[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:34.13276Z","iopub.execute_input":"2022-12-01T14:27:34.133522Z","iopub.status.idle":"2022-12-01T14:27:34.643265Z","shell.execute_reply.started":"2022-12-01T14:27:34.133484Z","shell.execute_reply":"2022-12-01T14:27:34.642658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"directory= '/kaggle/input/vinbigdata-chest-xray-resized-png-256x256/test'\n\nfor filename in os.listdir(directory):\n    \n    im = cv2.imread(os.path.join(directory, filename))\n    if predictor.input_format == \"RGB\":\n        im = im[:, :, ::-1]\n    height, width = im.shape[:2]\n    image = torch.as_tensor(im.astype(\"float32\").transpose(2, 0, 1))\n    inputs = [{\"image\": image, \"height\": height, \"width\": width}]\n    outputs = predictor.model(inputs)\n    output = outputs[0]\n\n    visualizer = Visualizer(im,metadata=vinbigdataMetadata, scale=1.5)\n    Pred = output[\"instances\"][output[\"instances\"].pred_classes==6].pred_classes\n\n    if len(Pred)==1:\n\n        out = visualizer.draw_instance_predictions(Pred.to(\"cpu\"))\n        Image.fromarray(out.get_image()[:, :, ::-1])","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:27:35.702285Z","iopub.execute_input":"2022-12-01T14:27:35.702705Z","iopub.status.idle":"2022-12-01T14:29:11.721797Z","shell.execute_reply.started":"2022-12-01T14:27:35.702673Z","shell.execute_reply":"2022-12-01T14:29:11.720664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#THIS CELL CUT NEW IMAGES FROM DIRECTORY\n\ndirectory = '/kaggle/input/vinbigdata-chest-xray-resized-png-256x256/test'\n \nfor filename in os.listdir(directory):\n    f = os.path.join(directory, filename)\n    \n    im = cv2.imread(f)\n    if predictor.input_format == \"RGB\":\n        im = im[:, :, ::-1]\n    height, width = im.shape[:2]\n    image = torch.as_tensor(im.astype(\"float32\").transpose(2, 0, 1))\n    inputs = [{\"image\": image, \"height\": height, \"width\": width}]\n    outputs = predictor.model(inputs)\n    output = outputs[0]\n\n    visualizer = Visualizer(im,metadata=vinbigdataMetadata, scale=1.5)\n\n    # pred_classes==6 means infiltration\n    Pred = output[\"instances\"][output[\"instances\"].pred_classes==6]\n\n    if len(Pred.pred_classes)==1:\n\n        bbox = Pred.pred_boxes.tensor[0]\n\n        out = visualizer.draw_instance_predictions(Pred.to(\"cpu\"))\n        \n        try:\n\n            Image.fromarray(out.get_image()[int(bbox[1]):int(bbox[3]), int(bbox[0]):int(bbox[2]), ::-1]).save(f.split('/')[-1])\n        except:\n            pass","metadata":{"execution":{"iopub.status.busy":"2022-12-01T14:29:11.723108Z","iopub.status.idle":"2022-12-01T14:29:11.723771Z","shell.execute_reply.started":"2022-12-01T14:29:11.723533Z","shell.execute_reply":"2022-12-01T14:29:11.723558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Reference\n\nhttps://www.kaggle.com/corochann/vinbigdata-detectron2-train#Customizing-detectron2-trainer\n\nhttps://www.kaggle.com/xhlulu/vinbigdata-process-and-resize-to-image\n\nhttps://detectron2.readthedocs.io/en/latest/tutorials\n\nhttps://eidos-ai.medium.com/training-on-detectron2-with-a-validation-set-and-plot-loss-on-it-to-avoid-overfitting-6449418fbf4e","metadata":{}}]}