{"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":"# Download packages for offline implement in kaggle","metadata":{}},{"cell_type":"code","source":"'''Required pakages for read jpeg2000 format images'''\n\n# 1. gdcm : using gdcm-conda-install package from kaggle\n!cp /kaggle/input/gdcm-conda-install/gdcm.tar .\n!tar -xvzf gdcm.tar\n!conda install --offline ./gdcm/gdcm-2.8.9-py37h71b2a6d_0.tar.bz2\n!rm -rf ./gdcm.tar\nimport gdcm\n\n# 2. pylibjpeg : adding dataset downloaded from https://github.com/pydicom/pylibjpeg\nimport sys\nsys.path.append('../input/pylibjpeg/pylibjpeg-master')\nimport pylibjpeg","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-01-11T12:33:15.381893Z","iopub.execute_input":"2023-01-11T12:33:15.382769Z","iopub.status.idle":"2023-01-11T12:33:35.255338Z","shell.execute_reply.started":"2023-01-11T12:33:15.382657Z","shell.execute_reply":"2023-01-11T12:33:35.25418Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Packages","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pydicom\nimport matplotlib.pyplot as plt\nimport os\nimport cv2\n\nimport torch\nfrom torch.optim import lr_scheduler\nimport torch.utils.data as td\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torchvision import datasets, models\nfrom torch import autograd\n# from torchsummary import summary","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:33:35.258447Z","iopub.execute_input":"2023-01-11T12:33:35.259426Z","iopub.status.idle":"2023-01-11T12:33:37.229769Z","shell.execute_reply.started":"2023-01-11T12:33:35.259384Z","shell.execute_reply":"2023-01-11T12:33:37.228804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  ROI detection for classification accuracy","metadata":{}},{"cell_type":"code","source":"'''roi detection with custom image processing'''\ndef roi_detection(array): \n    \n    # Otsu's thresholding after Gaussian filtering\n    '''refrerenced from https://www.kaggle.com/code/snnclsr/roi-extraction-using-opencv '''\n    blur = cv2.GaussianBlur((array*255).astype('uint8'), (5, 5), 0)\n    _, breast_mask = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)\n    \n    if array.mean() < 0.5: \n        breast_mask = 255 - breast_mask \n    \n    cnts = []\n    cnt, label = cv2.connectedComponents((255-breast_mask))\n    for l in range(1, cnt+1):\n        count = np.sum(label == l)\n        cnts.append(count)\n    maxlabel = np.argmax(cnts) + 1\n    breast_mask[label != maxlabel] = 255\n       \n    coord_y, coord_x = np.where(breast_mask == 0)\n    roi = array[coord_y.min():coord_y.max(), coord_x.min():coord_x.max()]\n    \n    return roi","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:33:37.231189Z","iopub.execute_input":"2023-01-11T12:33:37.2319Z","iopub.status.idle":"2023-01-11T12:33:37.243053Z","shell.execute_reply.started":"2023-01-11T12:33:37.231861Z","shell.execute_reply":"2023-01-11T12:33:37.242074Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Define dataset","metadata":{}},{"cell_type":"code","source":"## get dataset\nclass Dataset_test(td.Dataset):\n    def __init__(self, root_dir, plist, image_size = (2048, 2048)):\n        super(Dataset_test, self).__init__()\n        self.image_size = image_size\n        self.root_dir = root_dir\n        self.plist = plist\n        \n        self.files = []\n        for p in self.plist:\n            c_imlist = os.listdir(os.path.join(self.root_dir, p))\n            for im in c_imlist:\n                self.files.append(os.path.join(root_dir, p, im))\n                \n        \n    def __len__(self):\n        return len(self.files)\n    \n    def __getitem__(self, index):\n\n        filename = self.files[index]\n        dicom = pydicom.dcmread(filename)\n        array = dicom.pixel_array\n        \n        '''norm 0 to 1'''\n        array_float = array.astype('float') / array.max()\n        \n        '''ROI extraction'''\n#         array_float = roi_detection(array_float)\n        ## resize\n        if (array_float.shape[0] != self.image_size[0]) or (array_float.shape[1] != self.image_size[1]):\n            array_float = cv2.resize(array_float, self.image_size, interpolation = cv2.INTER_CUBIC)\n        \n        array_float = roi_detection(array_float)\n        array_float = cv2.resize(array_float, self.image_size, interpolation = cv2.INTER_CUBIC)\n        \n        '''image resize ?'''\n        array_float = np.reshape(array_float, ((1,) + array_float.shape))\n        \n        return array_float, filename","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:33:37.245713Z","iopub.execute_input":"2023-01-11T12:33:37.246192Z","iopub.status.idle":"2023-01-11T12:33:37.256359Z","shell.execute_reply.started":"2023-01-11T12:33:37.246156Z","shell.execute_reply":"2023-01-11T12:33:37.255202Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# get trained model","metadata":{}},{"cell_type":"code","source":"model = torchvision.models.efficientnet_b0(n_classes = 1)\nmodel.features[0][0] = nn.Conv2d(1, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\nmodel.classifier[1] = nn.Linear(in_features=1280, out_features=1, bias=True)\nmodel = model.cuda()\n\n'''trained with rsna mammography dataset'''\nsaved_pth = torch.load('/kaggle/input/rsna-sample-pth/230103_norm01_roicrop_resize256_10000image_64batch_efficientb0_BCELoss_scheduler_Yes_1th_epoch_0.12dice_0.9786iou.pth', map_location=torch.device('cpu'))\nmodel.load_state_dict(saved_pth['model_state_dict'])","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:36:14.974601Z","iopub.execute_input":"2023-01-11T12:36:14.975026Z","iopub.status.idle":"2023-01-11T12:36:15.755723Z","shell.execute_reply.started":"2023-01-11T12:36:14.97499Z","shell.execute_reply":"2023-01-11T12:36:15.754739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Get test dataset","metadata":{}},{"cell_type":"code","source":"image_size = (256, 256)\n\ntest_root = '../input/rsna-breast-cancer-detection/test_images'\ntest_plist = sorted(os.listdir(test_root))\n\ntestset = Dataset_test(test_root, test_plist, image_size = image_size)\n\nprint(testset.__len__())\ntest_loader = td.DataLoader(testset, batch_size = 1, shuffle = False)","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:36:16.703386Z","iopub.execute_input":"2023-01-11T12:36:16.703763Z","iopub.status.idle":"2023-01-11T12:36:16.715228Z","shell.execute_reply.started":"2023-01-11T12:36:16.70372Z","shell.execute_reply":"2023-01-11T12:36:16.713953Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split trained model as feature extractor and classifier for plot Grad-CAM","metadata":{}},{"cell_type":"code","source":"model.eval()\nmodel_feature = nn.Sequential(*list(model.children())[:-2])\nmodel_classifier = nn.Sequential(*list(model.children())[-1:]) \nmodel_classifier","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:36:17.616455Z","iopub.execute_input":"2023-01-11T12:36:17.617154Z","iopub.status.idle":"2023-01-11T12:36:17.626252Z","shell.execute_reply.started":"2023-01-11T12:36:17.617117Z","shell.execute_reply":"2023-01-11T12:36:17.62505Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Calculate Grad-CAM","metadata":{}},{"cell_type":"code","source":"for img, name in test_loader:\n    \n    img = img.cuda()\n    # get feature from last conv layer\n    feature = model_feature(img.float())\n    \n    # get prediction from sigmoid output (single class)\n    avg_pooled = F.adaptive_avg_pool2d(feature, (1, 1)).flatten()\n    predict = model_classifier(avg_pooled)\n    predict = torch.sigmoid(predict)\n    print(predict)\n    \n    # cal grads using pytorch autograd method\n    grads = autograd.grad(predict, feature)\n    grads = grads[0].squeeze()\n    \n    # dot product gradient and feature\n    feature = feature.detach().squeeze()\n    for i in range(grads.shape[0]):\n        feature[i, :, :] *= grads[i, :, :]\n        #feature[i, :, :] *= torch.mean(grads[i, :, :])\n    \n    # sum features\n    for i in range(grads.shape[0]):\n        if i == 0: \n            feature_sum = feature[i, :, :]\n        else:\n            feature_sum += feature[i, :, :] \n    \n    # get grad cam by relu activation\n    feature_sum += 0.003 # adding leak value to prevent the result going to zero-array after relu\n    gradcam = F.relu(feature_sum)\n    \n    # plot grad cam\n    gradcam_array = gradcam.detach().cpu().numpy()\n    img_array = img.detach().cpu().numpy().squeeze()\n    gradcam_resized = cv2.resize(gradcam_array, img_array.shape, interpolation = cv2.INTER_CUBIC)\n    print(gradcam_array.max())\n\n    fig, axe = plt.subplots(1,3, figsize = (20,15))\n    axe[0].imshow(gradcam_resized, cmap = 'jet')\n    axe[1].imshow(img_array, cmap = 'gray')\n    axe[1].set_title(name)\n    axe[2].imshow(img_array, cmap = 'gray')\n    axe[2].imshow(gradcam_resized, cmap = 'jet', alpha = 0.6)\n    axe[2].set_title(round(predict.item()))\n    plt.show()\n    \n#     break","metadata":{"execution":{"iopub.status.busy":"2023-01-11T12:36:18.43193Z","iopub.execute_input":"2023-01-11T12:36:18.432591Z","iopub.status.idle":"2023-01-11T12:36:29.617992Z","shell.execute_reply.started":"2023-01-11T12:36:18.432557Z","shell.execute_reply":"2023-01-11T12:36:29.617058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}