{"cells":[{"metadata":{"_uuid":"c85b20ca-b984-4278-890c-039782ea9206","_cell_guid":"c8125aa0-5576-489a-bded-ffcf667fccd9","trusted":true},"cell_type":"code","source":"'''\nVersions list:\nv1: Turbo mode added! Extremely fast inference\nv2: Add TTA (only flips)\nv3: Other TTA (doesn't work), added TTA_STEPS variable to change TTA times\nv4: Complete notebook run of TTAx4 to see runtime (limit should be about 8700s)\nv5: Patched albumentations bug with ToTensorV2 and division\nv6: Roll back TTA in order to test if notebook works fully \nv7: added brightness, contrast, hue augmentation, full run for submit\n'''\n\npackage_path = '../input/efficientnet-pytorch-07/efficientnet_pytorch-0.7.0'\nimport sys; sys.path.append(package_path)\n\nbash_commands = [\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\nimport subprocess\nfor bashCommand in bash_commands:\n    process = subprocess.Popen(bashCommand.split(), stdout=subprocess.PIPE)\n    output, error = process.communicate()\n\nfrom glob import glob\nfrom sklearn.model_selection import GroupKFold\nimport cv2\nfrom skimage import io\nimport torch\nfrom torch import nn\nimport os\nfrom datetime import datetime\nimport time\nimport random\nimport cv2\nimport torchvision\nfrom torchvision import transforms\nimport pandas as pd\nimport numpy as np\n\nimport matplotlib.pyplot as plt\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\n\nimport sklearn\nimport warnings\nimport joblib\nfrom sklearn.metrics import roc_auc_score, log_loss\nfrom sklearn import metrics\nimport warnings\nimport cv2\nimport pydicom\nfrom efficientnet_pytorch import EfficientNet\nfrom scipy.ndimage.interpolation import zoom\nfrom tqdm import tqdm\nimport albumentations as albu\n\ndo_full = False\n\nTTA_STEPS=3\n\nCFG = {\n    'train': False,\n    \n    'train_img_path': '../input/rsna-str-pulmonary-embolism-detection/train',\n    'test_img_path': '../input/rsna-str-pulmonary-embolism-detection/test',\n    'cv_fold_path': '../input/stratified-validation-strategy/rsna_train_splits_fold_20.csv',\n    'train_path': '../input/rsna-str-pulmonary-embolism-detection/train.csv',\n    'test_path': '../input/rsna-str-pulmonary-embolism-detection/test.csv',\n    \n    'image_target_cols': [\n        'pe_present_on_image', # only image level\n    ],\n    \n    'exam_target_cols': [\n        'negative_exam_for_pe', # exam level\n        'rv_lv_ratio_gte_1', # exam level\n        'rv_lv_ratio_lt_1', # exam level\n        'leftsided_pe', # exam level\n        'chronic_pe', # exam level\n        'rightsided_pe', # exam level\n        'acute_and_chronic_pe', # exam level\n        'central_pe', # exam level\n        'indeterminate' # exam level\n    ], \n    \n    'img_num': 200,\n    'img_size': 256,\n    'lr': 0.0005,\n    'epochs': 2,\n    'device': 'cuda', # cuda, cpu\n    'train_bs': 2,\n    'accum_iter': 8,\n    'verbose_step': 1,\n    'num_workers': 4,\n    'efbnet': 'efficientnet-b0',\n    \n    'train_folds': [np.arange(0,16),\n                    np.concatenate([np.arange(0,12), np.arange(16,20)]),\n                    np.concatenate([np.arange(0,8), np.arange(12,20)]),\n                    np.concatenate([np.arange(0,4), np.arange(8,20)]),\n                    np.arange(4,20),\n                   ],#[np.arange(0,16)],\n    \n    'valid_folds': [np.arange(16,20),\n                    np.arange(12,16),\n                    np.arange(8,12),\n                    np.arange(4,8),\n                    np.arange(0,4)\n                   ],#[np.arange(16,20)],\n    \n    'model_path': '../input/kh-rsna-model',\n    'tag': 'efb0_stage2_multilabel'\n}\n\nSEED = 42321\n\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\n\n\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\n\n\ndef window(img, WL=50, WW=350):\n    upper, lower = WL+WW//2, WL-WW//2\n    X = np.clip(img.copy(), lower, upper)\n    X = X - np.min(X)\n    X = X / np.max(X)\n    return X\n\ndef get_img(path, transforms):\n    \n    d = pydicom.read_file(path)\n    '''\n    res = cv2.resize((d.pixel_array - d.RescaleIntercept) / (d.RescaleSlope * 1000), (CFG['img_size'], CFG['img_size'])), d.ImagePositionPatient[2]\n    '''\n\n    '''\n    RED channel / LUNG window / level=-600, width=1500\n    GREEN channel / PE window / level=100, width=700\n    BLUE channel / MEDIASTINAL window / level=40, width=400\n    '''\n    \n    img = (d.pixel_array * d.RescaleSlope) + d.RescaleIntercept\n    \n    r = window(img, -600, 1500)\n    g = window(img, 100, 700)\n    b = window(img, 40, 400)\n    \n    res = np.concatenate([r[:, :, np.newaxis],\n                          g[:, :, np.newaxis],\n                          b[:, :, np.newaxis]], axis=-1)\n    \n    res = transforms(image=(res*255.0).astype('uint8'))['image']\n    #res = cv2.resize(res, (CFG['img_size'], CFG['img_size']))\n    res = torch.div(res, 255.)\n    return res\n\n# def tta_augmentation():\n#     transforms = [\n#         albu.Resize(256, 256),\n#         albu.CLAHE(p=0.4),\n#         albu.RandomBrightnessContrast(p=0.4),\n#         albu.HueSaturationValue(p=0.4),\n#         albu.Cutout(p=0.3),\n#         albu.ShiftScaleRotate(p=0.3),\n#         albu.HorizontalFlip(p=0.3)\n#         ToTensorV2(p=1.),\n#     ]\n#     return albu.Compose(transforms)\ndef tta_augmentation():\n    transforms = [\n        albu.Resize(256, 256),\n        #albu.VerticalFlip(p=0.25),\n        #albu.RandomRotate90(p=0.5),\n        albu.CLAHE(p=0.3),\n        #albu.RandomBrightnessContrast(p=0.3),\n        albu.HueSaturationValue(p=0.3),\n        albu.GaussianBlur(p=0.2),\n        albu.IAASharpen(p=0.4),\n        #albu.Cutout(p=0.3),\n        #albu.ShiftScaleRotate(p=0.4),\n        ToTensorV2(p=1.),\n    ]\n    return albu.Compose(transforms)\n\n\n\ndef get_valid_transforms():\n    return albu.Compose([\n            albu.Resize(256, 256),\n            ToTensorV2(p=1.),\n        ], p=1.)\n\nclass RSNADatasetStage1(Dataset):\n    def __init__(\n        self, df, label_smoothing, data_root, \n        image_subsampling=True, transforms=None, output_label=True\n    ):\n        \n        super().__init__()\n        self.df = df.reset_index(drop=True).copy()\n        self.label_smoothing = label_smoothing\n        self.transforms = transforms\n        self.data_root = data_root\n        self.output_label = output_label\n    \n    def __len__(self):\n        return self.df.shape[0]\n    \n    def __getitem__(self, index: int):\n        # get labels\n        if self.output_label:\n            target = self.df[CFG['image_target_cols']].values[index]\n\n        path = \"{}/{}/{}/{}.dcm\".format(self.data_root, \n                                        self.df.iloc[index]['StudyInstanceUID'], \n                                        self.df.iloc[index]['SeriesInstanceUID'], \n                                        self.df.iloc[index]['SOPInstanceUID'])\n\n        img  = get_img(path, self.transforms)\n        #print(torch.max(img))\n        #print(img.max())\n        return img\n        \nclass RSNADataset(Dataset):\n    def __init__(\n        self, df, label_smoothing, data_root, \n        image_subsampling=True, transforms=None, output_label=True\n    ):\n        \n        super().__init__()\n        self.df = df\n        self.patients = self.df['StudyInstanceUID'].unique()\n        self.image_subsampling = image_subsampling\n        self.label_smoothing = label_smoothing\n        self.transforms = transforms\n        self.data_root = data_root\n        self.output_label = output_label\n        \n    def get_patients(self):\n        return self.patients\n        \n    def __len__(self):\n        return len(self.patients)\n    \n    def __getitem__(self, index: int):\n        \n        patient = self.patients[index]\n        df_ = self.df.loc[self.df.StudyInstanceUID == patient]\n        \n        per_image_feats = get_stage1_columns()\n        #print(per_image_feats)\n        \n        if self.image_subsampling:\n            img_num = min(CFG['img_num'], df_.shape[0])\n            \n            # naive image subsampling\n            img_ix = np.random.choice(np.arange(df_.shape[0]), replace=False, size=img_num)\n            \n            # get all images, then slice location and sort according to z values\n            imgs = np.zeros((CFG['img_num'],), np.float32)\n            per_image_preds = np.zeros((CFG['img_num'], len(per_image_feats)), np.float32)\n            locs = np.zeros((CFG['img_num'],), np.float32)\n            image_masks = np.zeros((CFG['img_num'],), np.float32)\n            image_masks[:img_num] = 1.\n            \n            # get labels\n            if self.output_label:\n                exam_label = df_[CFG['exam_target_cols']].values[0]\n                image_labels = np.zeros((CFG['img_num'], len(CFG['image_target_cols'])), np.float32)\n            \n        else:\n            img_num = df_.shape[0]\n            img_ix = np.arange(df_.shape[0])\n            \n            # get all images, then slice location and sort according to z values\n            imgs = np.zeros((img_num, ), np.float32) #np.zeros((img_num, CFG['img_size'], CFG['img_size'], 3), np.float32)\n            per_image_preds = np.zeros((img_num, len(per_image_feats)), np.float32)\n            locs = np.zeros((img_num,), np.float32)\n            image_masks = np.zeros((img_num,), np.float32)\n            image_masks[:img_num] = 1.\n            \n            # get labels\n            if self.output_label:\n                exam_label = df_[CFG['exam_target_cols']].values[0]\n                image_labels = np.zeros((img_num, len(CFG['image_target_cols'])), np.float32)\n                \n        for i, im_ix in enumerate(img_ix):\n            path = \"{}/{}/{}/{}.dcm\".format(self.data_root, \n                                            df_['StudyInstanceUID'].values[im_ix], \n                                            df_['SeriesInstanceUID'].values[im_ix], \n                                            df_['SOPInstanceUID'].values[im_ix])\n            \n            d = pydicom.read_file(path)\n            locs[i] = d.ImagePositionPatient[2]\n            per_image_preds[i,:] = df_[per_image_feats].values[im_ix,:]\n            \n            if self.output_label == True:\n                image_labels[i] = df_[CFG['image_target_cols']].values[im_ix]\n\n        #print('get img done')\n        \n        seq_ix = np.argsort(locs)\n        \n        # image features: img_num * img_size * img_size * 1\n        '''\n        imgs = imgs[seq_ix]\n        if self.transforms:\n            imgs = [self.transforms(image=img)['image'] for img in imgs]\n        imgs = torch.stack(imgs)\n        '''\n        \n        # image level features: img_num\n        #locs[:img_num] -= locs[:img_num].min()\n        locs = locs[seq_ix]\n        locs[1:img_num] = locs[1:img_num]-locs[0:img_num-1]\n        locs[0] = 0\n        \n        per_image_preds = per_image_preds[seq_ix]\n        \n        # patient level features: 1\n        \n        # train, train-time valid, multiple patients: imgs, locs, image_labels, exam_label, img_num\n        # whole valid-time valid, single patient: imgs, locs, image_labels, exam_label, img_num, sorted id\n        # whole test-time test, single patient: imgs, locs, img_num, sorted_id\n        \n        # do label smoothing\n        if self.output_label == True:\n            image_labels = image_labels[seq_ix]\n            image_labels = np.clip(image_labels, self.label_smoothing, 1 - self.label_smoothing)\n            exam_label =  np.clip(exam_label, self.label_smoothing, 1 - self.label_smoothing)\n            \n            return imgs, per_image_preds, locs, image_labels, exam_label, image_masks\n        else:\n            return imgs, per_image_preds, locs, img_num, index, seq_ix\n\nfrom albumentations import (\n    HorizontalFlip, VerticalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,\n    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,\n    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, IAAPiecewiseAffine,\n    IAASharpen, IAAEmboss, RandomBrightnessContrast, Flip, OneOf, Compose, Normalize, Cutout\n)\n\nfrom albumentations.pytorch import ToTensorV2               \n\nclass RNSAImageFeatureExtractor(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.cnn_model = EfficientNet.from_name(CFG['efbnet'])\n        #print(self.cnn_model, CFG['efbnet'])\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        \n    def get_dim(self):\n        return self.cnn_model._fc.in_features\n        \n    def forward(self, x):\n        feats = self.cnn_model.extract_features(x)\n        return self.pooling(feats).view(x.shape[0], -1)   \n\nclass RSNAImgClassifierSingle(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.cnn_model = RNSAImageFeatureExtractor()\n        self.image_predictors = nn.Linear(self.cnn_model.get_dim(), 1)\n        \n    def forward(self, imgs):\n        #print(images.shape)\n        imgs_embdes = self.cnn_model(imgs) # bs * efb_feat_size\n        #print(imgs_embdes.shape)\n        image_preds = self.image_predictors(imgs_embdes)\n        \n        return image_preds\n\nclass RSNAImgClassifier(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.cnn_model = RNSAImageFeatureExtractor()\n        self.image_predictors = nn.Linear(self.cnn_model.get_dim(), 9)\n        \n    def forward(self, imgs):\n        #print(images.shape)\n        imgs_embdes = self.cnn_model(imgs) # bs * efb_feat_size\n        #print(imgs_embdes.shape)\n        image_preds = self.image_predictors(imgs_embdes)\n        \n        return image_preds\n    \ndef post_process(exam_pred, image_pred):\n    \n    rv_lv_ratio_lt_1_ix = CFG['exam_target_cols'].index('rv_lv_ratio_lt_1')\n    rv_lv_ratio_gte_1_ix = CFG['exam_target_cols'].index('rv_lv_ratio_gte_1')\n    central_pe_ix = CFG['exam_target_cols'].index('central_pe')\n    rightsided_pe_ix = CFG['exam_target_cols'].index('rightsided_pe')\n    leftsided_pe_ix = CFG['exam_target_cols'].index('leftsided_pe')\n    acute_and_chronic_pe_ix = CFG['exam_target_cols'].index('acute_and_chronic_pe')\n    chronic_pe_ix = CFG['exam_target_cols'].index('chronic_pe')\n    negative_exam_for_pe_ix = CFG['exam_target_cols'].index('negative_exam_for_pe')\n    indeterminate_ix = CFG['exam_target_cols'].index('indeterminate')\n    \n    # rule 1 or rule 2 judgement: if any pe image exist\n    has_pe_image = torch.max(image_pred, 1)[0][0] > 0\n    #print(has_pe_image)\n    \n    # rule 1-a: only one >= 0.5, the other < 0.5\n    rv_lv_ratios = exam_pred[:, [rv_lv_ratio_lt_1_ix, rv_lv_ratio_gte_1_ix]]\n    rv_lv_ratios_1_a = nn.functional.softmax(rv_lv_ratios, dim=1) # to make one at least > 0.5\n    rv_lv_ratios_1_a = torch.log(rv_lv_ratios_1_a/(1-rv_lv_ratios_1_a)) # turn back into logits\n    exam_pred[:, [rv_lv_ratio_lt_1_ix, rv_lv_ratio_gte_1_ix]] = torch.where(has_pe_image, rv_lv_ratios_1_a, rv_lv_ratios)\n    \n    # rule 1-b-1 or 1-b-2 judgement: at least one > 0.5\n    crl_pe = exam_pred[:, [central_pe_ix, rightsided_pe_ix, leftsided_pe_ix]]\n    has_no_pe = torch.max(crl_pe ,1)[0] <= 0 # all <= 0.5\n    #print(has_no_pe)\n    #assert False\n        \n    # rule 1-b\n    max_val = torch.max(crl_pe, 1)[0]\n    crl_pe_1_b = torch.where(crl_pe==max_val, 0.0001-crl_pe+crl_pe, crl_pe)\n    exam_pred[:, [central_pe_ix, rightsided_pe_ix, leftsided_pe_ix]] = torch.where(has_pe_image*has_no_pe, crl_pe_1_b, crl_pe)\n    \n    # rule 1-c-1 or 1-c-2 judgement: at most one > 0.5\n    ac_pe = exam_pred[:, [acute_and_chronic_pe_ix, chronic_pe_ix]]\n    both_ac_ch = torch.min(ac_pe ,1)[0] > 0 # all > 0.5\n    \n    # rule 1-c\n    ac_pe_1_c = nn.functional.softmax(ac_pe, dim=1) # to make only one > 0.5\n    ac_pe_1_c = torch.log(ac_pe_1_c/(1-ac_pe_1_c)) # turn back into logits\n    exam_pred[:, [acute_and_chronic_pe_ix, chronic_pe_ix]] = torch.where(has_pe_image*both_ac_ch, ac_pe_1_c, ac_pe)\n    \n    # rule 1-d\n    neg_ind = exam_pred[:, [negative_exam_for_pe_ix, indeterminate_ix]]\n    neg_ind_1d = torch.clamp(neg_ind, max=0)\n    exam_pred[:, [negative_exam_for_pe_ix, indeterminate_ix]] = torch.where(has_pe_image, neg_ind_1d, neg_ind)\n    \n    # rule 2-a\n    ne_inde = exam_pred[:, [negative_exam_for_pe_ix, indeterminate_ix]]\n    ne_inde_2_a = nn.functional.softmax(ne_inde, dim=1) # to make one at least > 0.5\n    ne_inde_2_a = torch.log(ne_inde_2_a/(1-ne_inde_2_a)) # turn back into logits\n    exam_pred[:, [negative_exam_for_pe_ix, indeterminate_ix]] = torch.where(~has_pe_image, ne_inde_2_a, ne_inde)\n    \n    # rule 2-b\n    all_other_exam_labels = exam_pred[:, [rv_lv_ratio_lt_1_ix, rv_lv_ratio_gte_1_ix,\n                                          central_pe_ix, rightsided_pe_ix, leftsided_pe_ix,\n                                          acute_and_chronic_pe_ix, chronic_pe_ix]]\n    all_other_exam_labels_2_b = torch.clamp(all_other_exam_labels, max=0)\n    exam_pred[:, [rv_lv_ratio_lt_1_ix, rv_lv_ratio_gte_1_ix,\n                  central_pe_ix, rightsided_pe_ix, leftsided_pe_ix,\n                  acute_and_chronic_pe_ix, chronic_pe_ix]] = torch.where(~has_pe_image, all_other_exam_labels_2_b, all_other_exam_labels)\n    \n    return exam_pred, image_pred\n    \ndef check_label_consistency(checking_df):\n    # CHECKING CONSISTENCY OF POSITIVE EXAM LABELS\n    df = checking_df.copy()\n    print(df.shape)\n    df['positive_images_in_exam'] = df['StudyInstanceUID'].map(df.groupby(['StudyInstanceUID']).pe_present_on_image.max())\n\n    df_pos = df.loc[df.positive_images_in_exam >  0.5]\n    df_neg = df.loc[df.positive_images_in_exam <= 0.5]\n\n    rule1a = df_pos.loc[((df_pos.rv_lv_ratio_lt_1  >  0.5)  & \n                         (df_pos.rv_lv_ratio_gte_1 >  0.5)) | \n                        ((df_pos.rv_lv_ratio_lt_1  <= 0.5)  & \n                         (df_pos.rv_lv_ratio_gte_1 <= 0.5))].reset_index(drop = True)\n    rule1a['broken_rule'] = '1a'\n\n    rule1b = df_pos.loc[(df_pos.central_pe    <= 0.5) & \n                        (df_pos.rightsided_pe <= 0.5) & \n                        (df_pos.leftsided_pe  <= 0.5)].reset_index(drop = True)\n    rule1b['broken_rule'] = '1b'\n\n    rule1c = df_pos.loc[(df_pos.acute_and_chronic_pe > 0.5) & \n                        (df_pos.chronic_pe           > 0.5)].reset_index(drop = True)\n    rule1c['broken_rule'] = '1c'\n    # CHECKING CONSISTENCY OF NEGATIVE EXAM LABELS\n\n    rule1d = df_pos.loc[(df_pos.indeterminate        > 0.5) | \n                        (df_pos.negative_exam_for_pe > 0.5)].reset_index(drop = True)\n    rule1d['broken_rule'] = '1d'\n\n    rule2a = df_neg.loc[((df_neg.indeterminate        >  0.5)  & \n                         (df_neg.negative_exam_for_pe >  0.5)) | \n                        ((df_neg.indeterminate        <= 0.5)  & \n                         (df_neg.negative_exam_for_pe <= 0.5))].reset_index(drop = True)\n    rule2a['broken_rule'] = '2a'\n\n    rule2b = df_neg.loc[(df_neg.rv_lv_ratio_lt_1     > 0.5) | \n                        (df_neg.rv_lv_ratio_gte_1    > 0.5) |\n                        (df_neg.central_pe           > 0.5) | \n                        (df_neg.rightsided_pe        > 0.5) | \n                        (df_neg.leftsided_pe         > 0.5) |\n                        (df_neg.acute_and_chronic_pe > 0.5) | \n                        (df_neg.chronic_pe           > 0.5)].reset_index(drop = True)\n    rule2b['broken_rule'] = '2b'\n    # MERGING INCONSISTENT PREDICTIONS\n    errors = pd.concat([rule1a, rule1b, rule1c, rule1d, rule2a, rule2b], axis = 0)\n    \n    print('label in-consistency counts:', errors.shape)\n        \n    if errors.shape[0] > 0:\n        print(errors.broken_rule.value_counts())\n        print(errors)\n        assert False\n\nclass TimeDistributed(nn.Module):\n\n    def __init__(self, module, batch_first=True):\n        super(TimeDistributed, self).__init__()\n        self.module = module\n        self.batch_first = batch_first\n\n    def forward(self, x):\n        ''' x size: (batch_size, time_steps, in_channels, height, width) '''\n        x_size= x.size()\n        c_in = x.contiguous().view(x_size[0] * x_size[1], *x_size[2:])\n        \n        c_out = self.module(c_in)\n        r_in = c_out.view(x_size[0], x_size[1], -1)\n        if self.batch_first is False:\n            r_in = r_in.permute(1, 0, 2)\n        return r_in \n\ndef inference(model, device, df, root_path):\n    model.eval()\n\n    t = time.time()\n\n    ds = RSNADataset(df, 0.0, root_path,  image_subsampling=False, transforms=None, output_label=False) # change transforms=get_valiid_augmentation() to avoid TTA, or tta_augmentation()\n\n    dataloader = torch.utils.data.DataLoader(\n        ds, \n        batch_size=1,\n        num_workers=CFG['num_workers'],\n        shuffle=False,\n        pin_memory=True,\n    )\n    \n    patients = ds.get_patients()\n    \n    res_dfs = []\n\n    for step, (imgs, per_image_preds, locs, img_num, index, seq_ix) in enumerate(dataloader):\n        imgs = imgs.to(device).float()\n        per_image_preds = per_image_preds.to(device).float()\n        locs = locs.to(device).float()\n        \n        index = index.detach().numpy()[0]\n        seq_ix = seq_ix.detach().numpy()[0,:]\n        \n        patient_filt = (df.StudyInstanceUID == patients[index])\n        \n        patient_df = pd.DataFrame()\n        patient_df['SOPInstanceUID'] = df.loc[patient_filt, 'SOPInstanceUID'].values[seq_ix]\n        patient_df['SeriesInstanceUID'] = df.loc[patient_filt, 'SeriesInstanceUID'].values # no need to sort\n        patient_df['StudyInstanceUID'] = patients[index] # single value\n        \n        for c in CFG['image_target_cols']+CFG['exam_target_cols']:\n            patient_df[c] = 0.0\n\n        #with autocast():\n        image_preds, exam_pred = model(per_image_preds, locs)   #output = model(input)\n        #print(image_preds.shape, exam_pred.shape)\n        \n        #exam_pred, image_preds = post_process(exam_pred, image_preds)\n        \n        exam_pred = torch.sigmoid(exam_pred).cpu().detach().numpy()\n        image_preds = torch.sigmoid(image_preds).cpu().detach().numpy()\n\n        patient_df[CFG['exam_target_cols']] = exam_pred[0]\n        patient_df[CFG['image_target_cols']] = image_preds[0,:]\n        res_dfs += [patient_df]\n\n        if ((step + 1) % CFG['verbose_step'] == 0) or ((step + 1) == len(dataloader)):\n            print(\n                f'Inference Step {step+1}/{len(dataloader)}, ' + \\\n                f'time: {(time.time() - t):.4f}', end='\\r' if (step + 1) != len(dataloader) else '\\n'\n            )\n    \n    res_dfs = pd.concat(res_dfs, axis=0).reset_index(drop=True)\n    res_dfs = df[['SOPInstanceUID', 'SeriesInstanceUID', 'StudyInstanceUID']].merge(res_dfs, on=['SOPInstanceUID', 'SeriesInstanceUID', 'StudyInstanceUID'], how='left')\n    assert res_dfs.shape[0] == df.shape[0]\n    #check_label_consistency(res_dfs)\n    \n    return res_dfs\n  \nSTAGE1_CFGS = [\n    {\n        'tag': 'efb0_stage1',\n        'model_constructor': RSNAImgClassifierSingle,\n        'dataset_constructor': RSNADatasetStage1,\n        'output_len': 1\n    },\n    {\n        'tag': 'efb0_stage1_multilabel',\n        'model_constructor': RSNAImgClassifier,\n        'dataset_constructor': RSNADatasetStage1,\n        'output_len': 9\n    },\n]\nSTAGE1_CFGS_TAG = 'efb0-stage1-single-multi-label'\n\n\ndef get_stage1_columns():\n    \n    new_feats = []\n    for cfg in STAGE1_CFGS: # CHECK THIS OUT, DOES IT WORK\n        for i in range(cfg['output_len']):\n            f = cfg['tag']+'_'+str(i)\n            new_feats += [f]\n        \n    return new_feats\n\ndef update_stage1_test_preds(df):\n    \n    new_feats = get_stage1_columns()\n    df.loc[:,new_feats] = 0 \n    #df=pd.concat([df.copy() for i in  range(TTA_STEPS)])\n    df_list=[]\n    for n, i in enumerate(range(TTA_STEPS)):\n        if n==0:\n           test_ds = RSNADatasetStage1(df, 0.0, CFG['test_img_path'],  image_subsampling=False, transforms=get_valid_transforms(), output_label=False) # transforms=get_valid_transforms() or transforms=tta_augmentation()\n        else:\n           test_ds = RSNADatasetStage1(df, 0.0, CFG['test_img_path'],  image_subsampling=False, transforms=tta_augmentation(), output_label=False)\n\n        test_loader = torch.utils.data.DataLoader(\n            test_ds, \n            batch_size=256,\n            num_workers=CFG['num_workers'],\n            shuffle=False,\n            pin_memory=False,\n            sampler=SequentialSampler(test_ds)\n        )\n        image_preds_all_list = []\n        models = []\n\n        for cfg in STAGE1_CFGS:\n            device = torch.device(CFG['device'])\n            model = cfg['model_constructor']().to(device)\n            model.load_state_dict(torch.load('{}/model_{}'.format(CFG['model_path'], cfg['tag'])))\n            model.eval()\n            models.append(model)\n\n        image_preds_all = []\n        for step, imgs in enumerate(tqdm(test_loader)):\n            #imgs = torch.reshape(imgs, (-1, 3, 256, 256))\n            imgs = imgs.to(device).float()\n            for model in models:\n                image_preds = model(imgs)   #output = model(input)\n                image_preds_all += [image_preds.cpu().detach().numpy()]\n            #print(imgs[0], image_preds[0,:]); break\n            #continue\n        del test_loader\n\n        torch.cuda.empty_cache()\n\n        image_preds_all_image = np.concatenate(image_preds_all[::2], axis=0)\n        image_preds_all_exam = np.concatenate(image_preds_all[1::2], axis=0)\n\n        image_preds_all = np.concatenate([image_preds_all_image, image_preds_all_exam], axis=1)\n\n        #image_preds_all = np.concatenate(image_preds_all, axis=1)\n        print(np.array(new_feats).shape)\n        print(np.array(image_preds_all).shape)\n        temp = df.copy()\n        temp.loc[:, new_feats] = image_preds_all\n        df_list.append(temp)\n        del temp\n    #df = pd.concat(df_list)\n    return df_list\n\nclass RSNAClassifier(nn.Module):\n    def __init__(self, hidden_size=64):\n        super().__init__()\n        \n        self.gru = nn.GRU(len(get_stage1_columns())+1, hidden_size, bidirectional=True, batch_first=True, num_layers=2)\n        \n        self.image_predictors = TimeDistributed(nn.Linear(hidden_size*2, 1))\n        self.exam_predictor = nn.Linear(hidden_size*2*2, 9)\n        \n    def forward(self, img_preds, locs):\n        \n        embeds = torch.cat([img_preds, locs.view(locs.shape[0], locs.shape[1], 1)], dim=2) # bs * ts * fs\n        \n        embeds, _ = self.gru(embeds)\n        image_preds = self.image_predictors(embeds)\n        \n        avg_pool = torch.mean(embeds, 1)\n        max_pool, _ = torch.max(embeds, 1)\n        conc = torch.cat([avg_pool, max_pool], 1)\n        \n        exam_pred = self.exam_predictor(conc)\n        return image_preds, exam_pred\n\nif __name__ == '__main__':\n\n    seed_everything(SEED)\n    from os import path\n    if path.exists('../input/rsna-str-pulmonary-embolism-detection/train') and not do_full:\n        test_df = pd.read_csv(CFG['test_path']).head(101)\n    else:\n        test_df = pd.read_csv(CFG['test_path'])\n    \n    with torch.no_grad():\n        test_df = update_stage1_test_preds(test_df)\n    #if do_full:\n    #    test_df.to_csv('troubleshooting_raw.csv') # COMMENT THIS OUT FOR FULL RUNS\n    device = torch.device(CFG['device'])\n    model = RSNAClassifier().to(device)\n    model.load_state_dict(torch.load('{}/model_{}'.format(CFG['model_path'], CFG['tag'])))\n    \n    test_pred_df = inference(model, device, test_df[0], CFG['test_img_path'])\n    for i in test_df[1:]:\n        test_pred_df.loc[:, test_pred_df.columns[3:]] += inference(model, device, i, CFG['test_img_path']).loc[:, test_pred_df.columns[3:]]\n    test_pred_df.loc[:, test_pred_df.columns[3:]]/=TTA_STEPS\n    ids = []\n    labels = []\n    \n    gp_mean = test_pred_df.loc[:, ['StudyInstanceUID']+CFG['exam_target_cols']].groupby('StudyInstanceUID', sort=False).mean()\n    for col in CFG['exam_target_cols']:\n        ids += [[patient+'_'+col for patient in gp_mean.index]]\n        labels += [gp_mean[col].values]\n\n    ids += [test_pred_df.SOPInstanceUID.values]\n    labels += [test_pred_df[CFG['image_target_cols']].values[:,0]]\n    ids = np.concatenate(ids)\n    labels = np.concatenate(labels)\n\n    assert len(ids) == len(labels)\n\n    submission = pd.DataFrame()\n    submission['id'] = ids\n    submission['label'] = labels\n    print(submission.head())\n    \n    submission.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}