{"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":"This combines my previous notebook. Refer to those for missing code/function.\n- https://www.kaggle.com/code/hengck23/combine-dali-and-dicomsdl-for-reading-dicom-files\n- https://www.kaggle.com/code/hengck23/notebooke04a738685\n\nHere we show it is possible to perform inference for 2048-input image without \"time out\" or \"out of memory\" error for kaggle notebook. I have tested for up to 5 fold of efficientnet-b2 model. (inference time is about 7hr)  \n\nNote: it may not be necessarily to go up to 2048. it is a trade off: \"large model + small image\" or \"large image + small model\"\n","metadata":{}},{"cell_type":"code","source":"if 1:\n   !pip install /kaggle/input/nvidia-dali-wheel/nvidia_dali_nightly_cuda110-1.21.0.dev20221207-6701433-py3-none-manylinux2014_x86_64.whl\n   !pip install /kaggle/input/rsna-2022-whl/pylibjpeg-1.4.0-py3-none-any.whl \n   !pip install /kaggle/input/rsna-2022-whl/python_gdcm-3.0.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n   !pip install /kaggle/input/rsna-breast-mammography-00/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl\n\nprint('install ok!')\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-12-13T15:05:40.620995Z","iopub.execute_input":"2022-12-13T15:05:40.621649Z","iopub.status.idle":"2022-12-13T15:07:51.035553Z","shell.execute_reply.started":"2022-12-13T15:05:40.621526Z","shell.execute_reply":"2022-12-13T15:07:51.034244Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys, os\nsys.path.append('/kaggle/input/rsna-breast-mammography-00')\n\n\nimport pydicom\nimport pandas as pd\nimport numpy as np\nimport cv2\n\n\nfrom timeit import default_timer as timer\n#from tqdm.notebook import tqdm\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\nfrom glob import glob\nfrom sklearn import metrics\n\n\nimport torch\nfrom torch.utils.data.dataset import Dataset\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data.sampler import *\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.cuda.amp as amp\n#print( 'torch.cuda.device_count() = %d'%torch.cuda.device_count())\n#print( 'torch.cuda.get_device_properties() = %s' % str(torch.cuda.get_device_properties(0))[21:])\n\nimport timm\nprint('timm',timm.__version__)\n#print(timm.__file__)\nfrom timm.models.resnet import *\nfrom timm.models.efficientnet import *\n\nfrom nb_dataset_v1 import *\n\n\n\nprint('import ok!\\n')","metadata":{"execution":{"iopub.status.busy":"2022-12-13T15:07:51.037948Z","iopub.execute_input":"2022-12-13T15:07:51.039516Z","iopub.status.idle":"2022-12-13T15:07:55.588553Z","shell.execute_reply.started":"2022-12-13T15:07:51.039471Z","shell.execute_reply":"2022-12-13T15:07:55.586401Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nimage_size = 2048\nthreshold = 0.3877551\nmode = 'submit-dicom'  #local-image  #submit-dicom\n\nif 'local' in mode:\n    # csv_file = '/kaggle/input/rsna-breast-cancer-detection/train.csv'\n    csv_file = '/kaggle/input/rsna-breast-mammography-00/valid_df.fold0.csv'\n    dcm_dir  = '/kaggle/input/rsna-breast-cancer-detection/train_images'\n\nif 'submit' in mode:\n    csv_file = '/kaggle/input/rsna-breast-cancer-detection/test.csv'\n    dcm_dir  = '/kaggle/input/rsna-breast-cancer-detection/test_images'\n\n'''\n1.2.840.10008.1.2.4.70 = JPEG Lossless, Nonhierarchical, First- Order Prediction (Processes 14)\n1.2.840.10008.1.2.4.90 = JPEG 2000 Image Compression (Lossless Only)\n'''\ntest_df = pd.read_csv(csv_file)\nmachine_id_to_transfer = make_transfer_syntax_uid(test_df, dcm_dir)\n\ntest_df.loc[:, 'i'] = np.arange(len(test_df))\ntest_df.loc[:, 'TransferSyntaxUID'] = test_df.machine_id.map(machine_id_to_transfer)\nif 'local' in mode:\n    test_df.loc[:, 'prediction_id'] = test_df.patient_id.astype(str) + '_' + test_df.laterality\n    if 'dicom' in mode:\n    #if 0:\n        test_id = [\n            #  1.2.840.10008.1.2.4.70  count(14)\n            65, 127, 152, 272, 282, 308, 477, 505, 2989, 3542, 7780, 9014, 11094, 11937,\n            #  1.2.840.10008.1.2.4.90  count(26)\n            30, 36, 90, 111, 122, 158, 204, 289, 299, 399, 425, 454, 826, 1703, 1759, 2346,\n            3021, 4340, 4824, 5059, 5769, 6654, 6658, 7053, 7493, 14292\n        ]\n        test_df = test_df[test_df.patient_id.isin(test_id)].reset_index(drop=True)\nprint(test_df.shape)\nprint(test_df)\n\n\n\nclass RsnaDataset(Dataset):\n    def __init__(self, df):\n        patient_id =  sorted(df.patient_id.unique())\n        self.patient_id = patient_id\n        self.length = len(patient_id)\n        self.df = df\n\n    def __len__(self):\n        return self.length\n\n    def __getitem__(self, index):\n        patient_id = self.patient_id[index]\n        df = self.df[self.df.patient_id == patient_id].reset_index(drop=True)\n\n        if df.iloc[0].TransferSyntaxUID=='1.2.840.10008.1.2.4.90':\n            image = read_image_with_dali(df, dcm_dir, image_size)\n        else:\n            image = read_image_with_dicomsdl(df, dcm_dir, image_size)\n\n        r = {}\n        r['index'] = index\n        r['df'] = df\n        r['image'] = torch.from_numpy(image)\n        return r\n\ntensor_key = ['image']\ndef null_collate(batch):\n    d = {}\n    key = batch[0].keys()\n    for k in key:\n        d[k] = [b[k] for b in batch]\n    d['image'] = torch.cat(d['image']).unsqueeze(1)\n    return d","metadata":{"execution":{"iopub.status.busy":"2022-12-13T15:07:55.590659Z","iopub.execute_input":"2022-12-13T15:07:55.591613Z","iopub.status.idle":"2022-12-13T15:07:56.478497Z","shell.execute_reply.started":"2022-12-13T15:07:55.591569Z","shell.execute_reply":"2022-12-13T15:07:56.477472Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nclass RGB(nn.Module):\n    IMAGE_RGB_MEAN = [0.5, 0.5, 0.5] #[0.485, 0.456, 0.406]\n    IMAGE_RGB_STD  = [0.5, 0.5, 0.5] #[0.229, 0.224, 0.225]\n\n    def __init__(self, ):\n        super(RGB, self).__init__()\n        self.register_buffer('mean', torch.zeros(1, 3, 1, 1))\n        self.register_buffer('std', torch.ones(1, 3, 1, 1))\n        self.mean.data = torch.FloatTensor(self.IMAGE_RGB_MEAN).view(self.mean.shape)\n        self.std.data = torch.FloatTensor(self.IMAGE_RGB_STD).view(self.std.shape)\n\n    def forward(self, x):\n        x = (x - self.mean) / self.std\n        return x\n\n\nclass EffB2Net(nn.Module):\n    def __init__(self,size=image_size):\n        super(EffB2Net, self).__init__()\n        self.size = size\n        self.rgb = RGB()\n        self.encoder = efficientnet_b2(pretrained=False)\n        self.cancer  = nn.Linear(1408,1)\n\n    def forward(self, batch):\n        x = batch['image']\n        # if (x.shape[2],x.shape[3])!=(self.size,self.size):\n        #     x = F.interpolate(x,size=self.size,mode='bilinear',align_corners=False) #,antialias=True)\n\n        x = x.expand(-1,3,-1,-1)\n        x = self.rgb(x)\n\n        #------\n        e = self.encoder\n        x = e.forward_features(x)\n        x = F.adaptive_avg_pool2d(x,1)\n        x = torch.flatten(x,1,3)\n        cancer = self.cancer(x)\n\n        cancer = cancer.reshape(-1)\n        cancer = torch.sigmoid(cancer.float())\n        return cancer\n","metadata":{"execution":{"iopub.status.busy":"2022-12-13T15:07:56.480874Z","iopub.execute_input":"2022-12-13T15:07:56.482476Z","iopub.status.idle":"2022-12-13T15:07:56.492918Z","shell.execute_reply.started":"2022-12-13T15:07:56.482436Z","shell.execute_reply":"2022-12-13T15:07:56.49178Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\ndef run_submit(): \n    model = [\n        [EffB2Net, 2048, '/kaggle/input/rsna-breast-mammography-weight-01/efficientnet_b2-2048-fold0-swa.model.pth'],\n        [EffB2Net, 2048, '/kaggle/input/rsna-breast-mammography-weight-01/efficientnet_b2-2048-fold1-swa.model.pth'],\n    ]\n    num_net = len(model)\n    print(f'num_net={num_net}')\n\n    net = []\n    for i in range(num_net):\n        Net, size, checkpoint = model[i]\n        n = Net(size)\n        f = torch.load(checkpoint, map_location=lambda storage, loc: storage)\n        n.load_state_dict(f['state_dict'], strict=True)  # True\n        n.cuda()\n        n.eval()\n        net.append(n)\n\n    #----\n    test_dataset = RsnaDataset(test_df)\n    test_loader = DataLoader(\n        test_dataset,\n        sampler = SequentialSampler(test_dataset),\n        batch_size  = 1,\n        drop_last   = False,\n        num_workers = 0,\n        pin_memory  = False,\n        collate_fn = null_collate,\n    )\n\n    #----\n    if 1:\n        result = {\n            'i':[],\n            'probability':[],\n        }\n        test_num = 0\n\n        start_timer = timer()\n        for t, batch in enumerate(test_loader):\n            batch_size = len(batch['index'])\n            batch['image'] = batch['image'].cuda()\n            #print(t, batch['image'].shape)\n\n            p = 0\n            count = 0\n            with torch.no_grad():\n                with amp.autocast(enabled=True):\n                    for i in range(num_net):\n                        p += net[i](batch)  # net(input)#\n                        count += 1\n\n                        # TTA\n                        batch['image'] = torch.flip(batch['image'], dims=[3, ])\n                        p += net[i](batch)\n                        count += 1\n\n            p = p / count\n            result['probability'].append(p.float().data.cpu().numpy())\n            result['i'].append(pd.concat(batch['df'])['i'].values)\n            test_num += batch_size\n            print('\\r %8d / %d  %s' % (test_num, len(test_dataset), time_to_str(timer() - start_timer, 'sec')), end='', flush=True)\n        print('')\n\n        #---\n        probability = np.concatenate(result['probability'])\n        i = np.concatenate(result['i'])\n        argsort = np.argsort(i)\n        i = i[argsort]\n        probability = probability[argsort]\n        np.save('probability.npy',probability)\n        #exit(0)\n\n    #----\n    probability = np.load('probability.npy')\n    print('probability', probability.shape)\n    print('')\n\n    submit_df = pd.DataFrame({'prediction_id':test_df.prediction_id})\n    submit_df.loc[:, 'cancer'] = probability\n    submit_df = submit_df.groupby('prediction_id').mean()\n    submit_df.loc[:, 'cancer'] = (submit_df.cancer.values>threshold).astype(np.float32)\n\n    submit_df = submit_df.sort_index()\n    submit_df.to_csv('submission.csv',index=True)\n    print('submit_df',submit_df)\n    print('')\n\n    if 'local' in mode: \n\n        # https://www.kaggle.com/code/sohier/probabilistic-f-score\n        def pfbeta(labels, predictions, beta=1):\n            y_true_count = 0\n            ctp = 0\n            cfp = 0\n\n            for idx in range(len(labels)):\n                prediction = min(max(predictions[idx], 0), 1)\n                if (labels[idx]):\n                    y_true_count += 1\n                    ctp += prediction\n                else:\n                    cfp += prediction\n\n            beta_squared = beta * beta\n            c_precision = ctp / (ctp + cfp)\n            c_recall = ctp / y_true_count\n            if (c_precision > 0 and c_recall > 0):\n                result = (1 + beta_squared) * (c_precision * c_recall) / (beta_squared * c_precision + c_recall)\n                return result\n            else:\n                return 0\n\n        truth_df = test_df[['prediction_id', 'cancer']].groupby('prediction_id').mean()\n        truth_df = truth_df.sort_index()\n        print('truth_df', truth_df)\n        print('')\n\n        truth = truth_df.cancer.values\n        predict = submit_df.cancer.values\n\n        lb_score = pfbeta(truth, predict)\n        print('lb_score', lb_score)\n\n        auc = metrics.roc_auc_score(truth, predict)\n        print('auc', auc)\n\n        #from kaggle_rsna_v1 import search_pfbeta\n        #search_pfbeta(truth_df.cancer.values, submit_df.cancer.values)\n\n\n\nrun_submit()","metadata":{"execution":{"iopub.status.busy":"2022-12-13T15:07:56.49583Z","iopub.execute_input":"2022-12-13T15:07:56.496572Z","iopub.status.idle":"2022-12-13T16:28:22.629677Z","shell.execute_reply.started":"2022-12-13T15:07:56.496503Z","shell.execute_reply":"2022-12-13T16:28:22.628444Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\nusing fold-0 model only\n\nsmall sample test (40 patient_id, 178 image_id)\n=================================================\nnum_net=1\n       40 / 40   1 min 24 sec\nprobability (178,)\n\nlb_score 0.5806451612903226\nauc 0.7045454545454546\n'''\n\n'''\nlarger sample test (2383 patient_id, 10935 image_id)\n=================================================\n\nnum_net=1\n     2383 / 2383  80 min 22 sec\nprobability (10935,)\n\n\nlb_score 0.36994219653179194\nauc 0.648519120156108\n'''","metadata":{"execution":{"iopub.status.busy":"2022-12-13T16:28:22.632026Z","iopub.execute_input":"2022-12-13T16:28:22.632462Z","iopub.status.idle":"2022-12-13T16:28:22.640807Z","shell.execute_reply.started":"2022-12-13T16:28:22.632401Z","shell.execute_reply":"2022-12-13T16:28:22.639602Z"},"trusted":true},"execution_count":null,"outputs":[]}]}