{"cells":[{"metadata":{},"cell_type":"markdown","source":"## Prepare Environment"},{"metadata":{"trusted":true},"cell_type":"code","source":"import gc\nimport os\nfrom pathlib import Path\nimport random\nimport sys\n\nfrom tqdm.notebook import tqdm\nimport numpy as np\nimport pandas as pd\nimport scipy as sp\n\nimport matplotlib.pyplot as plt\n\n# --- plotly ---\nfrom pydicom import dcmread\nimport pickle\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Install Detectron"},{"metadata":{"trusted":true},"cell_type":"code","source":"# if you are running on cpu\n!pip install detectron2 -f \"https://dl.fbaipublicfiles.com/detectron2/wheels/cpu/torch1.7/index.html\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# if you are running on gpu\n!pip install detectron2 -f \"https://dl.fbaipublicfiles.com/detectron2/wheels/cu102/torch1.7/index.html\"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Some basic setup:\n# Setup detectron2 logger\nimport detectron2\nfrom detectron2.utils.logger import setup_logger\nsetup_logger()\n\n# import some common libraries\nimport numpy as np\nimport os, json, cv2, random\n\n# import some common detectron2 utilities\nfrom detectron2 import model_zoo\nfrom detectron2.engine import DefaultPredictor, DefaultTrainer\nfrom detectron2.config import get_cfg\nfrom detectron2.utils.visualizer import Visualizer\nfrom detectron2.data import MetadataCatalog, DatasetCatalog, transforms, DatasetMapper, build_detection_train_loader\nfrom detectron2.structures import BoxMode\nfrom detectron2.evaluation import COCOEvaluator\nfrom detectron2.data.samplers import RepeatFactorTrainingSampler\n\n%matplotlib inline\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Import"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Path to dataframe and image folders\nPATH_ORIGIN = \"../input/vinbigdata-chest-xray-abnormalities-detection\"\nPATH_RESIZED = \"../input/vinbigdata-chest-xray-resized-png-256x256\"\nlen(os.listdir(os.path.join(PATH_ORIGIN, \"train\")))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataframe = pd.read_csv(os.path.join(PATH_ORIGIN, 'train.csv'))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Exploration"},{"metadata":{},"cell_type":"markdown","source":"### Data Information given by Kaggle\n\nImages are in the DICOM format https://de.wikipedia.org/wiki/Digital_Imaging_and_Communications_in_Medicine\nA .dicom file contains not just the pixel values but all sorts of usefull information"},{"metadata":{},"cell_type":"markdown","source":"Classes \n* 0 - Aortic enlargement\n* 1 - Atelectasis\n* 2 - Calcification\n* 3 - Cardiomegaly\n* 4 - Consolidation\n* 5 - ILD\n* 6 - Infiltration\n* 7 - Lung Opacity\n* 8 - Nodule/Mass\n* 9 - Other lesion\n* 10 - Pleural effusion\n* 11 - Pleural thickening\n* 12 - Pneumothorax\n* 13 - Pulmonary fibrosis\n* 14 - No finding"},{"metadata":{"trusted":true},"cell_type":"code","source":"print(train_dataframe.shape)\ntrain_dataframe.head()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Sample .dicom File Display"},{"metadata":{"trusted":true},"cell_type":"code","source":"ds = dcmread(os.path.join(PATH_, 'train', '000434271f63a053c4128a0ba6352c7f.png'))\n# Metadata readout\nprint(ds)\n# Pixel Array display\nplt.imshow(ds.pixel_array, cmap=plt.cm.gray)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Data Preparation"},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_vinbigdata_dicts(\n    imgdir: Path, train: pd.DataFrame, use_cache: bool = True, debug: bool = True,\n):\n    debug_str = f\"_debug{int(debug)}\"\n    cache_path = Path(\".\") / f\"dataset_dicts_cache{debug_str}.pkl\"\n    if not use_cache or not cache_path.exists():\n        print(\"Creating data...\")\n        train_meta = pd.read_csv(imgdir / \"train_meta.csv\")\n        if debug:\n            train_meta = train_meta.iloc[:500]  # For debug....\n\n        # Load 1 image to get image size.\n        image_id = train_meta.loc[0, \"image_id\"]\n        image_path = str(imgdir / \"train\" / f\"{image_id}.png\")\n        image = cv2.imread(image_path)\n        resized_height, resized_width, ch = image.shape\n        print(f\"image shape: {image.shape}\")\n\n        dataset_dicts = []\n        for index, train_meta_row in tqdm(train_meta.iterrows(), total=len(train_meta)):\n            record = {}\n\n            image_id, height, width = train_meta_row.values\n            filename = str(imgdir / \"train\" / f\"{image_id}.png\")\n            record[\"file_name\"] = filename\n            record[\"image_id\"] = index\n            record[\"height\"] = resized_height\n            record[\"width\"] = resized_width\n            objs = []\n            for index2, row in train.query(\"image_id == @image_id\").iterrows():\n                # print(row)\n                # print(row[\"class_name\"])\n                # class_name = row[\"class_name\"]\n                class_id = row[\"class_id\"]\n                if class_id == 14:\n                    # It is \"No finding\"\n                    # This annotator does not find anything, skip.\n                    pass\n                else:\n                    # bbox_original = [int(row[\"x_min\"]), int(row[\"y_min\"]), int(row[\"x_max\"]), int(row[\"y_max\"])]\n                    h_ratio = resized_height / height\n                    w_ratio = resized_width / width\n                    bbox_resized = [\n                        int(row[\"x_min\"]) * w_ratio,\n                        int(row[\"y_min\"]) * h_ratio,\n                        int(row[\"x_max\"]) * w_ratio,\n                        int(row[\"y_max\"]) * h_ratio,\n                    ]\n                    obj = {\n                        \"bbox\": bbox_resized,\n                        \"bbox_mode\": BoxMode.XYXY_ABS,\n                        \"category_id\": class_id,\n                    }\n                    objs.append(obj)\n            record[\"annotations\"] = objs\n            dataset_dicts.append(record)\n        with open(cache_path, mode=\"wb\") as f:\n            pickle.dump(dataset_dicts, f)\n\n    print(f\"Load from cache {cache_path}\")\n    with open(cache_path, mode=\"rb\") as f:\n        dataset_dicts = pickle.load(f)\n    return dataset_dicts\n\n\ndef get_vinbigdata_dicts_test(\n    imgdir: Path, test_meta: pd.DataFrame, use_cache: bool = True, debug: bool = True,\n):\n    debug_str = f\"_debug{int(debug)}\"\n    cache_path = Path(\".\") / f\"dataset_dicts_cache_test{debug_str}.pkl\"\n    if not use_cache or not cache_path.exists():\n        print(\"Creating data...\")\n        # test_meta = pd.read_csv(imgdir / \"test_meta.csv\")\n        if debug:\n            test_meta = test_meta.iloc[:500]  # For debug....\n\n        # Load 1 image to get image size.\n        image_id = test_meta.loc[0, \"image_id\"]\n        image_path = str(imgdir / \"test\" / f\"{image_id}.png\")\n        image = cv2.imread(image_path)\n        resized_height, resized_width, ch = image.shape\n        print(f\"image shape: {image.shape}\")\n\n        dataset_dicts = []\n        for index, test_meta_row in tqdm(test_meta.iterrows(), total=len(test_meta)):\n            record = {}\n\n            image_id, height, width = test_meta_row.values\n            filename = str(imgdir / \"test\" / f\"{image_id}.png\")\n            record[\"file_name\"] = filename\n            record[\"image_id\"] = index\n            record[\"height\"] = resized_height\n            record[\"width\"] = resized_width\n            # objs = []\n            # record[\"annotations\"] = objs\n            dataset_dicts.append(record)\n        with open(cache_path, mode=\"wb\") as f:\n            pickle.dump(dataset_dicts, f)\n\n    print(f\"Load from cache {cache_path}\")\n    with open(cache_path, mode=\"rb\") as f:\n        dataset_dicts = pickle.load(f)\n    return dataset_dicts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset_dicts = get_vinbigdata_dicts(Path(PATH_RESIZED), train_dataframe)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"collapsed":true},"cell_type":"code","source":"dataset_dicts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"thing_classes = [\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]\ncategory_name_to_id = {class_name: index for index, class_name in enumerate(thing_classes)}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DatasetCatalog.register(\n    \"vinbigdata_train3\", lambda: get_vinbigdata_dicts(Path(PATH_RESIZED), train_dataframe)\n)\nMetadataCatalog.get(\"vinbigdata_train3\").set(thing_classes=thing_classes)\nmetadata = MetadataCatalog.get(\"vinbigdata_train3\")\nvinbig_metadata = MetadataCatalog.get(\"vinbigdata_train3\")\n","execution_count":null,"outputs":[]},{"metadata":{"id":"27nwIqW9C76o","outputId":"da2aa05e-746a-4634-b199-f998a1857a31","trusted":true},"cell_type":"code","source":"vinbig_metadata\nfor d in random.sample(dataset_dicts, 21):\n    img = cv2.imread(d[\"file_name\"])\n    visualizer = Visualizer(img[:, :, ::-1], metadata=vinbig_metadata, scale=1)\n    out = visualizer.draw_dataset_dict(d)\n    plt.imshow(out.get_image()[:, :, ::-1]) \n\n","execution_count":null,"outputs":[]},{"metadata":{"id":"xJBQSu5FE4SM","outputId":"3656cc62-0fa6-4952-ffee-01912d1dcc1b","trusted":true},"cell_type":"code","source":"model_name = \"COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml\"\n\ncfg = get_cfg()\ncfg.merge_from_file(model_zoo.get_config_file(model_name))\ncfg.DATASETS.TRAIN = (\"vinbigdata_train3\",)\ncfg.DATALOADER.NUM_WORKERS = 0\ncfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(model_name)  # Let training initialize from model zoo\ncfg.SOLVER.IMS_PER_BATCH = 4\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = 14\n\n#####\n# Testing here\n#####\ncfg.SOLVER.MAX_ITER = 5000\ncfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 224\ncfg.SOLVER.BASE_LR = 0.0005\ncfg.MODEL.RPN.NMS_THRESH = 0.5\n\n\nos.makedirs(cfg.OUTPUT_DIR, exist_ok=True)\ntrainer = DefaultTrainer(cfg)\ntrainer.resume_or_load(resume=False)\ntrainer.train()","execution_count":null,"outputs":[]},{"metadata":{"id":"1UXCDN1s3W0N"},"cell_type":"markdown","source":"# Predictions"},{"metadata":{"id":"MVu-93V34E4C"},"cell_type":"markdown","source":"### Setting Predictor"},{"metadata":{"id":"didNbcAxUakw","trusted":false},"cell_type":"code","source":"cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, \"model_final.pth\")  # path to the model we just trained\n\npredictor = DefaultPredictor(cfg)","execution_count":null,"outputs":[]},{"metadata":{"id":"v-Ho51O-4JWI"},"cell_type":"markdown","source":"## Prediction on one image"},{"metadata":{"id":"is_eID4FUkil","outputId":"488d68af-f954-4478-8f80-237f0b7de9ad","trusted":false},"cell_type":"code","source":"from detectron2.utils.visualizer import ColorMode\ndataset_dicts = val_set\nd = dataset_dicts[9]\nim = cv2.imread(d[\"file_name\"])\noutputs = predictor(im)  \nv = Visualizer(im[:, :, ::-1],\n                metadata=facemask_metadata, \n                scale=3\n)\nout = v.draw_instance_predictions(outputs[\"instances\"].to(\"cpu\"))\nplt_imshow(out.get_image()[:, :, ::-1])","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}