{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":39272,"databundleVersionId":4629629,"sourceType":"competition"},{"sourceId":1873742,"sourceType":"datasetVersion","datasetId":1115384},{"sourceId":4619805,"sourceType":"datasetVersion","datasetId":2688675},{"sourceId":4679582,"sourceType":"datasetVersion","datasetId":2711917}],"dockerImageVersionId":30302,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"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":"2024-03-14T04:04:00.384835Z","iopub.execute_input":"2024-03-14T04:04:00.385894Z","iopub.status.idle":"2024-03-14T04:04:12.202825Z","shell.execute_reply.started":"2024-03-14T04:04:00.385853Z","shell.execute_reply":"2024-03-14T04:04:12.201572Z"},"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":"2024-03-14T04:04:18.215272Z","iopub.execute_input":"2024-03-14T04:04:18.216116Z","iopub.status.idle":"2024-03-14T04:04:18.222908Z","shell.execute_reply.started":"2024-03-14T04:04:18.216077Z","shell.execute_reply":"2024-03-14T04:04:18.221867Z"},"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":"2024-03-14T04:04:19.348804Z","iopub.execute_input":"2024-03-14T04:04:19.349225Z","iopub.status.idle":"2024-03-14T04:04:19.360367Z","shell.execute_reply.started":"2024-03-14T04:04:19.349192Z","shell.execute_reply":"2024-03-14T04:04:19.359262Z"},"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":"2024-03-14T04:04:19.931908Z","iopub.execute_input":"2024-03-14T04:04:19.932661Z","iopub.status.idle":"2024-03-14T04:04:19.947475Z","shell.execute_reply.started":"2024-03-14T04:04:19.932619Z","shell.execute_reply":"2024-03-14T04:04:19.946666Z"},"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":"2024-03-14T04:04:20.393241Z","iopub.execute_input":"2024-03-14T04:04:20.393634Z","iopub.status.idle":"2024-03-14T04:04:23.206138Z","shell.execute_reply.started":"2024-03-14T04:04:20.393596Z","shell.execute_reply":"2024-03-14T04:04:23.205024Z"},"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":"2024-03-14T04:04:24.691908Z","iopub.execute_input":"2024-03-14T04:04:24.692296Z","iopub.status.idle":"2024-03-14T04:04:24.697458Z","shell.execute_reply.started":"2024-03-14T04:04:24.692264Z","shell.execute_reply":"2024-03-14T04:04:24.69648Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cp -r $MODEL_PATH ./","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:25.492502Z","iopub.execute_input":"2024-03-14T04:04:25.49343Z","iopub.status.idle":"2024-03-14T04:04:27.366346Z","shell.execute_reply.started":"2024-03-14T04:04:25.493392Z","shell.execute_reply":"2024-03-14T04:04:27.365008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd breast_density_classification","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:27.368407Z","iopub.execute_input":"2024-03-14T04:04:27.36874Z","iopub.status.idle":"2024-03-14T04:04:27.375767Z","shell.execute_reply.started":"2024-03-14T04:04:27.368709Z","shell.execute_reply":"2024-03-14T04:04:27.374674Z"},"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":"2024-03-14T04:04:29.018052Z","iopub.execute_input":"2024-03-14T04:04:29.018826Z","iopub.status.idle":"2024-03-14T04:04:29.028624Z","shell.execute_reply.started":"2024-03-14T04:04:29.018791Z","shell.execute_reply":"2024-03-14T04:04:29.027566Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_dataset(\"sample_data\", \"configs/sample_image_data.json\")","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:29.709704Z","iopub.execute_input":"2024-03-14T04:04:29.710112Z","iopub.status.idle":"2024-03-14T04:04:29.716347Z","shell.execute_reply.started":"2024-03-14T04:04:29.710079Z","shell.execute_reply":"2024-03-14T04:04:29.715116Z"},"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":"2024-03-14T04:04:31.294104Z","iopub.execute_input":"2024-03-14T04:04:31.294501Z","iopub.status.idle":"2024-03-14T04:04:31.299671Z","shell.execute_reply.started":"2024-03-14T04:04:31.29447Z","shell.execute_reply":"2024-03-14T04:04:31.298554Z"},"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":"2024-03-14T04:04:32.098611Z","iopub.execute_input":"2024-03-14T04:04:32.09929Z","iopub.status.idle":"2024-03-14T04:04:32.108244Z","shell.execute_reply.started":"2024-03-14T04:04:32.099253Z","shell.execute_reply":"2024-03-14T04:04:32.107202Z"},"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":"2024-03-14T04:04:33.236087Z","iopub.execute_input":"2024-03-14T04:04:33.236463Z","iopub.status.idle":"2024-03-14T04:04:33.242848Z","shell.execute_reply.started":"2024-03-14T04:04:33.236431Z","shell.execute_reply":"2024-03-14T04:04:33.241888Z"},"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":"2024-03-14T04:04:33.838939Z","iopub.execute_input":"2024-03-14T04:04:33.839344Z","iopub.status.idle":"2024-03-14T04:04:33.933556Z","shell.execute_reply.started":"2024-03-14T04:04:33.839309Z","shell.execute_reply":"2024-03-14T04:04:33.932719Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:34.432135Z","iopub.execute_input":"2024-03-14T04:04:34.433012Z","iopub.status.idle":"2024-03-14T04:04:34.438823Z","shell.execute_reply.started":"2024-03-14T04:04:34.432977Z","shell.execute_reply":"2024-03-14T04:04:34.437872Z"},"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":"2024-03-14T04:04:35.898044Z","iopub.execute_input":"2024-03-14T04:04:35.898852Z","iopub.status.idle":"2024-03-14T04:04:35.907175Z","shell.execute_reply.started":"2024-03-14T04:04:35.898815Z","shell.execute_reply":"2024-03-14T04:04:35.906018Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a = '/kaggle/input/rsna-breast-cancer-512-pngs'\n","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:35:03.316356Z","iopub.execute_input":"2024-03-14T04:35:03.317139Z","iopub.status.idle":"2024-03-14T04:35:03.321482Z","shell.execute_reply.started":"2024-03-14T04:35:03.317101Z","shell.execute_reply":"2024-03-14T04:35:03.320426Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:36.473317Z","iopub.execute_input":"2024-03-14T04:04:36.4737Z","iopub.status.idle":"2024-03-14T04:04:46.22645Z","shell.execute_reply.started":"2024-03-14T04:04:36.473669Z","shell.execute_reply":"2024-03-14T04:04:46.22523Z"},"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":"2024-03-14T04:04:52.095619Z","iopub.execute_input":"2024-03-14T04:04:52.096779Z","iopub.status.idle":"2024-03-14T04:04:52.102315Z","shell.execute_reply.started":"2024-03-14T04:04:52.096728Z","shell.execute_reply":"2024-03-14T04:04:52.101294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(data)","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:35:38.486878Z","iopub.execute_input":"2024-03-14T04:35:38.487858Z","iopub.status.idle":"2024-03-14T04:35:38.493912Z","shell.execute_reply.started":"2024-03-14T04:35:38.48782Z","shell.execute_reply":"2024-03-14T04:35:38.492873Z"},"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":"2024-03-14T04:04:52.555055Z","iopub.execute_input":"2024-03-14T04:04:52.55558Z","iopub.status.idle":"2024-03-14T04:04:55.448033Z","shell.execute_reply.started":"2024-03-14T04:04:52.555528Z","shell.execute_reply":"2024-03-14T04:04:55.447026Z"},"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":"2024-03-14T04:04:55.450077Z","iopub.execute_input":"2024-03-14T04:04:55.45078Z","iopub.status.idle":"2024-03-14T04:04:55.459231Z","shell.execute_reply.started":"2024-03-14T04:04:55.450743Z","shell.execute_reply":"2024-03-14T04:04:55.458117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"create_rsna_dataset(SAVE_FOLDER, \"configs/rsna_test.json\")","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:04:55.460306Z","iopub.execute_input":"2024-03-14T04:04:55.460588Z","iopub.status.idle":"2024-03-14T04:04:55.46975Z","shell.execute_reply.started":"2024-03-14T04:04:55.46056Z","shell.execute_reply":"2024-03-14T04:04:55.468766Z"},"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":"2024-03-14T04:04:58.77831Z","iopub.execute_input":"2024-03-14T04:04:58.779131Z","iopub.status.idle":"2024-03-14T04:04:58.78338Z","shell.execute_reply.started":"2024-03-14T04:04:58.779094Z","shell.execute_reply":"2024-03-14T04:04:58.782362Z"},"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":"2024-03-14T04:04:59.357912Z","iopub.execute_input":"2024-03-14T04:04:59.358811Z","iopub.status.idle":"2024-03-14T04:04:59.367595Z","shell.execute_reply.started":"2024-03-14T04:04:59.358778Z","shell.execute_reply":"2024-03-14T04:04:59.366379Z"},"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":"2024-03-14T04:05:00.202346Z","iopub.execute_input":"2024-03-14T04:05:00.203065Z","iopub.status.idle":"2024-03-14T04:05:00.209442Z","shell.execute_reply.started":"2024-03-14T04:05:00.203029Z","shell.execute_reply":"2024-03-14T04:05:00.20846Z"},"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":"2024-03-14T04:05:00.661694Z","iopub.execute_input":"2024-03-14T04:05:00.662121Z","iopub.status.idle":"2024-03-14T04:05:00.704354Z","shell.execute_reply.started":"2024-03-14T04:05:00.662087Z","shell.execute_reply":"2024-03-14T04:05:00.703516Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:05:01.456984Z","iopub.execute_input":"2024-03-14T04:05:01.457415Z","iopub.status.idle":"2024-03-14T04:05:01.463832Z","shell.execute_reply.started":"2024-03-14T04:05:01.457381Z","shell.execute_reply":"2024-03-14T04:05:01.462793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:05:01.692918Z","iopub.execute_input":"2024-03-14T04:05:01.693809Z","iopub.status.idle":"2024-03-14T04:05:03.086794Z","shell.execute_reply.started":"2024-03-14T04:05:01.693774Z","shell.execute_reply":"2024-03-14T04:05:03.08571Z"},"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":"2024-03-14T04:05:06.700834Z","iopub.execute_input":"2024-03-14T04:05:06.701261Z","iopub.status.idle":"2024-03-14T04:05:07.165098Z","shell.execute_reply.started":"2024-03-14T04:05:06.701223Z","shell.execute_reply":"2024-03-14T04:05:07.164068Z"},"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":"2024-03-14T04:05:17.334335Z","iopub.execute_input":"2024-03-14T04:05:17.334738Z","iopub.status.idle":"2024-03-14T04:05:19.72463Z","shell.execute_reply.started":"2024-03-14T04:05:17.334698Z","shell.execute_reply":"2024-03-14T04:05:19.723701Z"},"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":"2024-03-14T04:05:19.726679Z","iopub.execute_input":"2024-03-14T04:05:19.727121Z","iopub.status.idle":"2024-03-14T04:05:19.732264Z","shell.execute_reply.started":"2024-03-14T04:05:19.72708Z","shell.execute_reply":"2024-03-14T04:05:19.73115Z"},"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":"2024-03-14T04:05:19.733924Z","iopub.execute_input":"2024-03-14T04:05:19.73448Z","iopub.status.idle":"2024-03-14T04:05:19.74477Z","shell.execute_reply.started":"2024-03-14T04:05:19.734441Z","shell.execute_reply":"2024-03-14T04:05:19.743863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:05:19.746724Z","iopub.execute_input":"2024-03-14T04:05:19.747084Z","iopub.status.idle":"2024-03-14T04:05:19.757049Z","shell.execute_reply.started":"2024-03-14T04:05:19.747056Z","shell.execute_reply":"2024-03-14T04:05:19.756084Z"},"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":"2024-03-14T04:05:19.758262Z","iopub.execute_input":"2024-03-14T04:05:19.758623Z","iopub.status.idle":"2024-03-14T04:05:19.80094Z","shell.execute_reply.started":"2024-03-14T04:05:19.758586Z","shell.execute_reply":"2024-03-14T04:05:19.800186Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:05:19.802233Z","iopub.execute_input":"2024-03-14T04:05:19.802595Z","iopub.status.idle":"2024-03-14T04:05:19.808838Z","shell.execute_reply.started":"2024-03-14T04:05:19.802559Z","shell.execute_reply":"2024-03-14T04:05:19.807759Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:05:19.8107Z","iopub.execute_input":"2024-03-14T04:05:19.810999Z","iopub.status.idle":"2024-03-14T04:07:33.879047Z","shell.execute_reply.started":"2024-03-14T04:05:19.810948Z","shell.execute_reply":"2024-03-14T04:07:33.878Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.save('/kaggle/working/preds_density.npy', preds)","metadata":{"execution":{"iopub.status.busy":"2024-03-14T04:07:42.17637Z","iopub.execute_input":"2024-03-14T04:07:42.176754Z","iopub.status.idle":"2024-03-14T04:07:42.182879Z","shell.execute_reply.started":"2024-03-14T04:07:42.176721Z","shell.execute_reply":"2024-03-14T04:07:42.181909Z"},"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":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-03-14T04:07:52.523817Z","iopub.execute_input":"2024-03-14T04:07:52.524615Z","iopub.status.idle":"2024-03-14T04:07:52.536926Z","shell.execute_reply.started":"2024-03-14T04:07:52.524566Z","shell.execute_reply":"2024-03-14T04:07:52.535879Z"},"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":"2024-03-14T04:07:54.911131Z","iopub.execute_input":"2024-03-14T04:07:54.911546Z","iopub.status.idle":"2024-03-14T04:07:55.104789Z","shell.execute_reply.started":"2024-03-14T04:07:54.911495Z","shell.execute_reply":"2024-03-14T04:07:55.103725Z"},"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":"2024-03-14T04:07:57.619877Z","iopub.execute_input":"2024-03-14T04:07:57.620815Z","iopub.status.idle":"2024-03-14T04:07:57.745629Z","shell.execute_reply.started":"2024-03-14T04:07:57.620778Z","shell.execute_reply":"2024-03-14T04:07:57.744786Z"},"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":"2024-03-14T04:08:00.666909Z","iopub.execute_input":"2024-03-14T04:08:00.667312Z","iopub.status.idle":"2024-03-14T04:08:00.875342Z","shell.execute_reply.started":"2024-03-14T04:08:00.667279Z","shell.execute_reply":"2024-03-14T04:08:00.873811Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Done !","metadata":{}}]}