{"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":"code","source":"#https://www.kaggle.com/richardepstein/load-gdcm-in-notebook-without-internet\n!cp ../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\n\n'''\n> import sys\n> sys.version\n'3.7.10 | packaged by conda-forge | (default, Feb 19 2021, 16:07:37) \\n[GCC 9.3.0]'\n\n'''","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:57:57.60572Z","iopub.execute_input":"2021-08-09T21:57:57.606147Z","iopub.status.idle":"2021-08-09T21:58:22.61415Z","shell.execute_reply.started":"2021-08-09T21:57:57.606038Z","shell.execute_reply":"2021-08-09T21:58:22.613238Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir  = '/kaggle/input/siim-covid19-detection'\nmodel_dir = '../input/finalsiimcovid2021/trained_model'\n\n\n\n# common ---\nimport numpy as np\nimport pandas as pd\nimport glob\nimport sys\nimport cv2\n\nfrom timeit import default_timer as timer\n\nimport collections\nfrom collections import defaultdict\n\n\n# pytorch ---\nimport torch\nfrom torch.utils.data.dataset import Dataset\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data.sampler import *\n\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.optim as optim\nfrom torch.nn.parallel.data_parallel import data_parallel\n\nfrom torch.nn.utils.rnn import *\n\n\n#-- siim ------\nimport pydicom \nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\n\n\n#-- other ------\n#https://www.kaggle.com/kozodoi/local-installation-for-timm-pytorch-image-models\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nimport timm\nprint('timm', timm.__version__)\n\n#https://www.kaggle.com/shonenkov/wbf-approach-for-ensemble\nsys.path.append('../input/weightedboxesfusion')\nfrom ensemble_boxes import *\n\n#https://www.kaggle.com/shonenkov/omegaconf\nsys.path.append('../input/omegaconf')\nimport omegaconf\n\n\n#-- helper -- \ndef time_to_str(t, mode='min'):\n    if mode=='min':\n        t  = int(t)/60\n        hr = t//60\n        min = t%60\n        return '%2d hr %02d min'%(hr,min)\n\n    elif mode=='sec':\n        t   = int(t)\n        min = t//60\n        sec = t%60\n        return '%2d min %02d sec'%(min,sec)\n\n    else:\n        raise NotImplementedError","metadata":{"_uuid":"b847cc23-9cfe-4fb2-809c-33533e8682d7","_cell_guid":"e90c7af8-8172-4b21-9676-765d9c831b42","collapsed":false,"jupyter":{"outputs_hidden":false},"execution":{"iopub.status.busy":"2021-08-09T21:58:22.615878Z","iopub.execute_input":"2021-08-09T21:58:22.616239Z","iopub.status.idle":"2021-08-09T21:58:25.836586Z","shell.execute_reply.started":"2021-08-09T21:58:22.616201Z","shell.execute_reply":"2021-08-09T21:58:25.835064Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#dataset.py\n\ndef dicom_to_image(dicom, voi_lut=True, fix_monochrome=True):\n\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.max(data) - data\n\n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    return data\n\n\n \ndcm_size = 640\n\ndcm_file = glob.glob(data_dir + '/test/**/*dcm', recursive=True)\ndf_meta = pd.DataFrame({'dcm_file': dcm_file})\ndf_meta['image_id' ] = df_meta.dcm_file.map(lambda x: x.split('/')[-1].replace('.dcm', '') + '_image')\ndf_meta['study_id' ] = df_meta.dcm_file.map(lambda x: x.split('/')[-3].replace('.dcm', '') + '_study')\ndf_meta.loc[:, 'width' ] = 0\ndf_meta.loc[:, 'height'] = 0\n\n\n\nclass SiimDataset(Dataset):\n    def __init__(self, df=df_meta):\n        super().__init__()\n        self.df = df\n        self.length = len(df)\n\n    def __len__(self):\n        return self.length\n\n    def __getitem__(self, index):\n        d = self.df.iloc[index]\n\n        dicom = pydicom.read_file(d.dcm_file)\n        image = dicom_to_image(dicom, voi_lut=True)\n        height,width = image.shape\n\n        self.df.loc[index,'width' ] = width\n        self.df.loc[index,'height'] = height\n\n        image = cv2.resize(image, dsize=(dcm_size, dcm_size), interpolation=cv2.INTER_AREA)\n\n        #---\n        d = self.df.iloc[index] #reload for width,height\n        r = {\n            'index': index,\n            'd': d,\n            'image': image,\n        }\n        return r\n\n\ndef null_collate(batch):\n    collate = defaultdict(list)\n    for b, r in enumerate(batch):\n        for k, v in r.items():\n            collate[k].append(v)\n\n    # ---\n    image = np.stack(collate['image'])\n    image = image.reshape(-1, 1, dcm_size, dcm_size).repeat(3, 1)\n    image = np.ascontiguousarray(image)\n    image = image.astype(np.float32) / 255\n    collate['image'] = torch.from_numpy(image)\n\n    return collate\n\n","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:58:25.839826Z","iopub.execute_input":"2021-08-09T21:58:25.84009Z","iopub.status.idle":"2021-08-09T21:58:30.758644Z","shell.execute_reply.started":"2021-08-09T21:58:25.840061Z","shell.execute_reply":"2021-08-09T21:58:30.757816Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#study model\n\nfrom timm.models.efficientnet import *\n\nclass StudyNet(nn.Module):\n    def __init__(self):\n        super(StudyNet, self).__init__()\n\n        e = tf_efficientnetv2_m_in21ft1k(pretrained=False)\n        self.b0 = nn.Sequential(\n            e.conv_stem,\n            e.bn1,\n            e.act1,\n        )\n        self.b1 = e.blocks[0]\n        self.b2 = e.blocks[1]\n        self.b3 = e.blocks[2]\n        self.b4 = e.blocks[3]\n        self.b5 = e.blocks[4]\n        self.b6 = e.blocks[5]\n        self.b7 = e.blocks[6]\n        self.b8 = nn.Sequential(\n            e.conv_head, #384, 1536\n            e.bn2,\n            e.act2,\n        )\n        self.logit = nn.Linear(1280, 4)\n\n        self.mask = nn.Sequential(\n            nn.Conv2d(176, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 128, kernel_size=3, padding=1),\n            nn.BatchNorm2d(128),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(128, 1, kernel_size=1, padding=0),\n        )\n\n    @torch.cuda.amp.autocast()\n    def forward(self, image):\n        batch_size = len(image)\n        x = 2*image-1     # ; print('input ',   x.shape)\n\n        x = self.b0(x) #; print (x.shape)  # torch.Size([2, 40, 256, 256])\n        x = self.b1(x) #; print (x.shape)  # torch.Size([2, 24, 256, 256])\n        x = self.b2(x) #; print (x.shape)  # torch.Size([2, 32, 128, 128])\n        x = self.b3(x) #; print (x.shape)  # torch.Size([2, 48, 64, 64])\n        x = self.b4(x) #; print (x.shape)  # torch.Size([2, 96, 32, 32])\n        x = self.b5(x) #; print (x.shape)  # torch.Size([2, 136, 32, 32])\n        #------------\n        mask = self.mask(x)\n        #-------------\n        x = self.b6(x) #; print (x.shape)  # torch.Size([2, 232, 16, 16])\n        x = self.b7(x) #; print (x.shape)  # torch.Size([2, 384, 16, 16])\n        x = self.b8(x) #; print (x.shape)  # torch.Size([2, 1536, 16, 16])\n        x = F.adaptive_avg_pool2d(x,1).reshape(batch_size,-1)\n        #x = F.dropout(x, 0.5, training=self.training)\n        logit = self.logit(x)\n\n        return logit, mask\n\n    \n#image model\nsys.path.append('../input/finalsiimcovid2021') \nfrom image_model.model import ImageNet\nfrom image_model.model import *","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:58:30.760153Z","iopub.execute_input":"2021-08-09T21:58:30.76047Z","iopub.status.idle":"2021-08-09T21:58:30.895547Z","shell.execute_reply.started":"2021-08-09T21:58:30.760433Z","shell.execute_reply":"2021-08-09T21:58:30.894665Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n#load study model ------------------------------------------------------------------------------\nstudy_net_checkpoint=[\n    model_dir + '/study/eff2m-512-lovasz/fold0_00005600_model.pth',\n    model_dir + '/study/eff2m-512-lovasz/fold1_00006600_model.pth',\n    model_dir + '/study/eff2m-512-lovasz/fold2_00006000_model.pth',\n    model_dir + '/study/eff2m-512-lovasz/fold3_00005800_model.pth',\n    model_dir + '/study/eff2m-512-lovasz/fold4_00006800_model.pth',\n]\n\nstudy_net = []\nfor i in range(5):\n    net = StudyNet()\n    net.load_state_dict(torch.load(study_net_checkpoint[i])['state_dict'], strict=True)\n    study_net.append(net)\nprint('load study_net ok!')\n\n\n\n\n#load image model ------------------------------------------------------------------------------\n\nimage_net_checkpoint=[\n    model_dir + '/image/effdet-d3-640-s3.0/fold0_0000-swa_model.pth',\n    model_dir + '/image/effdet-d3-640-s3.0/fold1_0000-swa_model.pth',\n    model_dir + '/image/effdet-d3-640-s3.0/fold2_0000-swa_model.pth',\n    model_dir + '/image/effdet-d3-640-s3.0/fold3_0000-swa_model.pth',\n    model_dir + '/image/effdet-d3-640-s3.0/fold4_0000-swa_model.pth',\n]\nimage_net = []\nfor i in range(5):\n    net = ImageNet()\n    net.load_state_dict(torch.load(image_net_checkpoint[i])['state_dict'], strict=True)\n    image_net.append(net)\nprint('load image_net ok!')\n\n\n \n    \n ","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:58:30.896781Z","iopub.execute_input":"2021-08-09T21:58:30.897114Z","iopub.status.idle":"2021-08-09T21:58:58.837423Z","shell.execute_reply.started":"2021-08-09T21:58:30.897078Z","shell.execute_reply":"2021-08-09T21:58:58.8365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#csv processing\n\ndef probability_to_df_study(df, probability):\n    df = df[:len(probability)] #<debug>\n\n    df_study = pd.DataFrame()\n    df_study.loc[:,'id'] = df.study_id\n\n    for i, col in enumerate(['negative','typical','indeterminate','atypical']):\n        df_study.loc[:,col]=probability[:,i]\n\n    df_study = df_study.groupby('id', as_index=False).mean()\n    df_study.loc[:, 'PredictionString'] = \\\n           'negative '      + df_study.negative.apply(lambda x: '%0.6f'%x)      + ' 0 0 1 1' \\\n        + ' typical '       + df_study.typical.apply(lambda x: '%0.6f'%x)       + ' 0 0 1 1' \\\n        + ' indeterminate ' + df_study.indeterminate.apply(lambda x: '%0.6f'%x) + ' 0 0 1 1' \\\n        + ' atypical '      + df_study.atypical.apply(lambda x: '%0.6f'%x)      + ' 0 0 1 1'\n\n    df_study = df_study[['id','PredictionString']]\n    return df_study\n\n\n\ndef detection_to_df_image(df, detection):\n    df = df[:len(detection)] #<debug>\n\n    df_image = pd.DataFrame()\n    df_image.loc[:,'id'] = df.image_id\n    #df_image.loc[:, 'PredictionString']=''\n\n    predict_string = []\n    for i,det in enumerate(detection):\n        d = df.iloc[i]\n\n        s = ''\n        for x0, y0, x1, y1, c in det:\n            x0 = int(x0*d.width )\n            y0 = int(y0*d.height)\n            x1 = int(x1*d.width )\n            y1 = int(y1*d.height)\n            s += ' opacity %0.5f %4d %4d %4d %4d'%(c,x0,y0,x1,y1)\n        predict_string.append(s)\n\n    df_image.loc[:, 'PredictionString'] = predict_string\n    #df_image = df_image[['id','PredictionString']]\n    return df_image\n\ndef make_fake_opacity_prediction(df_image, df_study, df_meta):\n\n    predict_string=[]\n    for i,d in df_image.iterrows():\n        #if d.PredictionString == 'none 1 0 0 1 1': continue\n        #print(d.PredictionString)\n        p = d.PredictionString\n\n        study_id = df_meta[df_meta.image_id==d.id].study_id.values[0]\n        q = df_study[df_study.id==study_id].PredictionString.values[0]\n        q = q[:25].replace('negative','none')\n        p = q + ' ' + p\n        predict_string.append(p)\n\n    df_image.loc[:,'PredictionString']=predict_string\n    return df_image","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:58:58.838773Z","iopub.execute_input":"2021-08-09T21:58:58.839147Z","iopub.status.idle":"2021-08-09T21:58:58.853709Z","shell.execute_reply.started":"2021-08-09T21:58:58.839082Z","shell.execute_reply":"2021-08-09T21:58:58.851819Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#inference and make submission csv here!!!!\n\ndef process_one_batch_for_image(image_640):\n    image_size = 640\n\n    detection = []\n    for i in range(5):  # <debug>\n\n        with torch.no_grad():\n            probability_flat = []\n            box_flat = []\n\n            logit, delta = image_net[i](image)\n            probability, box = infer_prediction(logit, delta, image_net[i].anchor)\n            p = pyramid_to_flat(probability)\n            b = pyramid_to_flat(box)\n            probability_flat.append(p)\n            box_flat.append(b)\n\n            # --------------------------------------------------\n            # flip in tta\n            logit, delta = image_net[i](torch.flip(image, dims=(3,)))\n            probability, box = infer_prediction(logit, delta, net.anchor)\n            p = pyramid_to_flat(probability)\n            b = pyramid_to_flat(box)\n            b[..., [0, 2]] = image_size - b[..., [2, 0]]\n            probability_flat.append(p)\n            box_flat.append(b)\n\n            #'scale+crop' in tta:\n            s = int(0.10 * image_size)\n            m = F.interpolate(image, size=(image_size + 2 * s, image_size + 2 * s), mode='bilinear', align_corners=False)\n            m = m[:, :, s:s + image_size, s:s + image_size]\n\n            logit, delta = image_net[i](m)\n            probability, box = infer_prediction(logit, delta, net.anchor)\n            p = pyramid_to_flat(probability)\n            b = pyramid_to_flat(box)\n            b[..., :4] = b[..., :4] + s\n            b[..., :4] = b[..., :4] / (image_size + 2 * s) * image_size\n            probability_flat.append(p)\n            box_flat.append(b)\n\n            # --------------------------------------------------\n            probability_flat = torch.cat(probability_flat, 1)\n            box_flat = torch.cat(box_flat, 1)\n            det = do_non_max_suppression(\n                probability_flat,\n                box_flat,\n                nms_objectness_threshold=0.01,\n                nms_iou_threshold=0.5,\n                nms_pre_max_num=1000,\n                nms_post_max_num=50,\n            )\n            #box normalised to 0,1 in do_non_max_suppression !!!\n            detection.append(det)\n\n    #------------\n    batch_size = len(image_640)\n    num_model = len(detection)\n\n    ensemble = []\n    for b in range(batch_size):\n        box   = []\n        score = []\n        label = []\n        for i in range(num_model):\n            det = detection[i][b]\n            x = det[:, :4]\n            x = np.clip(x, 0, 1)  # clip to image size\n            s = det[:, 4]\n            l = [1] * len(s)\n            box.append(x.tolist())\n            score.append(s.tolist())\n            label.append(l)\n\n        box, score, label = weighted_boxes_fusion(box, score, label, weights=None, iou_thr=0.60)\n        # box, score, label = nms(box, score, label, weights=None,iou_thr=0.60)\n\n        score = score.reshape(-1, 1)\n        e = np.concatenate([box, score], 1)[:100]\n        ensemble.append(e)\n\n    return ensemble\n\n\n\ndef process_one_batch_for_study(image_512, image_640):\n    ensemble = 0\n\n    # for i in range(5):\n    for i in range(5):  # <debug>\n        with torch.no_grad():\n            prob = []\n\n            logit, _ = study_net[i](image_512)\n            prob.append(F.softmax(logit, -1))\n\n            # ----\n            # 'flip' in tta:\n            logit, _ = study_net[i](torch.flip(image_512, dims=(3,)))\n            prob.append(F.softmax(logit, -1))\n\n            # 'scale' in tta:\n            logit, _ = study_net[i](image_640)\n            prob.append(F.softmax(logit, -1))\n            # ----\n\n        prob = torch.stack(prob, 0).mean(0)\n        ensemble += prob ** 0.5\n\n    return ensemble\n\n\n#------\n\n\n\n\nif 1:\n\n    dataset = SiimDataset()  # null_augment\n    loader = DataLoader(\n        dataset,\n        sampler=SequentialSampler(dataset),\n        batch_size=3,\n        drop_last=False,\n        num_workers=0,\n        pin_memory=True,\n        collate_fn=null_collate,\n    )\n    print('len(loader)', len(loader))\n\n    #-----------------------------------------------------\n\n    for net in study_net:\n        net.eval()\n        net.cuda()\n\n    for net in image_net:\n        net.eval()\n        net.cuda()\n\n    start_timer = timer()\n    study_probability = []\n    image_detection = []\n    for t, batch in enumerate(loader):\n        # if t==5 :break  #<debug>\n\n        image = batch['image'].cuda()\n        image_512 = F.interpolate(image, size=(512,512), mode='bilinear', align_corners=False)\n        image_640 = image\n\n        ensemble = process_one_batch_for_study(image_512, image_640)\n        study_probability.append(ensemble.float().data.cpu().numpy())\n\n        ensemble = process_one_batch_for_image(image_640)\n        image_detection.extend(ensemble)\n\n        #-----\n        print('\\r\\tbatch t=%d of loader : %s' % (t, time_to_str(timer() - start_timer, 'sec')),end='', flush=True)\n    print('')\n    # -----\n\n    study_probability = np.concatenate(study_probability)\n    print('study_probability',study_probability.shape)\n\n    df_study = probability_to_df_study(dataset.df, study_probability)\n    print('df_study', df_study.shape)\n    print(df_study)\n    print('')\n\n    #----\n\n    print('len(image_detection)',len(image_detection))\n\n    df_image = detection_to_df_image(dataset.df, image_detection)\n    print('df_image', df_image.shape)\n    print(df_image)\n    print('')\n\n    #----\n    # we use study 'negative' for image 'none' prediction\n    # this is more accurate ????\n    df_image = make_fake_opacity_prediction(df_image, df_study, dataset.df)\n    print('df_image', df_image.shape)\n    print(df_image)\n    print('')\n\n\n    #----\n    #submit :\n    df_submit = pd.concat([df_study, df_image]).reset_index(drop=True)\n    print(df_submit)\n    df_submit[['id', 'PredictionString']].to_csv('./submission.csv', index=False)\n\nprint('*** sucess !!!! ***')","metadata":{"execution":{"iopub.status.busy":"2021-08-09T21:58:58.855154Z","iopub.execute_input":"2021-08-09T21:58:58.855517Z","iopub.status.idle":"2021-08-09T21:59:17.598197Z","shell.execute_reply.started":"2021-08-09T21:58:58.85548Z","shell.execute_reply":"2021-08-09T21:59:17.597334Z"},"trusted":true},"execution_count":null,"outputs":[]}]}