{"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":"# Breast Density Classification using MONAI\n\n\n#### About\n[MONAI](https://monai.io/) is a useful library for medical imaging. \n\nHere, I use the breast density classification model available in the [model zoo](https://monai.io/model-zoo.html).\n\n\n#### Purposes\n\nThis model can be used to pseudo-label missing values in the density column. It may require some finetuning though.\n\nInference is slow, I don't recommend using it when submitting.\n\n\n#### Dataset Links :\n\n - [512x512 pngs](https://www.kaggle.com/datasets/theoviel/rsna-breast-cancer-512-pngs)\n - [MONAI Breast density classification](https://www.kaggle.com/datasets/theoviel/monai-breast-density-classification)","metadata":{}},{"cell_type":"markdown","source":"## Initialization","metadata":{}},{"cell_type":"code","source":"!pip install -qU python-gdcm pydicom pylibjpeg monai","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T13:50:45.851413Z","iopub.execute_input":"2022-12-07T13:50:45.852059Z","iopub.status.idle":"2022-12-07T13:51:03.858185Z","shell.execute_reply.started":"2022-12-07T13:50:45.851931Z","shell.execute_reply":"2022-12-07T13:51:03.856815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport sys\nimport json\nimport glob\nimport gdcm\nimport torch\nimport pydicom\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\n\nfrom tqdm.notebook import tqdm\nfrom joblib import Parallel, delayed\nfrom monai.bundle.config_parser import ConfigParser","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T13:51:03.862191Z","iopub.execute_input":"2022-12-07T13:51:03.862523Z","iopub.status.idle":"2022-12-07T13:51:09.958139Z","shell.execute_reply.started":"2022-12-07T13:51:03.862486Z","shell.execute_reply":"2022-12-07T13:51:09.956923Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preprocessing\n- https://www.kaggle.com/code/theoviel/dicom-resized-png-jpg","metadata":{}},{"cell_type":"code","source":"def process(f, size=512, save_folder=\"\", extension=\"png\"):\n    patient = f.split('/')[-2]\n    image = f.split('/')[-1][:-4]\n\n    dicom = pydicom.dcmread(f)\n    img = dicom.pixel_array\n\n    img = (img - img.min()) / (img.max() - img.min())\n\n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        img = 1 - img\n\n    img = cv2.resize(img, (size, size))\n\n    cv2.imwrite(save_folder + f\"{patient}_{image}.{extension}\", (img * 255).astype(np.uint8))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T13:51:09.959737Z","iopub.execute_input":"2022-12-07T13:51:09.960735Z","iopub.status.idle":"2022-12-07T13:51:09.968747Z","shell.execute_reply.started":"2022-12-07T13:51:09.960682Z","shell.execute_reply":"2022-12-07T13:51:09.967529Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images = glob.glob(\"/kaggle/input/rsna-breast-cancer-detection/test_images/*/*.dcm\")\n\nSAVE_FOLDER = \"/kaggle/working/output/\"\nSIZE = 512\nEXTENSION = \"png\"\n\nos.makedirs(SAVE_FOLDER, exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T13:51:09.970085Z","iopub.execute_input":"2022-12-07T13:51:09.972032Z","iopub.status.idle":"2022-12-07T13:51:09.997689Z","shell.execute_reply.started":"2022-12-07T13:51:09.971993Z","shell.execute_reply":"2022-12-07T13:51:09.99677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_ = Parallel(n_jobs=2)(\n    delayed(process)(uid, size=SIZE, save_folder=SAVE_FOLDER, extension=EXTENSION)\n    for uid in tqdm(images)\n)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T13:51:10.002776Z","iopub.execute_input":"2022-12-07T13:51:10.004963Z","iopub.status.idle":"2022-12-07T13:51:14.302201Z","shell.execute_reply.started":"2022-12-07T13:51:10.004931Z","shell.execute_reply":"2022-12-07T13:51:14.30096Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# MONAI Density classification","metadata":{}},{"cell_type":"code","source":"MODEL_PATH = \"/kaggle/input/monai-breast-density-classification/breast_density_classification/\"","metadata":{"execution":{"iopub.status.busy":"2022-12-07T13:59:37.549008Z","iopub.execute_input":"2022-12-07T13:59:37.549634Z","iopub.status.idle":"2022-12-07T13:59:37.554888Z","shell.execute_reply.started":"2022-12-07T13:59:37.54959Z","shell.execute_reply":"2022-12-07T13:59:37.553897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cp -r $MODEL_PATH ./","metadata":{"execution":{"iopub.status.busy":"2022-12-07T13:59:37.747676Z","iopub.execute_input":"2022-12-07T13:59:37.74858Z","iopub.status.idle":"2022-12-07T13:59:38.879369Z","shell.execute_reply.started":"2022-12-07T13:59:37.748534Z","shell.execute_reply":"2022-12-07T13:59:38.877763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd breast_density_classification","metadata":{"execution":{"iopub.status.busy":"2022-12-07T13:59:38.882289Z","iopub.execute_input":"2022-12-07T13:59:38.883035Z","iopub.status.idle":"2022-12-07T13:59:38.890982Z","shell.execute_reply.started":"2022-12-07T13:59:38.882986Z","shell.execute_reply":"2022-12-07T13:59:38.889851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create Dataset","metadata":{}},{"cell_type":"code","source":"def create_dataset(base_dir: str, output_file: str):\n    list_classes = [\"A\", \"B\", \"C\", \"D\"]\n\n    output_list = []\n    for _class in list_classes:\n        data_dir = os.path.join(base_dir, _class)\n        list_files = os.listdir(data_dir)\n        if _class == \"A\":\n            _label = [1, 0, 0, 0]\n        elif _class == \"B\":\n            _label = [0, 1, 0, 0]\n        elif _class == \"C\":\n            _label = [0, 0, 1, 0]\n        elif _class == \"D\":\n            _label = [0, 0, 0, 1]\n\n        for _file in list_files:\n            _out = {\"image\": os.path.join(data_dir, _file), \"label\": _label}\n            output_list.append(_out)\n\n    data_dict = {\"Test\": output_list}\n\n    fid = open(output_file, \"w\")\n    json.dump(data_dict, fid, indent=1)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:06:04.339674Z","iopub.execute_input":"2022-12-07T14:06:04.340411Z","iopub.status.idle":"2022-12-07T14:06:04.349424Z","shell.execute_reply.started":"2022-12-07T14:06:04.340373Z","shell.execute_reply":"2022-12-07T14:06:04.348064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_dataset(\"sample_data\", \"configs/sample_image_data.json\")","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:06:04.51399Z","iopub.execute_input":"2022-12-07T14:06:04.514381Z","iopub.status.idle":"2022-12-07T14:06:04.521245Z","shell.execute_reply.started":"2022-12-07T14:06:04.514345Z","shell.execute_reply":"2022-12-07T14:06:04.520042Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Config\n- Update the data config path + minor fixes","metadata":{}},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference.json\"","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:07:39.137006Z","iopub.execute_input":"2022-12-07T14:07:39.1378Z","iopub.status.idle":"2022-12-07T14:07:39.143983Z","shell.execute_reply.started":"2022-12-07T14:07:39.137751Z","shell.execute_reply":"2022-12-07T14:07:39.142712Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile $CONFIG_FILE\n\n{\n    \"import\": [\n        \"$import glob\",\n        \"$import os\",\n        \"$import torchvision\"\n    ],\n    \"bundle_root\": \".\",\n    \"model_dir\": \"$@bundle_root + '/models'\",\n    \"output_dir\": \"$@bundle_root + '/output'\",\n    \"data\": {\n        \"_target_\": \"createList.CreateImageLabelList\",\n        \"filename\": \"../configs/sample_image_data.json\"\n    },\n    \"test_imagelist\": \"$@data.create_dataset('Test')[0]\",\n    \"test_labellist\": \"$@data.create_dataset('Test')[1]\",\n    \"dataset\": {\n        \"_target_\": \"CacheDataset\",\n        \"data\": \"$[{'image': i, 'label': l} for i, l in zip(@test_imagelist, @test_labellist)]\",\n        \"transform\": \"@preprocessing\",\n        \"cache_rate\": 1,\n        \"num_workers\": 2\n    },\n    \"dataloader\": {\n        \"_target_\": \"DataLoader\",\n        \"dataset\": \"@dataset\",\n        \"batch_size\": 16,\n        \"shuffle\": false,\n        \"num_workers\": 2\n    },\n    \"device\": \"$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\",\n    \"network_def\": {\n        \"_target_\": \"TorchVisionFCModel\",\n        \"model_name\": \"inception_v3\",\n        \"num_classes\": 4,\n        \"pool\": null,\n        \"use_conv\": false,\n        \"bias\": true,\n        \"pretrained\": true\n    },\n    \"network\": \"$@network_def.to(@device)\",\n    \"preprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"LoadImaged\",\n                \"keys\": \"image\"\n            },\n            {\n                \"_target_\": \"EnsureChannelFirstd\",\n                \"keys\": \"image\",\n                \"channel_dim\": 2\n            },\n            {\n                \"_target_\": \"ScaleIntensityd\",\n                \"keys\": \"image\",\n                \"minv\": 0.0,\n                \"maxv\": 1.0\n            },\n            {\n                \"_target_\": \"Resized\",\n                \"keys\": \"image\",\n                \"spatial_size\": [\n                    299,\n                    299\n                ]\n            }\n        ]\n    },\n    \"inferer\": {\n        \"_target_\": \"SimpleInferer\"\n    },\n    \"postprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"Activationsd\",\n                \"keys\": \"pred\",\n                \"sigmoid\": false\n            }\n        ]\n    },\n    \"handlers\": [\n        {\n            \"_target_\": \"CheckpointLoader\",\n            \"load_path\": \"$@model_dir + '/model.pt'\",\n            \"load_dict\": {\n                \"model\": \"@network\"\n            }\n        },\n        {\n            \"_target_\": \"StatsHandler\",\n            \"iteration_log\": false,\n            \"output_transform\": \"$lambda x: None\"\n        },\n        {\n            \"_target_\": \"ClassificationSaver\",\n            \"output_dir\": \"@output_dir\",\n            \"batch_transform\": \"$monai.handlers.from_engine(['image_meta_dict'])\",\n            \"output_transform\": \"$monai.handlers.from_engine(['pred'])\"\n        }\n    ],\n    \"evaluator\": {\n        \"_target_\": \"SupervisedEvaluator\",\n        \"device\": \"@device\",\n        \"val_data_loader\": \"@dataloader\",\n        \"network\": \"@network\",\n        \"inferer\": \"@inferer\",\n        \"postprocessing\": \"@postprocessing\",\n        \"val_handlers\": \"@handlers\",\n        \"amp\": true\n    },\n    \"evaluating\": [\n        \"$setattr(torch.backends.cudnn, 'benchmark', True)\",\n        \"$@evaluator.run()\"\n    ]\n}\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T14:13:13.727857Z","iopub.execute_input":"2022-12-07T14:13:13.728242Z","iopub.status.idle":"2022-12-07T14:13:13.737016Z","shell.execute_reply.started":"2022-12-07T14:13:13.72821Z","shell.execute_reply":"2022-12-07T14:13:13.735792Z"},"jupyter":{"source_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### MONAI Parser\n- I have to navigate in the directories in the meantime, which is not ideal","metadata":{}},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:14.072355Z","iopub.execute_input":"2022-12-07T14:13:14.073021Z","iopub.status.idle":"2022-12-07T14:13:14.079841Z","shell.execute_reply.started":"2022-12-07T14:13:14.072986Z","shell.execute_reply":"2022-12-07T14:13:14.07886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"parser = ConfigParser()\n\nparser.read_config(CONFIG_FILE)\n\ndata = parser.get_parsed_content(\"data\")\ndevice = parser.get_parsed_content(\"device\")","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:14.270476Z","iopub.execute_input":"2022-12-07T14:13:14.271292Z","iopub.status.idle":"2022-12-07T14:13:14.318505Z","shell.execute_reply.started":"2022-12-07T14:13:14.271242Z","shell.execute_reply":"2022-12-07T14:13:14.317538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:14.450024Z","iopub.execute_input":"2022-12-07T14:13:14.450398Z","iopub.status.idle":"2022-12-07T14:13:14.457322Z","shell.execute_reply.started":"2022-12-07T14:13:14.450365Z","shell.execute_reply":"2022-12-07T14:13:14.456311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Inference","metadata":{}},{"cell_type":"code","source":"def predict(parser):\n    inference = parser.get_parsed_content(\"inferer\")\n    loader = parser.get_parsed_content(\"dataloader\")\n    network = parser.get_parsed_content(\"network_def\")\n    \n    state_dict = torch.load(\"/kaggle/input/monai-breast-density-classification/breast_density_classification/models/model.pt\")\n    network.load_state_dict(state_dict, strict=True)\n\n    preds = []\n    network.eval()\n    with torch.no_grad():\n        for batch in tqdm(loader):\n            pred = inference(batch['image'], network)\n            pred = pred.softmax(-1)\n            preds.append(pred.detach().cpu().numpy())\n\n    return np.concatenate(preds)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:09.495543Z","iopub.execute_input":"2022-12-07T14:19:09.495997Z","iopub.status.idle":"2022-12-07T14:19:09.503616Z","shell.execute_reply.started":"2022-12-07T14:19:09.495959Z","shell.execute_reply":"2022-12-07T14:19:09.502568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:15.796773Z","iopub.execute_input":"2022-12-07T14:13:15.797149Z","iopub.status.idle":"2022-12-07T14:13:31.556855Z","shell.execute_reply.started":"2022-12-07T14:13:15.797112Z","shell.execute_reply":"2022-12-07T14:13:31.555653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Plot results","metadata":{}},{"cell_type":"code","source":"CLASSES = [\"A\", \"B\", \"C\", \"D\"]\ndata = json.load(open('configs/sample_image_data.json', 'r'))['Test']","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:31.573462Z","iopub.execute_input":"2022-12-07T14:13:31.574275Z","iopub.status.idle":"2022-12-07T14:13:31.579946Z","shell.execute_reply.started":"2022-12-07T14:13:31.574243Z","shell.execute_reply":"2022-12-07T14:13:31.578957Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20, 20))\n\nfor i, d in enumerate(data):\n    plt.subplot(4, 4, i + 1)\n    y = CLASSES[np.argmax(d['label'])]\n    pred = CLASSES[np.argmax(preds[i])]\n    conf = np.max(preds[i])\n    \n    \n    img = cv2.imread(d['image'])\n    img = cv2.resize(img, (512, 512))\n    plt.imshow(img)\n    plt.title(f'Truth : {y} - Pred {pred} (conf={conf:.3f})')\n    plt.axis(False)\n    \nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:31.582598Z","iopub.execute_input":"2022-12-07T14:13:31.583612Z","iopub.status.idle":"2022-12-07T14:13:34.642271Z","shell.execute_reply.started":"2022-12-07T14:13:31.583565Z","shell.execute_reply":"2022-12-07T14:13:34.640449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Density of RSNA Test Data","metadata":{}},{"cell_type":"markdown","source":"### Data","metadata":{}},{"cell_type":"code","source":"def create_rsna_dataset(base_dir: str, output_file: str, num_files=0):\n    output_list = []\n\n    for _file in glob.glob(base_dir + \"*.png\"):\n        _out = {\"image\": _file, \"label\": [0, 0, 0, 0]}\n        output_list.append(_out)\n\n    if num_files:\n        output_list = output_list[:num_files]\n\n    data_dict = {\"Test\": output_list}\n\n    fid = open(output_file, \"w\")\n    json.dump(data_dict, fid, indent=1)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:34.64401Z","iopub.execute_input":"2022-12-07T14:13:34.644689Z","iopub.status.idle":"2022-12-07T14:13:34.65189Z","shell.execute_reply.started":"2022-12-07T14:13:34.644637Z","shell.execute_reply":"2022-12-07T14:13:34.650683Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_rsna_dataset(SAVE_FOLDER, \"configs/rsna_test.json\")","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:34.653686Z","iopub.execute_input":"2022-12-07T14:13:34.654027Z","iopub.status.idle":"2022-12-07T14:13:34.662962Z","shell.execute_reply.started":"2022-12-07T14:13:34.653995Z","shell.execute_reply":"2022-12-07T14:13:34.661665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Config\n- Update the data config path\n- Modify the reader to handle grayscale images\n    ```\n    \"_target_\": \"LoadImaged\",\n    \"reader\": \"PILReader\",\n    \"converter\" : \"$lambda img: img.convert('RGB')\",\n    \"keys\": \"image\"\n     ```","metadata":{}},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference_rsna_test.json\"","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:34.664353Z","iopub.execute_input":"2022-12-07T14:13:34.665594Z","iopub.status.idle":"2022-12-07T14:13:34.671997Z","shell.execute_reply.started":"2022-12-07T14:13:34.665565Z","shell.execute_reply":"2022-12-07T14:13:34.67073Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile $CONFIG_FILE\n\n{\n    \"import\": [\n        \"$import glob\",\n        \"$import os\",\n        \"$import torchvision\"\n    ],\n    \"bundle_root\": \".\",\n    \"model_dir\": \"$@bundle_root + '/models'\",\n    \"output_dir\": \"$@bundle_root + '/output'\",\n    \"data\": {\n        \"_target_\": \"createList.CreateImageLabelList\",\n        \"filename\": \"../configs/rsna_test.json\"\n    },\n    \"test_imagelist\": \"$@data.create_dataset('Test')[0]\",\n    \"test_labellist\": \"$@data.create_dataset('Test')[1]\",\n    \"dataset\": {\n        \"_target_\": \"CacheDataset\",\n        \"data\": \"$[{'image': i, 'label': l} for i, l in zip(@test_imagelist, @test_labellist)]\",\n        \"transform\": \"@preprocessing\",\n        \"cache_rate\": 1,\n        \"num_workers\": 2\n    },\n    \"dataloader\": {\n        \"_target_\": \"DataLoader\",\n        \"dataset\": \"@dataset\",\n        \"batch_size\": 16,\n        \"shuffle\": false,\n        \"num_workers\": 2\n    },\n    \"device\": \"$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\",\n    \"network_def\": {\n        \"_target_\": \"TorchVisionFCModel\",\n        \"model_name\": \"inception_v3\",\n        \"num_classes\": 4,\n        \"pool\": null,\n        \"use_conv\": false,\n        \"bias\": true,\n        \"pretrained\": true\n    },\n    \"network\": \"$@network_def.to(@device)\",\n    \"preprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"LoadImaged\",\n                \"reader\": \"PILReader\",\n                \"converter\" : \"$lambda img: img.convert('RGB')\",\n                \"keys\": \"image\"\n            },\n            {\n                \"_target_\": \"EnsureChannelFirstd\",\n                \"keys\": \"image\",\n                \"channel_dim\": 2\n            },\n            {\n                \"_target_\": \"ScaleIntensityd\",\n                \"keys\": \"image\",\n                \"minv\": 0.0,\n                \"maxv\": 1.0\n            },\n            {\n                \"_target_\": \"Resized\",\n                \"keys\": \"image\",\n                \"spatial_size\": [\n                    299,\n                    299\n                ]\n            }\n        ]\n    },\n    \"inferer\": {\n        \"_target_\": \"SimpleInferer\"\n    },\n    \"postprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"Activationsd\",\n                \"keys\": \"pred\",\n                \"sigmoid\": false\n            }\n        ]\n    },\n    \"handlers\": [\n        {\n            \"_target_\": \"CheckpointLoader\",\n            \"load_path\": \"$@model_dir + '/model.pt'\",\n            \"load_dict\": {\n                \"model\": \"@network\"\n            }\n        },\n        {\n            \"_target_\": \"StatsHandler\",\n            \"iteration_log\": false,\n            \"output_transform\": \"$lambda x: None\"\n        },\n        {\n            \"_target_\": \"ClassificationSaver\",\n            \"output_dir\": \"@output_dir\",\n            \"batch_transform\": \"$monai.handlers.from_engine(['image_meta_dict'])\",\n            \"output_transform\": \"$monai.handlers.from_engine(['pred'])\"\n        }\n    ],\n    \"evaluator\": {\n        \"_target_\": \"SupervisedEvaluator\",\n        \"device\": \"@device\",\n        \"val_data_loader\": \"@dataloader\",\n        \"network\": \"@network\",\n        \"inferer\": \"@inferer\",\n        \"postprocessing\": \"@postprocessing\",\n        \"val_handlers\": \"@handlers\",\n        \"amp\": true\n    },\n    \"evaluating\": [\n        \"$setattr(torch.backends.cudnn, 'benchmark', True)\",\n        \"$@evaluator.run()\"\n    ]\n}\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T14:13:53.694149Z","iopub.execute_input":"2022-12-07T14:13:53.694514Z","iopub.status.idle":"2022-12-07T14:13:53.702908Z","shell.execute_reply.started":"2022-12-07T14:13:53.694481Z","shell.execute_reply":"2022-12-07T14:13:53.701711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Inference","metadata":{}},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:55.229143Z","iopub.execute_input":"2022-12-07T14:13:55.229511Z","iopub.status.idle":"2022-12-07T14:13:55.235803Z","shell.execute_reply.started":"2022-12-07T14:13:55.229479Z","shell.execute_reply":"2022-12-07T14:13:55.234705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"parser = ConfigParser()\n\nparser.read_config(CONFIG_FILE)\n\ndata = parser.get_parsed_content(\"data\")\ndevice = parser.get_parsed_content(\"device\")","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:55.436263Z","iopub.execute_input":"2022-12-07T14:13:55.436992Z","iopub.status.idle":"2022-12-07T14:13:55.471706Z","shell.execute_reply.started":"2022-12-07T14:13:55.436946Z","shell.execute_reply":"2022-12-07T14:13:55.470783Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:55.625674Z","iopub.execute_input":"2022-12-07T14:13:55.626068Z","iopub.status.idle":"2022-12-07T14:13:55.632577Z","shell.execute_reply.started":"2022-12-07T14:13:55.626034Z","shell.execute_reply":"2022-12-07T14:13:55.631278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:56.645991Z","iopub.execute_input":"2022-12-07T14:13:56.646697Z","iopub.status.idle":"2022-12-07T14:13:58.253606Z","shell.execute_reply.started":"2022-12-07T14:13:56.64666Z","shell.execute_reply":"2022-12-07T14:13:58.252472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(20, 20))\ndata = json.load(open('configs/rsna_test.json', 'r'))['Test']\n\nfor i, d in enumerate(data):\n    plt.subplot(1, 4, i + 1)\n    pred = CLASSES[np.argmax(preds[i])]\n    conf = np.max(preds[i])\n    \n    img = cv2.imread(d['image'])\n    img = cv2.resize(img, (512, 512))\n    plt.imshow(img)\n    plt.title(d['image'].split('/')[-1][:-4] + f' - Pred : {pred} (conf={conf:.3f})')\n    plt.axis(False)\n\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:13:58.255978Z","iopub.execute_input":"2022-12-07T14:13:58.256689Z","iopub.status.idle":"2022-12-07T14:13:58.695734Z","shell.execute_reply.started":"2022-12-07T14:13:58.256639Z","shell.execute_reply":"2022-12-07T14:13:58.694648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Density of RSNA Train Data","metadata":{}},{"cell_type":"code","source":"create_rsna_dataset(\"/kaggle/input/rsna-breast-cancer-512-pngs/\", \"configs/rsna_train.json\", num_files=1000)  # I use a subset for faster computing times.","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:16.395838Z","iopub.execute_input":"2022-12-07T14:19:16.396538Z","iopub.status.idle":"2022-12-07T14:19:16.900889Z","shell.execute_reply.started":"2022-12-07T14:19:16.396501Z","shell.execute_reply":"2022-12-07T14:19:16.899907Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference_rsna_train.json\"","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:16.903013Z","iopub.execute_input":"2022-12-07T14:19:16.903415Z","iopub.status.idle":"2022-12-07T14:19:16.909138Z","shell.execute_reply.started":"2022-12-07T14:19:16.903378Z","shell.execute_reply":"2022-12-07T14:19:16.908027Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile $CONFIG_FILE\n\n{\n    \"import\": [\n        \"$import glob\",\n        \"$import os\",\n        \"$import torchvision\"\n    ],\n    \"bundle_root\": \".\",\n    \"model_dir\": \"$@bundle_root + '/models'\",\n    \"output_dir\": \"$@bundle_root + '/output'\",\n    \"data\": {\n        \"_target_\": \"createList.CreateImageLabelList\",\n        \"filename\": \"../configs/rsna_train.json\"\n    },\n    \"test_imagelist\": \"$@data.create_dataset('Test')[0]\",\n    \"test_labellist\": \"$@data.create_dataset('Test')[1]\",\n    \"dataset\": {\n        \"_target_\": \"CacheDataset\",\n        \"data\": \"$[{'image': i, 'label': l} for i, l in zip(@test_imagelist, @test_labellist)]\",\n        \"transform\": \"@preprocessing\",\n        \"copy_cache\": false,\n        \"cache_rate\": 0.1,\n        \"num_workers\": 2\n    },\n    \"dataloader\": {\n        \"_target_\": \"DataLoader\",\n        \"dataset\": \"@dataset\",\n        \"batch_size\": 16,\n        \"shuffle\": false,\n        \"num_workers\": 2\n    },\n    \"device\": \"$torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')\",\n    \"network_def\": {\n        \"_target_\": \"TorchVisionFCModel\",\n        \"model_name\": \"inception_v3\",\n        \"num_classes\": 4,\n        \"pool\": null,\n        \"use_conv\": false,\n        \"bias\": true,\n        \"pretrained\": true\n    },\n    \"network\": \"$@network_def.to(@device)\",\n    \"preprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"LoadImaged\",\n                \"reader\": \"PILReader\",\n                \"converter\" : \"$lambda img: img.convert('RGB')\",\n                \"keys\": \"image\"\n            },\n            {\n                \"_target_\": \"EnsureChannelFirstd\",\n                \"keys\": \"image\",\n                \"channel_dim\": 2\n            },\n            {\n                \"_target_\": \"ScaleIntensityd\",\n                \"keys\": \"image\",\n                \"minv\": 0.0,\n                \"maxv\": 1.0\n            },\n            {\n                \"_target_\": \"Resized\",\n                \"keys\": \"image\",\n                \"spatial_size\": [\n                    299,\n                    299\n                ]\n            }\n        ]\n    },\n    \"inferer\": {\n        \"_target_\": \"SimpleInferer\"\n    },\n    \"postprocessing\": {\n        \"_target_\": \"Compose\",\n        \"transforms\": [\n            {\n                \"_target_\": \"Activationsd\",\n                \"keys\": \"pred\",\n                \"sigmoid\": false\n            }\n        ]\n    },\n    \"handlers\": [\n        {\n            \"_target_\": \"CheckpointLoader\",\n            \"load_path\": \"$@model_dir + '/model.pt'\",\n            \"load_dict\": {\n                \"model\": \"@network\"\n            }\n        },\n        {\n            \"_target_\": \"StatsHandler\",\n            \"iteration_log\": false,\n            \"output_transform\": \"$lambda x: None\"\n        },\n        {\n            \"_target_\": \"ClassificationSaver\",\n            \"output_dir\": \"@output_dir\",\n            \"batch_transform\": \"$monai.handlers.from_engine(['image_meta_dict'])\",\n            \"output_transform\": \"$monai.handlers.from_engine(['pred'])\"\n        }\n    ],\n    \"evaluator\": {\n        \"_target_\": \"SupervisedEvaluator\",\n        \"device\": \"@device\",\n        \"val_data_loader\": \"@dataloader\",\n        \"network\": \"@network\",\n        \"inferer\": \"@inferer\",\n        \"postprocessing\": \"@postprocessing\",\n        \"val_handlers\": \"@handlers\",\n        \"amp\": true\n    },\n    \"evaluating\": [\n        \"$setattr(torch.backends.cudnn, 'benchmark', True)\",\n        \"$@evaluator.run()\"\n    ]\n}\n\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-12-07T14:19:18.74583Z","iopub.execute_input":"2022-12-07T14:19:18.746237Z","iopub.status.idle":"2022-12-07T14:19:18.757159Z","shell.execute_reply.started":"2022-12-07T14:19:18.746204Z","shell.execute_reply":"2022-12-07T14:19:18.755907Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:19.470848Z","iopub.execute_input":"2022-12-07T14:19:19.47198Z","iopub.status.idle":"2022-12-07T14:19:19.479775Z","shell.execute_reply.started":"2022-12-07T14:19:19.47193Z","shell.execute_reply":"2022-12-07T14:19:19.478575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"parser = ConfigParser()\n\nparser.read_config(CONFIG_FILE)\n\ndata = parser.get_parsed_content(\"data\")\ndevice = parser.get_parsed_content(\"device\")","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:19.684048Z","iopub.execute_input":"2022-12-07T14:19:19.684427Z","iopub.status.idle":"2022-12-07T14:19:19.717414Z","shell.execute_reply.started":"2022-12-07T14:19:19.684395Z","shell.execute_reply":"2022-12-07T14:19:19.716436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:19:19.989554Z","iopub.execute_input":"2022-12-07T14:19:19.989966Z","iopub.status.idle":"2022-12-07T14:19:19.998619Z","shell.execute_reply.started":"2022-12-07T14:19:19.989931Z","shell.execute_reply":"2022-12-07T14:19:19.9975Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:26:20.993121Z","iopub.execute_input":"2022-12-07T14:26:20.993506Z","iopub.status.idle":"2022-12-07T14:26:20.998805Z","shell.execute_reply.started":"2022-12-07T14:26:20.99347Z","shell.execute_reply":"2022-12-07T14:26:20.997448Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.save('/kaggle/working/preds_density.npy', preds)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:17:00.822862Z","iopub.execute_input":"2022-12-07T14:17:00.823277Z","iopub.status.idle":"2022-12-07T14:17:00.830477Z","shell.execute_reply.started":"2022-12-07T14:17:00.823239Z","shell.execute_reply":"2022-12-07T14:17:00.829407Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Results","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\n\nfrom itertools import product\nfrom sklearn.metrics import confusion_matrix\n\n\ndef plot_confusion_matrix(\n    y_pred,\n    y_true,\n    cm=None,\n    normalize=None,\n    display_labels=None,\n    cmap=\"viridis\",\n):\n    \"\"\"\n    Computes and plots a confusion matrix.\n    Args:\n        y_pred (numpy array): Predictions.\n        y_true (numpy array): Truths.\n        normalize (bool or None, optional): Whether to normalize the matrix. Defaults to None.\n        display_labels (list of strings or None, optional): Axis labels. Defaults to None.\n        cmap (str, optional): Colormap name. Defaults to \"viridis\".\n    \"\"\"\n    if cm is None:\n        cm = confusion_matrix(y_true, y_pred, normalize=normalize)\n    cm = cm[::-1, :]\n\n    # Display colormap\n    n_classes = cm.shape[0]\n    im_ = plt.imshow(cm, interpolation=\"nearest\", cmap=cmap)\n\n    # Display values\n    cmap_min, cmap_max = im_.cmap(0), im_.cmap(256)\n    thresh = (cm.max() + cm.min()) / 2.0\n    for i, j in product(range(n_classes), range(n_classes)):\n        color = cmap_max if cm[i, j] < thresh else cmap_min\n        text = f\"{cm[i, j]:.0f}\" if normalize is None else f\"{cm[i, j]:.3f}\"\n        plt.text(\n            j, i, text, ha=\"center\", va=\"center\", color=color\n        )\n\n    # Display legend\n    plt.xlim(-0.5, n_classes - 0.5)\n    plt.ylim(-0.5, n_classes - 0.5)\n    plt.xticks(\n        np.arange(n_classes), display_labels\n        # [d for i, d in enumerate(display_labels) if i in np.unique(y_true)]\n    )\n    plt.yticks(np.arange(n_classes), display_labels[::-1])\n\n    plt.ylabel(\"True label\", fontsize=12)\n    plt.xlabel(\"Predicted label\", fontsize=12)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:37:34.670576Z","iopub.execute_input":"2022-12-07T14:37:34.67129Z","iopub.status.idle":"2022-12-07T14:37:34.683554Z","shell.execute_reply.started":"2022-12-07T14:37:34.671253Z","shell.execute_reply":"2022-12-07T14:37:34.682463Z"},"_kg_hide-input":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sns.countplot(x=preds.argmax(-1))\nplt.title('Predictions Repartition')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:26:29.158106Z","iopub.execute_input":"2022-12-07T14:26:29.158528Z","iopub.status.idle":"2022-12-07T14:26:29.304113Z","shell.execute_reply.started":"2022-12-07T14:26:29.15849Z","shell.execute_reply":"2022-12-07T14:26:29.302793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data = json.load(open('configs/rsna_train.json', 'r'))['Test']\nimg_ids = [int(d['image'].split('_')[-1][:-4]) for d in data]\n\ndf = pd.read_csv('/kaggle/input/rsna-breast-cancer-detection/train.csv')\ndf = df.set_index('image_id').loc[img_ids]\n\ndf['pred'] = [CLASSES[p] for p in preds.argmax(-1)]\ndf = df[['density', 'pred']].dropna(axis=0)","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:35:25.715291Z","iopub.execute_input":"2022-12-07T14:35:25.715661Z","iopub.status.idle":"2022-12-07T14:35:25.785734Z","shell.execute_reply.started":"2022-12-07T14:35:25.715621Z","shell.execute_reply":"2022-12-07T14:35:25.784774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(8, 8))\nplot_confusion_matrix(df['pred'], df['density'], display_labels=CLASSES)\nplt.title('Confusion Matrix', size=15)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-12-07T14:44:29.73726Z","iopub.execute_input":"2022-12-07T14:44:29.738087Z","iopub.status.idle":"2022-12-07T14:44:29.939533Z","shell.execute_reply.started":"2022-12-07T14:44:29.738037Z","shell.execute_reply":"2022-12-07T14:44:29.938199Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Done !","metadata":{}}]}