{"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":10382816,"sourceType":"datasetVersion","datasetId":6431831},{"sourceId":10413381,"sourceType":"datasetVersion","datasetId":6453733},{"sourceId":11184483,"sourceType":"datasetVersion","datasetId":6981598}],"dockerImageVersionId":30302,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -q \"monai-weekly[gdown, nibabel, tqdm, itk]\"","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-03-27T08:02:01.831823Z","iopub.execute_input":"2025-03-27T08:02:01.832881Z","iopub.status.idle":"2025-03-27T08:02:10.058673Z","shell.execute_reply.started":"2025-03-27T08:02:01.832826Z","shell.execute_reply":"2025-03-27T08:02:10.057496Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nimport tempfile\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport numpy as np\nimport cv2\nfrom sklearn.metrics import classification_report\nimport torch\nfrom monai.apps import download_and_extract\nfrom monai.config import print_config\nfrom monai.metrics import ROCAUCMetric\nfrom monai.networks.nets import DenseNet121\nfrom monai.transforms import *\nfrom monai.data import Dataset, DataLoader\nfrom monai.utils import set_determinism\n","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-03-27T08:02:10.060777Z","iopub.execute_input":"2025-03-27T08:02:10.061299Z","iopub.status.idle":"2025-03-27T08:02:10.068991Z","shell.execute_reply.started":"2025-03-27T08:02:10.061255Z","shell.execute_reply":"2025-03-27T08:02:10.068107Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dir='/kaggle/input/breast-cancer-vindr-fitvlute-kltn'\n#test_dir='../input/brain-tumor-classification-mri/Testing'","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2025-03-27T08:02:10.070169Z","iopub.execute_input":"2025-03-27T08:02:10.070389Z","iopub.status.idle":"2025-03-27T08:02:10.08085Z","shell.execute_reply.started":"2025-03-27T08:02:10.070368Z","shell.execute_reply":"2025-03-27T08:02:10.08009Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lấy danh sách các mục trong train_dir và chỉ giữ lại những mục là thư mục\nclass_names0 = os.listdir(train_dir)\nclass_names = [d for d in class_names0 if os.path.isdir(os.path.join(train_dir, d))]\nclass_names = sorted(class_names)\nprint(\"Các lớp:\", class_names)\nnum_class = len(class_names)\n\n# Lấy danh sách các file ảnh trong mỗi lớp, loại bỏ các file csv nếu có\nimage_files = [\n    [os.path.join(train_dir, class_name, x)\n     for x in os.listdir(os.path.join(train_dir, class_name))\n     if not x.endswith(\".csv\") or x.endswith(\"Birads2\")]\n    for class_name in class_names\n]\n\n# Khởi tạo danh sách file ảnh và nhãn\nimage_file_list = []\nimage_label_list = []\n\nfor i, class_name in enumerate(class_names):\n    image_file_list.extend(image_files[i])\n    image_label_list.extend([i] * len(image_files[i]))\n\nnum_total = len(image_label_list)\nprint(\"Tổng số ảnh:\", num_total)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:07:31.390333Z","iopub.execute_input":"2025-03-27T08:07:31.391292Z","iopub.status.idle":"2025-03-27T08:07:31.466258Z","shell.execute_reply.started":"2025-03-27T08:07:31.391249Z","shell.execute_reply":"2025-03-27T08:07:31.465302Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"valid_frac = 0.25\ntrainX,trainY = [],[]\nvalX,valY = [],[]\n\nfor i in range(num_total):\n    rann = np.random.random()\n    if rann < valid_frac:\n        valX.append(image_file_list[i])\n        valY.append(image_label_list[i])\n    else:\n        trainX.append(image_file_list[i])\n        trainY.append(image_label_list[i])\n\nprint(len(trainX),len(valX))","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:10.151244Z","iopub.execute_input":"2025-03-27T08:02:10.151513Z","iopub.status.idle":"2025-03-27T08:02:10.17482Z","shell.execute_reply.started":"2025-03-27T08:02:10.151489Z","shell.execute_reply":"2025-03-27T08:02:10.174095Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.subplots(3,3, figsize=(12,12))\nfor i,k in enumerate(np.random.randint(num_total, size=9)):\n    im = Image.open(image_file_list[k])\n    arr = np.array(im)\n    print(arr.shape)\n    plt.subplot(3,3, i+1)\n    plt.xlabel(class_names[image_label_list[k]])\n    plt.imshow(arr, cmap='gray', vmin=0, vmax=255)\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:10.175903Z","iopub.execute_input":"2025-03-27T08:02:10.176247Z","iopub.status.idle":"2025-03-27T08:02:13.460563Z","shell.execute_reply.started":"2025-03-27T08:02:10.176221Z","shell.execute_reply":"2025-03-27T08:02:13.459612Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"trainX=np.array(trainX)\ntrainY=np.array(trainY)\nvalX=np.array(valX)\nvalY=np.array(valY)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:13.462091Z","iopub.execute_input":"2025-03-27T08:02:13.46248Z","iopub.status.idle":"2025-03-27T08:02:13.477545Z","shell.execute_reply.started":"2025-03-27T08:02:13.462441Z","shell.execute_reply":"2025-03-27T08:02:13.476782Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SumDimension(Transform):\n    def __init__(self, dim=1):\n        self.dim = dim\n\n    def __call__(self, inputs):\n        return inputs.sum(self.dim)\nclass MyResize(Transform):\n    def __init__(self, size=(100, 100)):\n        self.size = size\n\n    def __call__(self, inputs):\n        # Đảm bảo inputs là numpy array\n        if isinstance(inputs, torch.Tensor):\n            inputs = inputs.cpu().numpy()\n        elif not isinstance(inputs, np.ndarray):\n            inputs = np.array(inputs)\n\n        # Đảm bảo dtype là float32 hoặc uint8\n        if inputs.dtype not in [np.float32, np.uint8]:\n            inputs = inputs.astype(np.float32)\n\n        # Xử lý trường hợp đầu vào có số chiều không mong muốn\n        if inputs.ndim == 3 and inputs.shape[0] == 1:  # (1, H, W) -> (H, W)\n            inputs = np.squeeze(inputs, axis=0)\n        elif inputs.ndim == 2:  # (H, W), không cần xử lý\n            pass\n        else:\n            raise ValueError(f\"Unsupported input shape {inputs.shape}\")\n\n        # Gọi cv2.resize\n        image2 = cv2.resize(inputs, dsize=(self.size[1], self.size[0]), interpolation=cv2.INTER_CUBIC)\n        return image2\n\n\ntrain_transforms = Compose([\n    LoadImage(image_only=True),\n    Resize((-1,1)),\n    SumDimension(2),\n    MyResize(),\n    AddChannel(),    \n    ToTensor(),\n])\n\nval_transforms = Compose([\n    LoadImage(image_only=True),\n    Resize((-1,1)),\n    SumDimension(2),\n    MyResize(),\n    AddChannel(),    \n    ToTensor(),\n])\n\ntest_transforms = Compose([\n    LoadImage(image_only=True),\n    Resize((-1,1)),\n    SumDimension(2),\n    MyResize(),\n    AddChannel(),    \n    ToTensor(),\n])\n\nact = Activations(softmax=True)\nto_onehot = AsDiscrete(to_onehot=num_class, n_classes=num_class)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:13.47863Z","iopub.execute_input":"2025-03-27T08:02:13.478896Z","iopub.status.idle":"2025-03-27T08:02:13.493317Z","shell.execute_reply.started":"2025-03-27T08:02:13.478873Z","shell.execute_reply":"2025-03-27T08:02:13.492444Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class MedNISTDataset(Dataset):\n\n    def __init__(self, image_files, labels, transforms):\n        self.image_files = image_files\n        self.labels = labels\n        self.transforms = transforms\n\n    def __len__(self):\n        return len(self.image_files)\n\n    def __getitem__(self, index):\n        return self.transforms(self.image_files[index]), self.labels[index]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-27T08:02:13.494457Z","iopub.execute_input":"2025-03-27T08:02:13.494828Z","iopub.status.idle":"2025-03-27T08:02:13.506434Z","shell.execute_reply.started":"2025-03-27T08:02:13.494801Z","shell.execute_reply":"2025-03-27T08:02:13.50562Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_ds = MedNISTDataset(trainX, trainY, train_transforms)\ntrain_loader = DataLoader(train_ds, batch_size=64, shuffle=True, num_workers=2)\n\nval_ds = MedNISTDataset(valX, valY, val_transforms)\nval_loader = DataLoader(val_ds, batch_size=64, num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-27T08:02:13.509387Z","iopub.execute_input":"2025-03-27T08:02:13.509663Z","iopub.status.idle":"2025-03-27T08:02:13.520377Z","shell.execute_reply.started":"2025-03-27T08:02:13.50964Z","shell.execute_reply":"2025-03-27T08:02:13.519548Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"device = torch.device(\"cuda:0\")   #\"cuda:0\"\nmodel = DenseNet121(\n    spatial_dims=2,            \n    in_channels=1,\n    out_channels=num_class,\n).to(device)\n\nloss_function = torch.nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), 1e-5)\nepoch_num = 30\nval_interval = 1","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:13.521365Z","iopub.execute_input":"2025-03-27T08:02:13.521615Z","iopub.status.idle":"2025-03-27T08:02:13.740839Z","shell.execute_reply.started":"2025-03-27T08:02:13.521591Z","shell.execute_reply":"2025-03-27T08:02:13.739865Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"best_metric = -1\nbest_metric_epoch = -1\nepoch_loss_values = list()\nauc_metric = ROCAUCMetric()\nmetric_values = list()\n\nfor epoch in range(epoch_num):\n    print('-' * 10)\n    print(f\"epoch {epoch + 1}/{epoch_num}\")\n    model.train()\n    epoch_loss = 0\n    step = 0\n\n    for batch_data in train_loader:\n        step += 1\n        inputs, labels = batch_data[0].to(device), batch_data[1].to(device)\n        optimizer.zero_grad()\n        outputs = model(inputs.float())     ##### \n        loss = loss_function(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        epoch_loss += loss.item()\n        print(f\"{step}/{len(train_ds) // train_loader.batch_size}, train_loss: {loss.item():.4f}\")\n        epoch_len = len(train_ds) // train_loader.batch_size\n\n    epoch_loss /= step\n    epoch_loss_values.append(epoch_loss)\n    print(f\"epoch {epoch + 1} average loss: {epoch_loss:.4f}\")\n\n    if (epoch + 1) % val_interval == 0:\n        model.eval()\n        with torch.no_grad():\n            y_pred = torch.tensor([], dtype=torch.float32, device=device)\n            y = torch.tensor([], dtype=torch.long, device=device)\n            for val_data in val_loader:\n                val_images, val_labels = val_data[0].to(device), val_data[1].to(device)\n                y_pred = torch.cat([y_pred, model(val_images.float())], dim=0)\n                y = torch.cat([y, val_labels], dim=0)\n                \n            y_onehot = [to_onehot(i) for i in y]\n            y_pred_act = [act(i) for i in y_pred]\n            auc_metric(y_pred_act, y_onehot)\n            auc_result = auc_metric.aggregate()\n            auc_metric.reset()\n            del y_pred_act, y_onehot\n            metric_values.append(auc_result)\n            acc_value = torch.eq(y_pred.argmax(dim=1), y)\n            acc_metric = acc_value.sum().item() / len(acc_value)\n            \n            if acc_metric > best_metric:\n                best_metric = acc_metric\n                best_metric_epoch = epoch + 1\n                torch.save(model.state_dict(), 'best_metric_model.pth')\n                print('saved new best metric model')\n                \n            print(f\"current epoch: {epoch + 1} current AUC: {auc_result:.4f}\"\n                  f\" current accuracy: {acc_metric:.4f} best AUC: {best_metric:.4f}\"\n                  f\" at epoch: {best_metric_epoch}\")\n            \nprint(f\"train completed, best_metric: {best_metric:.4f} at epoch: {best_metric_epoch}\")","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:02:13.74199Z","iopub.execute_input":"2025-03-27T08:02:13.742269Z","iopub.status.idle":"2025-03-27T08:03:30.372369Z","shell.execute_reply.started":"2025-03-27T08:02:13.742245Z","shell.execute_reply":"2025-03-27T08:03:30.369821Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference.json\"","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.37374Z","iopub.status.idle":"2025-03-27T08:03:30.374129Z","shell.execute_reply.started":"2025-03-27T08:03:30.373937Z","shell.execute_reply":"2025-03-27T08:03:30.373953Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.375674Z","iopub.status.idle":"2025-03-27T08:03:30.375989Z","shell.execute_reply.started":"2025-03-27T08:03:30.375839Z","shell.execute_reply":"2025-03-27T08:03:30.375855Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.377694Z","iopub.status.idle":"2025-03-27T08:03:30.378032Z","shell.execute_reply.started":"2025-03-27T08:03:30.377879Z","shell.execute_reply":"2025-03-27T08:03:30.377895Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.379455Z","iopub.status.idle":"2025-03-27T08:03:30.379761Z","shell.execute_reply.started":"2025-03-27T08:03:30.379614Z","shell.execute_reply":"2025-03-27T08:03:30.379629Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.380821Z","iopub.status.idle":"2025-03-27T08:03:30.38116Z","shell.execute_reply.started":"2025-03-27T08:03:30.380982Z","shell.execute_reply":"2025-03-27T08:03:30.380996Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.383141Z","iopub.status.idle":"2025-03-27T08:03:30.383519Z","shell.execute_reply.started":"2025-03-27T08:03:30.383352Z","shell.execute_reply":"2025-03-27T08:03:30.383369Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.384542Z","iopub.status.idle":"2025-03-27T08:03:30.384866Z","shell.execute_reply.started":"2025-03-27T08:03:30.384705Z","shell.execute_reply":"2025-03-27T08:03:30.384719Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.386325Z","iopub.status.idle":"2025-03-27T08:03:30.386634Z","shell.execute_reply.started":"2025-03-27T08:03:30.386482Z","shell.execute_reply":"2025-03-27T08:03:30.386496Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.387792Z","iopub.status.idle":"2025-03-27T08:03:30.388121Z","shell.execute_reply.started":"2025-03-27T08:03:30.38795Z","shell.execute_reply":"2025-03-27T08:03:30.387965Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"create_rsna_dataset(SAVE_FOLDER, \"configs/rsna_test.json\")","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.389416Z","iopub.status.idle":"2025-03-27T08:03:30.389723Z","shell.execute_reply.started":"2025-03-27T08:03:30.389574Z","shell.execute_reply":"2025-03-27T08:03:30.389588Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference_rsna_test.json\"","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.390759Z","iopub.status.idle":"2025-03-27T08:03:30.391165Z","shell.execute_reply.started":"2025-03-27T08:03:30.390973Z","shell.execute_reply":"2025-03-27T08:03:30.39099Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.392426Z","iopub.status.idle":"2025-03-27T08:03:30.392737Z","shell.execute_reply.started":"2025-03-27T08:03:30.392585Z","shell.execute_reply":"2025-03-27T08:03:30.392599Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.394168Z","iopub.status.idle":"2025-03-27T08:03:30.39447Z","shell.execute_reply.started":"2025-03-27T08:03:30.394325Z","shell.execute_reply":"2025-03-27T08:03:30.39434Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.395769Z","iopub.status.idle":"2025-03-27T08:03:30.396122Z","shell.execute_reply.started":"2025-03-27T08:03:30.395946Z","shell.execute_reply":"2025-03-27T08:03:30.395961Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.397691Z","iopub.status.idle":"2025-03-27T08:03:30.397998Z","shell.execute_reply.started":"2025-03-27T08:03:30.397849Z","shell.execute_reply":"2025-03-27T08:03:30.397865Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.401538Z","iopub.status.idle":"2025-03-27T08:03:30.402022Z","shell.execute_reply.started":"2025-03-27T08:03:30.401783Z","shell.execute_reply":"2025-03-27T08:03:30.401803Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.404193Z","iopub.status.idle":"2025-03-27T08:03:30.40466Z","shell.execute_reply.started":"2025-03-27T08:03:30.404422Z","shell.execute_reply":"2025-03-27T08:03:30.404443Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.405947Z","iopub.status.idle":"2025-03-27T08:03:30.406274Z","shell.execute_reply.started":"2025-03-27T08:03:30.406125Z","shell.execute_reply":"2025-03-27T08:03:30.40614Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"CONFIG_FILE = \"/kaggle/working/breast_density_classification/configs/inference_rsna_train.json\"","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.407334Z","iopub.status.idle":"2025-03-27T08:03:30.407734Z","shell.execute_reply.started":"2025-03-27T08:03:30.407526Z","shell.execute_reply":"2025-03-27T08:03:30.407546Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.409501Z","iopub.status.idle":"2025-03-27T08:03:30.409945Z","shell.execute_reply.started":"2025-03-27T08:03:30.40968Z","shell.execute_reply":"2025-03-27T08:03:30.409703Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/scripts","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.412196Z","iopub.status.idle":"2025-03-27T08:03:30.412911Z","shell.execute_reply.started":"2025-03-27T08:03:30.412624Z","shell.execute_reply":"2025-03-27T08:03:30.41265Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.413986Z","iopub.status.idle":"2025-03-27T08:03:30.414442Z","shell.execute_reply.started":"2025-03-27T08:03:30.414216Z","shell.execute_reply":"2025-03-27T08:03:30.414237Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"cd /kaggle/working/breast_density_classification/","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.415797Z","iopub.status.idle":"2025-03-27T08:03:30.416317Z","shell.execute_reply.started":"2025-03-27T08:03:30.416065Z","shell.execute_reply":"2025-03-27T08:03:30.41609Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\npreds = predict(parser)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.418149Z","iopub.status.idle":"2025-03-27T08:03:30.418592Z","shell.execute_reply.started":"2025-03-27T08:03:30.418361Z","shell.execute_reply":"2025-03-27T08:03:30.418383Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"np.save('/kaggle/working/preds_density.npy', preds)","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.419635Z","iopub.status.idle":"2025-03-27T08:03:30.420156Z","shell.execute_reply.started":"2025-03-27T08:03:30.419881Z","shell.execute_reply":"2025-03-27T08:03:30.419906Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.421799Z","iopub.status.idle":"2025-03-27T08:03:30.422267Z","shell.execute_reply.started":"2025-03-27T08:03:30.422016Z","shell.execute_reply":"2025-03-27T08:03:30.422038Z"},"_kg_hide-input":true,"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sns.countplot(x=preds.argmax(-1))\nplt.title('Predictions Repartition')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2025-03-27T08:03:30.423728Z","iopub.status.idle":"2025-03-27T08:03:30.424207Z","shell.execute_reply.started":"2025-03-27T08:03:30.423948Z","shell.execute_reply":"2025-03-27T08:03:30.42397Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.426752Z","iopub.status.idle":"2025-03-27T08:03:30.42724Z","shell.execute_reply.started":"2025-03-27T08:03:30.426987Z","shell.execute_reply":"2025-03-27T08:03:30.427008Z"},"trusted":true},"outputs":[],"execution_count":null},{"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":"2025-03-27T08:03:30.428469Z","iopub.status.idle":"2025-03-27T08:03:30.42892Z","shell.execute_reply.started":"2025-03-27T08:03:30.428678Z","shell.execute_reply":"2025-03-27T08:03:30.428701Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Done !","metadata":{}}]}