{"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":"!pip install /kaggle/input/dicomsdl/dicomsdl-0.109.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:10:06.066794Z","iopub.execute_input":"2023-10-13T15:10:06.068902Z","iopub.status.idle":"2023-10-13T15:10:39.624037Z","shell.execute_reply.started":"2023-10-13T15:10:06.068858Z","shell.execute_reply":"2023-10-13T15:10:39.622965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"0\"\n\nlibdir = '.'\nvalid_bs_ = 4\nnum_workers_ = 2\nfrom glob import glob\n\nclass CFG:\n    seed=42\n    device='GPU'\n    num_workers=num_workers_\n    valid_bs=valid_bs_\n    mode = 'test'\n    data_dir = '/kaggle/input/rsna-2023-abdominal-trauma-detection/'\n    img_dir = data_dir + f'{mode}_images'\n    target_cols=['bowel_healthy', 'bowel_injury', 'extravasation_healthy',\n       'extravasation_injury', 'kidney_healthy', 'kidney_low', 'kidney_high',\n       'liver_healthy', 'liver_low', 'liver_high', 'spleen_healthy',\n       'spleen_low', 'spleen_high']\n    \n    archs_list = [\"resnest50d\"]*5\n    weights_list = glob('/kaggle/input/rsna-gru-aug3c/*.pth') \n    \n    archs_list2 = [\"resnest50d\"]*5\n    weights_list2 = glob('/kaggle/input/rsna-kidney-mxaug3c/*.pth') \n                   \n    seq_len = 96\n    img_size = 256\n    \n    dropout=0.1\n    \nimport sys; \n\npackage_paths = [f'{libdir}pytorch-image-models-master']\nfor pth in package_paths:\n    sys.path.append(pth)\n    \nimport ast\nfrom glob import glob\nimport cv2\n# from skimage import io\nimport os\nfrom datetime import datetime\nimport time\nimport random\nfrom tqdm import tqdm\nfrom contextlib import contextmanager\nimport math\n\nimport dicomsdl\n\nimport numpy as np\nimport pandas as pd\nimport sklearn\nfrom sklearn.metrics import roc_auc_score, log_loss\nfrom sklearn import metrics\nfrom sklearn.model_selection import GroupKFold, StratifiedKFold, StratifiedGroupKFold\nimport torch\nimport torchvision\nfrom torchvision import transforms\nfrom torch import nn\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\nfrom torch.nn.modules.loss import _WeightedLoss\nimport torch.nn.functional as F\nimport matplotlib.pyplot as plt\n\nfrom torch.optim import Adam, SGD, AdamW\nfrom torch.optim.lr_scheduler import CosineAnnealingWarmRestarts, CosineAnnealingLR, ReduceLROnPlateau\nimport timm\nimport warnings\nimport joblib\nfrom scipy.ndimage.interpolation import zoom\nimport nibabel as nib\nimport pydicom as dicom\nimport gc \nfrom torch.nn import DataParallel\n\nfrom albumentations import Resize\n\nimport albumentations\nfrom albumentations.pytorch import ToTensorV2\n\nfrom torch.cuda.amp import autocast, GradScaler\n\n\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n\ndef seed_everything(seed=42):\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\nseed_everything(CFG.seed)\n\n\ndef do_pad_to_square(image):\n    l, h, w = image.shape\n    if w > h:\n        pad = w - h\n        pad0 = pad // 2\n        pad1 = pad - pad0\n        image = F.pad(image, [0, 0, pad0, pad1], mode='constant', value=0)\n    if w < h:\n        pad = h - w\n        pad0 = pad // 2\n        pad1 = pad - pad0\n        image = F.pad(image, [pad0, pad1, 0, 0], mode='constant', value=0)\n    return image\n\n\ndef do_scale_to_size(image, spacing, max_size):\n    dz, dy, dx = spacing\n    l, s, s = image.shape # scale to max size\n    if max_size != s:\n        scale = max_size / s\n\n        l = int(dz / dy * l * 0.5)  # we use sapcing dz,dy,dx = 2,1,1\n        l = int(scale * l)\n        h = int(scale * s)\n        w = int(scale * s)\n\n        image = F.interpolate(\n            image.unsqueeze(0).unsqueeze(0),\n            size=(l, h, w),\n            mode='trilinear',\n            align_corners=False,\n        ).squeeze(0).squeeze(0)\n    return image\n\ndef dicomsdl_to_numpy_image(ds, index=0):\n    info = ds.getPixelDataInfo()\n    if info['SamplesPerPixel'] != 1:\n        raise RuntimeError('SamplesPerPixel != 1')  # number of separate planes in this image\n    shape = [info['Rows'], info['Cols']]\n    dtype = info['dtype']\n    outarr = np.empty(shape, dtype=dtype)\n    ds.copyFrameData(index, outarr)\n    return outarr\n\n\n\ndef load_dicomsdl_dir(dcm_dir, slice_range=None):\n    dcm_file = sorted(glob(f'{dcm_dir}/*.dcm'), key=lambda x: int(x.split('/')[-1].split('.')[0]))\n    \n    # https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection/discussion/435815\n\n    #fake some slice so that it won't cause error ....\n    if len(dcm_file)==1:\n        dcm = dicomsdl.open(dcm_file[0])\n        pixel_array = dicomsdl_to_numpy_image(dcm) \n        pixel_array = pixel_array.astype(np.float32)\n        image = np.stack([pixel_array]*16)\n        dz,dy,dx = 1,1,1\n        return image, (dz,dy,dx)\n    \n    dcm_file_excep = []\n    image = []\n    for f in dcm_file:\n        try:\n            dcm = dicomsdl.open(f)\n            pixel_array = dicomsdl_to_numpy_image(dcm)\n            if dcm.PixelRepresentation == 1:\n                bit_shift = dcm.BitsAllocated - dcm.BitsStored\n                dtype = pixel_array.dtype\n                pixel_array = (pixel_array << bit_shift).astype(dtype) >> bit_shift\n\n            #processing\n            pixel_array = pixel_array.astype(np.float32)\n            pixel_array = dcm.RescaleSlope * pixel_array + dcm.RescaleIntercept\n            xmin = dcm.WindowCenter-0.5-(dcm.WindowWidth-1)* 0.5\n            xmax = dcm.WindowCenter-0.5+(dcm.WindowWidth-1)* 0.5\n            norm = np.empty_like(pixel_array, dtype=np.uint8)\n            dicomsdl.util.convert_to_uint8(pixel_array, norm, xmin, xmax)\n            if dcm.PhotometricInterpretation == 'MONOCHROME1':\n                norm = 255 - norm\n            img = norm\n            if(img.shape[0]>512):\n                s1 = img[:512].sum()\n                s2 = img[(img.shape[0]//2)-256:(img.shape[0]//2)+256].sum()\n                s3 = img[-512:].sum()\n                if(s1>s2 and s1>s3):\n                    img = img[:512]\n                elif(s3>s1 and s3>s2):\n                    img = img[-512:]\n                else:\n                    img = img[(img.shape[0]//2)-256:(img.shape[0]//2)+256]\n            if(img.shape[1]>512):\n                s1 = img[:, :512].sum()\n                s2 = img[:, (img.shape[0]//2)-256:(img.shape[0]//2)+256].sum()\n                s3 = img[:, -512:].sum()\n                if(s1>s2 and s1>s3):\n                    img = img[:, :512]\n                elif(s3>s1 and s3>s2):\n                    img = img[:, -512:]\n                else:\n                    img = img[:, (img.shape[0]//2)-256:(img.shape[0]//2)+256]\n            image.append(img)\n        except:\n            dcm_file_excep.append(f)\n            \n    dcm_file = [i for i in dcm_file if i not in dcm_file_excep]\n    #------------------------------------\n    if slice_range is None: \n        slice_min = int(dcm_file[0].split('/')[-1].split('.')[0])\n        slice_max = int(dcm_file[-1].split('/')[-1].split('.')[0])+1\n        slice_range=(slice_min, slice_max)\n\n    slice_min, slice_max = slice_range\n    sz0, szN = None, None\n        \n        \n    if 1: #check inversion\n        dcm0 = dicomsdl.open(f'{dcm_dir}/{slice_min}.dcm')\n        dcmN = dicomsdl.open(f'{dcm_dir}/{slice_max-1}.dcm')\n        sx0, sy0, sz0 = dcm0.ImagePositionPatient\n        sxN, syN, szN = dcmN.ImagePositionPatient\n        if szN > sz0:\n            image=image[::-1]\n\n        dx, dy = dcm0.PixelSpacing\n        dz = np.abs((szN - sz0) / (slice_max - slice_min-1))\n    image = np.stack(image)\n    return image, (dz,dy,dx)\n\n\ndef pre_process_slice_predictor(image):\n    l,s,s = image.shape\n    L,S,S = CFG.seq_len, CFG.img_size, CFG.img_size\n\n    l1 = int(S / s * l)\n    image = F.interpolate(\n            image.unsqueeze(0).unsqueeze(0),\n            size=[l1,S,S],\n            mode='trilinear'\n        ).squeeze(0).squeeze(0)\n\n    # pad or crop to max length L\n    if L > l1:\n        image = F.pad(image, [0, 0, 0, 0, 0, L - l1], mode='constant', value=0)\n    if L < l1:\n        image = image[:L]\n    return image\n\ndef get_df():\n\n    df_test = pd.read_csv(os.path.join(CFG.data_dir, f'{CFG.mode}_series_meta.csv')).merge(\n                    pd.read_csv(os.path.join(CFG.data_dir, f\"{CFG.mode.replace('test', 'sample_submission')}.csv\")))\n    \n    \n    \n    df_test['path'] = CFG.img_dir + '/' + df_test['patient_id'].astype(str)+'/'+df_test['series_id'].astype(str)\n    df_test = df_test[df_test['path'].apply(os.path.isdir)]\n    \n    df_test = df_test.reset_index(drop=True)\n\n    return df_test\n\nclass TestDataset(Dataset):\n    def __init__(self, csv):\n        self.csv = csv\n\n    def __len__(self):\n        return self.csv.shape[0]\n\n    def __getitem__(self, index):\n\n        row = self.csv.iloc[index]\n        image, (dz, dy, dx) = load_dicomsdl_dir(row.path, slice_range=None)\n        image = torch.from_numpy(image).float()\n        image = do_pad_to_square(image)\n        image = do_scale_to_size(image, (dz, dy, dx), max_size=CFG.img_size)\n        image = pre_process_slice_predictor(image)\n        image = image.to(torch.float16)\n        image /= 255\n        return row.patient_id, image\n        \nimport torch.nn as nn\nfrom itertools import repeat\n\nclass SpatialDropout(nn.Module):\n    def __init__(self, drop=0.5):\n        super(SpatialDropout, self).__init__()\n        self.drop = drop\n        \n    def forward(self, inputs, noise_shape=None):\n        outputs = inputs.clone()\n        if noise_shape is None:\n            noise_shape = (inputs.shape[0], *repeat(1, inputs.dim()-2), inputs.shape[-1]) \n        \n        self.noise_shape = noise_shape\n        if not self.training or self.drop == 0:\n            return inputs\n        else:\n            noises = self._make_noises(inputs)\n            if self.drop == 1:\n                noises.fill_(0.0)\n            else:\n                noises.bernoulli_(1 - self.drop).div_(1 - self.drop)\n            noises = noises.expand_as(inputs)    \n            outputs.mul_(noises)\n            return outputs\n            \n    def _make_noises(self, inputs):\n        return inputs.new().resize_(self.noise_shape)\nimport torch\nfrom torch import nn\nimport torch.nn.functional as F\n\nfrom typing import Dict, Optional\n \nimport numpy as np\nimport torch\nimport torch.nn.functional as F\nfrom torch import Tensor\n\nclass MLPAttentionNetwork(nn.Module):\n \n    def __init__(self, hidden_dim, attention_dim=None):\n        super(MLPAttentionNetwork, self).__init__()\n \n        self.hidden_dim = hidden_dim\n        self.attention_dim = attention_dim\n        if self.attention_dim is None:\n            self.attention_dim = self.hidden_dim\n        # W * x + b\n        self.proj_w = nn.Linear(self.hidden_dim, self.attention_dim, bias=True)\n        # v.T\n        self.proj_v = nn.Linear(self.attention_dim, 1, bias=False)\n \n    def forward(self, x):\n        batch_size, seq_len, _ = x.size()\n        H = torch.tanh(self.proj_w(x))\n        att_scores = torch.softmax(self.proj_v(H),axis=1)\n        attn_x = (x * att_scores).sum(1)\n        return attn_x\n    \n\nclass RSNAClassifier(nn.Module):\n    def __init__(self, model_arch, hidden_dim=256, seq_len=CFG.seq_len, pretrained=False):\n        super().__init__()\n        self.seq_len = seq_len\n        self.model_arch = model_arch\n        self.model = timm.create_model(model_arch, in_chans=3, pretrained=pretrained)\n\n\n        cnn_feature = self.model.fc.in_features\n        self.model.global_pool = nn.Identity()\n        self.model.fc = nn.Identity()\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        \n        self.spatialdropout = SpatialDropout(CFG.dropout)\n        self.gru = nn.GRU(cnn_feature, hidden_dim, num_layers=2, batch_first=True, bidirectional=True)\n        self.mlp_attention_layer = MLPAttentionNetwork(2 * hidden_dim)\n        self.logits = nn.Sequential(\n#             nn.Linear(hidden_dim*2, 128),\n#             nn.ReLU(),\n#             nn.Dropout(CFG.dropout),\n            nn.Linear(256, len(CFG.target_cols)),\n        )\n\n    def forward(self, x):\n        bs = x.size(0)\n        x = x.reshape(bs*self.seq_len//3, 3, x.size(2), x.size(3))\n        features = self.model(x)\n        features = self.pooling(features).view(bs*self.seq_len//3, -1)\n        features = self.spatialdropout(features) \n        # print(features.shape)\n        features = features.reshape(bs, self.seq_len//3, -1) \n        features, _ = self.gru(features)            \n        atten_out = self.mlp_attention_layer(features) \n        pred = self.logits(atten_out)\n        pred = pred.view(bs, -1)\n        return pred\n\n    \nclass RSNAClassifier2(nn.Module):\n    def __init__(self, model_arch, hidden_dim=256, seq_len=CFG.seq_len, pretrained=False):\n        super().__init__()\n        self.seq_len = seq_len\n        self.model_arch = model_arch\n        self.model = timm.create_model(model_arch, in_chans=3, pretrained=pretrained)\n\n\n        cnn_feature = self.model.fc.in_features\n        self.model.global_pool = nn.Identity()\n        self.model.fc = nn.Identity()\n        self.pooling = nn.AdaptiveAvgPool2d(1)\n        \n        self.spatialdropout = SpatialDropout(CFG.dropout)\n        self.gru = nn.GRU(cnn_feature, hidden_dim, num_layers=2, batch_first=True, bidirectional=True)\n        self.mlp_attention_layer = MLPAttentionNetwork(2 * hidden_dim)\n        self.logits = nn.Sequential(\n#             nn.Linear(hidden_dim*2, 128),\n#             nn.ReLU(),\n#             nn.Dropout(CFG.dropout),\n            nn.Linear(256, 9),\n        )\n\n    def forward(self, x):\n        bs = x.size(0)\n        x = x.reshape(bs*self.seq_len//3, 3, x.size(2), x.size(3))\n        features = self.model(x)\n        features = self.pooling(features).view(bs*self.seq_len//3, -1)\n        features = self.spatialdropout(features) \n        # print(features.shape)\n        features = features.reshape(bs, self.seq_len//3, -1) \n        features, _ = self.gru(features)            \n        atten_out = self.mlp_attention_layer(features) \n        pred = self.logits(atten_out)\n        pred = pred.view(bs, -1)\n        return pred\n\ndef get_preds():\n    test_df = get_df()\n    test_dataset = TestDataset(test_df)\n    test_loader = DataLoader(test_dataset, batch_size=CFG.valid_bs, shuffle=False, num_workers=CFG.num_workers, pin_memory=True, drop_last=False)\n\n    cls_model_list = []\n    for m_arch, m_weight  in zip(CFG.archs_list, CFG.weights_list):\n        model = RSNAClassifier(m_arch, hidden_dim=128, seq_len=CFG.seq_len, pretrained=False)\n        model.to(device)\n        model.load_state_dict(torch.load(m_weight)[\"model\"])\n        model.eval()\n        cls_model_list.append(model)\n        \n    cls_model_list2 = []\n    for m_arch, m_weight  in zip(CFG.archs_list2, CFG.weights_list2):\n        model = RSNAClassifier2(m_arch, hidden_dim=128, seq_len=CFG.seq_len, pretrained=False)\n        model.to(device)\n        model.load_state_dict(torch.load(m_weight)[\"model\"])\n        model.eval()\n        cls_model_list2.append(model)\n\n    print(len(cls_model_list), len(cls_model_list2))\n\n    all_preds = []\n    patient_ids = []\n\n    for step, (patient, images) in enumerate(test_loader):\n        images = images.to(device, dtype=torch.float)\n        models_preds = []\n        for model in cls_model_list:\n            with torch.no_grad(): \n                y_preds = model(images)\n                y_preds = y_preds.squeeze(1)\n                models_preds.append(y_preds.sigmoid().to('cpu').numpy())\n        models_preds = np.mean(models_preds, axis=0)\n        \n        models_preds2 = []\n        for model in cls_model_list2:\n            with torch.no_grad(): \n                y_preds = model(images)\n                y_preds = y_preds.squeeze(1)\n                models_preds2.append(y_preds.sigmoid().to('cpu').numpy())\n        models_preds2 = np.mean(models_preds2, axis=0)\n        \n        models_preds[:, 4:] = 0.5*models_preds[:, 4:] + 0.5*models_preds2\n        \n        all_preds.append(models_preds)\n        patient_ids += patient.tolist()\n    all_preds = np.concatenate(all_preds)\n    all_preds[:, 1] *= 2\n    all_preds[:, 3] *= 6\n    all_preds[:, [5, 8, 11]] *= 2\n    all_preds[:, [6, 9, 12]] *= 4\n    \n    del cls_model_list, model, test_dataset, test_loader, test_df\n    gc.collect()\n    torch.cuda.empty_cache()\n    sub = pd.DataFrame(all_preds, columns = CFG.target_cols)\n    sub['patient_id'] = patient_ids\n    sub = sub[['patient_id'] + CFG.target_cols].groupby('patient_id').mean().reset_index()\n    \n    return sub\n\n\nsub__ =  get_preds()","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:10:39.626449Z","iopub.execute_input":"2023-10-13T15:10:39.627028Z","iopub.status.idle":"2023-10-13T15:11:15.279323Z","shell.execute_reply.started":"2023-10-13T15:10:39.62699Z","shell.execute_reply":"2023-10-13T15:11:15.278272Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install pydicom\n!pip install nibabel\n!pip install timm\n!pip install transformers\n!pip install albumentations\n#!pip install segmentation_models_pytorch","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:11:15.2819Z","iopub.execute_input":"2023-10-13T15:11:15.282259Z","iopub.status.idle":"2023-10-13T15:13:57.23876Z","shell.execute_reply.started":"2023-10-13T15:11:15.282224Z","shell.execute_reply":"2023-10-13T15:13:57.237583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/segmentation-library/segmentation_models.pytorch')\nsys.path.append('/kaggle/input/pretrainedmodels/pretrainedmodels-0.7.4')\nsys.path.append('/kaggle/input/efficientnet-library/EfficientNet-PyTorch')\n\nimport pandas as pd\nimport numpy as np\n\nimport cv2\nimport zipfile\nimport os\nimport gc\nimport glob\nimport shutil\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\n\nimport pydicom #as dicom\nimport nibabel as nib\n\nimport albumentations as A\n\nimport torch\nimport torch.nn as nn\nfrom torch.nn import functional as F\n\nimport timm\n\nfrom transformers import RobertaPreLayerNormConfig, RobertaPreLayerNormModel\n\nfrom segmentation_models_pytorch.decoders.unet.model import (\n    UnetDecoder,\n    SegmentationHead,\n)\n\ndevice = 'cuda'","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:13:57.242017Z","iopub.execute_input":"2023-10-13T15:13:57.24266Z","iopub.status.idle":"2023-10-13T15:14:05.919127Z","shell.execute_reply.started":"2023-10-13T15:13:57.242605Z","shell.execute_reply":"2023-10-13T15:14:05.918182Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SegModel(nn.Module):\n    def __init__(self):\n        super(SegModel, self).__init__()\n   \n        self.n_classes = len(\n            [\n                'background',\n                'liver',\n                'spleen',\n                'left kidney',\n                'right kidney',\n                'bowel'\n            ])\n        in_chans = 1\n\n        self.encoder = timm.create_model(\n            'regnety_002',\n            pretrained=False,\n            features_only=True,\n            in_chans=in_chans,\n        )\n        encoder_channels = tuple(\n            [in_chans]\n            + [\n                self.encoder.feature_info[i][\"num_chs\"]\n                for i in range(len(self.encoder.feature_info))\n            ]\n        )\n        self.decoder = UnetDecoder(\n            encoder_channels=encoder_channels,\n            decoder_channels=(256, 128, 64, 32, 16),\n            n_blocks=5,\n            use_batchnorm=True,\n            center=False,\n            attention_type=None,\n        )\n\n        self.segmentation_head = SegmentationHead(\n            in_channels=16,\n            out_channels=self.n_classes,\n            activation=None,\n            kernel_size=3,\n        )\n\n        self.bce_seg = nn.BCEWithLogitsLoss()\n\n    def forward(self, x_in):\n        enc_out = self.encoder(x_in)\n\n        decoder_out = self.decoder(*[x_in] + enc_out)\n        x_seg = self.segmentation_head(decoder_out)\n\n        return nn.Sigmoid()(x_seg)\n\n\nclass SegPipeline(nn.Module):\n    def __init__(self):\n        super(SegPipeline, self).__init__()\n\n        self.seg_model = SegModel().cuda()\n        self.seg_model.eval()\n        checkpoint = torch.load('/kaggle/input/rsna-atd-segmentation-weights/epoch040-trainloss0.0049-valloss0.0068.bin')\n        self.seg_model.load_state_dict(checkpoint)\n        self.seg_model.eval()\n\n        self.batch_size = 128\n\n    @torch.no_grad()\n    def forward(self, x_in):\n        x_in = x_in.cuda()\n        segmentations = []\n        for i in range(0, x_in.shape[0], self.batch_size):\n            segmentations.append(self.seg_model(x_in[i:i+self.batch_size]))\n\n        return torch.cat(segmentations).cpu()\n\nseg_pipeline = SegPipeline()","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:05.920753Z","iopub.execute_input":"2023-10-13T15:14:05.921788Z","iopub.status.idle":"2023-10-13T15:14:08.57084Z","shell.execute_reply.started":"2023-10-13T15:14:05.921751Z","shell.execute_reply":"2023-10-13T15:14:08.5699Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from transformers import RobertaPreLayerNormConfig, RobertaPreLayerNormModel\n\nclass FeatureExtractor(nn.Module):\n    def __init__(self, hidden, num_channel):\n        super(FeatureExtractor, self).__init__()\n\n        self.hidden = hidden\n        self.num_channel = num_channel\n\n        self.cnn = timm.create_model(model_name = 'regnety_002',\n                                     pretrained = False,\n                                     num_classes = 0,\n                                     in_chans = num_channel)\n\n        self.fc = nn.Linear(hidden, hidden//2)\n\n    def forward(self, x):\n        batch_size, num_frame, h, w = x.shape\n        x = x.reshape(batch_size, num_frame//self.num_channel, self.num_channel, h, w)\n        x = x.reshape(-1, self.num_channel, h, w)\n        x = self.cnn(x)\n        x = x.reshape(batch_size, num_frame//self.num_channel, self.hidden)\n\n        x = self.fc(x)\n        return x\n\nclass ContextProcessor(nn.Module):\n    def __init__(self, hidden):\n        super(ContextProcessor, self).__init__()\n        self.transformer = RobertaPreLayerNormModel(\n            RobertaPreLayerNormConfig(\n                hidden_size = hidden//2,\n                num_hidden_layers = 1,\n                num_attention_heads = 4,\n                intermediate_size = hidden*2,\n                hidden_act = 'gelu_new',\n                )\n            )\n\n        del self.transformer.embeddings.word_embeddings\n\n        self.dense = nn.Linear(hidden, hidden)\n        self.activation = nn.ReLU()\n\n\n    def forward(self, x):\n        x = self.transformer(inputs_embeds = x).last_hidden_state\n\n        apool = torch.mean(x, dim = 1)\n        mpool, _ = torch.max(x, dim = 1)\n        x = torch.cat([mpool, apool], dim = -1)\n\n        x = self.dense(x)\n        x = self.activation(x)\n        return x\n    \nclass CustomModel(nn.Module):\n    def __init__(self, hidden = 368, num_channel = 2):\n        super(CustomModel, self).__init__()\n\n        self.full_extractor = FeatureExtractor(hidden=hidden, num_channel=num_channel)\n        self.kidney_extractor = FeatureExtractor(hidden=hidden, num_channel=num_channel)\n        self.liver_extractor = FeatureExtractor(hidden=hidden, num_channel=num_channel)\n        self.spleen_extractor = FeatureExtractor(hidden=hidden, num_channel=num_channel)\n\n        self.full_processor = ContextProcessor(hidden=hidden)\n        self.kidney_processor = ContextProcessor(hidden=hidden)\n        self.liver_processor = ContextProcessor(hidden=hidden)\n        self.spleen_processor = ContextProcessor(hidden=hidden)\n\n        self.bowel = nn.Linear(hidden, 2)\n        self.extravasation = nn.Linear(hidden, 2)\n        self.kidney = nn.Linear(hidden, 3)\n        self.liver = nn.Linear(hidden, 3)\n        self.spleen = nn.Linear(hidden, 3)\n\n        self.softmax = nn.Softmax(dim = -1)\n\n    def forward(self, full_input, crop_liver, crop_spleen, crop_kidney):\n        full_output = self.full_extractor(full_input)\n        kidney_output = self.kidney_extractor(crop_kidney)\n        liver_output = self.liver_extractor(crop_liver)\n        spleen_output = self.spleen_extractor(crop_spleen)\n\n        full_output2 = self.full_processor(torch.cat([full_output, kidney_output, liver_output, spleen_output], dim = 1))\n        kidney_output2 = self.kidney_processor(torch.cat([full_output, kidney_output], dim = 1))\n        liver_output2 = self.liver_processor(torch.cat([full_output, liver_output], dim = 1))\n        spleen_output2 = self.spleen_processor(torch.cat([full_output, spleen_output], dim = 1))\n\n        bowel = self.softmax(self.bowel(full_output2))[0].tolist()\n        extravasation = self.softmax(self.extravasation(full_output2))[0].tolist()\n        kidney = self.softmax(self.kidney(kidney_output2))[0].tolist()\n        liver = self.softmax(self.liver(liver_output2))[0].tolist()\n        spleen = self.softmax(self.spleen(spleen_output2))[0].tolist()\n\n        #any_injury = torch.stack([\n        #    self.softmax(bowel)[:, 0],\n        #    self.softmax(extravasation)[:, 0],\n        #    self.softmax(kidney)[:, 0],\n        #    self.softmax(liver)[:, 0],\n        #    self.softmax(spleen)[:, 0]\n        #], dim = -1)\n        #any_injury = 1 - any_injury\n\n        #if mode == 'train':\n        #    mask = mask[:, [0, 2, 4, 7, 10]]\n\n        #    assert any_injury.shape == mask.shape\n        #    any_injury = any_injury * mask\n        #    any_injury = any_injury.sum(1) / mask.sum(1)\n        #    any_injury\n        #else:\n        #    any_injury, _ = any_injury.max(1)\n\n        return bowel, extravasation, kidney, liver, spleen#, any_injury\n    \nmodel1 = CustomModel()\nweights1 = torch.load('/kaggle/input/rsna-atd-weights/25dcnn-channel2-512-1thfold-trainloss0.165-valloss0.539.bin')\nmodel1 = model1.to(device)\nmodel1.load_state_dict(weights1)\n\nmodel2 = CustomModel()\nweights2 = torch.load('/kaggle/input/rsna-atd-weights/25dcnn-channel2-512-2thfold-trainloss0.2092-valloss0.4989.bin')\nmodel2 = model2.to(device)\nmodel2.load_state_dict(weights2)\n\nmodel3 = CustomModel()\nweights3 = torch.load('/kaggle/input/rsna-atd-weights/25dcnn-channel2-512-3thfold-trainloss0.186-valloss0.4705.bin')\nmodel3 = model3.to(device)\nmodel3.load_state_dict(weights3)\n\nmodel4 = CustomModel()\nweights4 = torch.load('/kaggle/input/rsna-atd-weights/25dcnn-channel2-512-4thfold-trainloss0.1983-valloss0.4716.bin')\nmodel4 = model4.to(device)\nmodel4.load_state_dict(weights4)\n\nmodel5 = CustomModel()\nweights5 = torch.load('/kaggle/input/rsna-atd-weights/25dcnn-channel2-512-5thfold-trainloss0.1559-valloss0.5194.bin')\nmodel5 = model5.to(device)\nmodel5.load_state_dict(weights5)","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:08.572437Z","iopub.execute_input":"2023-10-13T15:14:08.573012Z","iopub.status.idle":"2023-10-13T15:14:16.58268Z","shell.execute_reply.started":"2023-10-13T15:14:08.572976Z","shell.execute_reply":"2023-10-13T15:14:16.581708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# weight per model\n\nclass CustomModelEnsemble(nn.Module):\n    def __init__(self, models):\n        super(CustomModelEnsemble, self).__init__()\n        self.models = models\n        \n        '''\n        self.weight = np.array(\n            [\n                [0.5, 1, 1, 2, 1, 3, 2, 5],\n                [0.2, 2, 2, 2, 1, 2, 4, 3],\n                [0.2, 1, 3, 1, 2, 3, 2, 6],\n                [0.2, 2, 2, 1, 1, 4, 4, 4],\n                [0.8, 1, 2, 2, 1, 1, 5, 4]\n            ]\n        )\n        '''\n        self.weight = np.array(\n            [\n                [0.9, 4, 2, 4, 2, 6, 6, 6],\n                [0.9, 1, 4, 3, 2, 5, 5, 6],\n                [0.2, 3, 2, 1, 2, 4, 2, 6],\n                [0.5, 2, 2, 2, 2, 2, 6, 6],\n                [1, 2, 3, 2, 6, 3, 6, 5]\n            ]\n        )\n        \n        for model in self.models:\n            model.eval()\n        \n    def forward(self, x, crop_liver, crop_spleen, crop_kidney):\n        bowels = []\n        extravasations = []\n        kidneys = []\n        livers = []\n        spleens = []\n        for model in self.models:\n            bowel, extravasation, kidney, liver, spleen = model(x, crop_liver, crop_spleen, crop_kidney)\n            bowels.append(bowel)\n            extravasations.append(extravasation)\n            kidneys.append(kidney)\n            livers.append(liver)\n            spleens.append(spleen)\n\n        bowels = np.array(bowels)\n        extravasations = np.array(extravasations)\n        kidneys = np.array(kidneys)\n        livers = np.array(livers)\n        spleens = np.array(spleens)\n        \n        bowels[:, 1] *= self.weight[:, 0]\n        extravasations[:, 1] *= self.weight[:, 7]\n        kidneys[:, 1] *= self.weight[:, 1]\n        kidneys[:, 2] *= self.weight[:, 4]\n        livers[:, 1] *= self.weight[:, 2]\n        livers[:, 2] *= self.weight[:, 5]\n        spleens[:, 1] *= self.weight[:, 3]\n        spleens[:, 2] *= self.weight[:, 6]\n        \n        bowels = bowels ** 0.8\n        extravasations = extravasations ** 0.8\n        kidneys = kidneys ** 0.8\n        livers = livers ** 0.8\n        spleens = spleens ** 0.8\n        \n        bowel = np.mean(bowels, axis=0)\n        extravasation = np.mean(extravasations, axis=0)\n        kidney = np.mean(kidneys, axis=0)\n        liver = np.mean(livers, axis=0)\n        spleen = np.mean(spleens, axis=0)\n        \n        return bowel.tolist(), extravasation.tolist(), kidney.tolist(), liver.tolist(), spleen.tolist() #, any_injury \n    \nmodels = [model1, model2, model3, model4, model5]\nmodel = CustomModelEnsemble(models)","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:16.584324Z","iopub.execute_input":"2023-10-13T15:14:16.584712Z","iopub.status.idle":"2023-10-13T15:14:16.621354Z","shell.execute_reply.started":"2023-10-13T15:14:16.58468Z","shell.execute_reply":"2023-10-13T15:14:16.620293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# utils\n\ndef standardize_pixel_array(dcm: pydicom.dataset.FileDataset) -> np.ndarray:\n    \"\"\"\n    Source : https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection/discussion/427217\n    \"\"\"\n    # Correct DICOM pixel_array if PixelRepresentation == 1.\n    pixel_array = dcm.pixel_array\n    if dcm.PixelRepresentation == 1:\n        bit_shift = dcm.BitsAllocated - dcm.BitsStored\n        dtype = pixel_array.dtype \n        pixel_array = (pixel_array << bit_shift).astype(dtype) >>  bit_shift\n#         pixel_array = pydicom.pixel_data_handlers.util.apply_modality_lut(new_array, dcm)\n\n    intercept = float(dcm.RescaleIntercept)\n    slope = float(dcm.RescaleSlope)\n    center = int(dcm.WindowCenter)\n    width = int(dcm.WindowWidth)\n    low = center - width / 2\n    high = center + width / 2    \n    \n    pixel_array = (pixel_array * slope) + intercept\n    pixel_array = np.clip(pixel_array, low, high)\n\n    return pixel_array\n\ndef get_high_aortic_hu(df):\n    patient_ids = df.patient_id.unique()\n\n    high_aortic_hu_df = []\n    for i in range(len(patient_ids)):\n        patient_id = patient_ids[i]\n        sample = df.query(f'patient_id=={patient_id}').sort_values('aortic_hu', ascending=False).reset_index(drop=True)\n        sample = sample.loc[0]\n        high_aortic_hu_df.append(sample)\n\n    high_aortic_hu_df = pd.concat(high_aortic_hu_df, axis=1).transpose().reset_index(drop=True)\n    high_aortic_hu_df = high_aortic_hu_df.astype('int32')\n    return high_aortic_hu_df","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:16.622788Z","iopub.execute_input":"2023-10-13T15:14:16.623937Z","iopub.status.idle":"2023-10-13T15:14:16.634011Z","shell.execute_reply.started":"2023-10-13T15:14:16.623901Z","shell.execute_reply":"2023-10-13T15:14:16.633145Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# data process\nimage_height, image_width = 320, 320\ntransform_function = A.Resize(image_height, image_width)\n\ndef get_stride_box(min_y, min_x, max_y, max_x, stride=10):\n    min_y = np.clip(min_y - stride, a_min=0, a_max=512)\n    min_x = np.clip(min_x - stride, a_min=0, a_max=512)\n    max_y = np.clip(max_y + stride, a_min=0, a_max=512)\n    max_x = np.clip(max_x + stride, a_min=0, a_max=512)\n    return min_y, min_x, max_y, max_x\n\n\ndef get_segmentation_inputs(video, image_height=320, image_width=320, transform_function = transform_function):\n    video = video.transpose(1, 2, 0)\n    video = cv2.resize(video, dsize=(int(image_height), int(image_width)))\n    video = video.astype(np.uint8).transpose(2, 0, 1)\n\n    transforms = [transform_function(image=video[i]) for i in range(video.shape[0])]\n    video = np.stack([x['image'] for x in transforms], axis=0)\n\n    video = torch.tensor(video, dtype=torch.float)\n    video = video / 255\n    video = video[:, None]\n    return video\n\ndef get_coordinates(logit, thres=0.5):\n    liver = (logit[:, 0]>thres).float()\n    spleen = (logit[:, 1]>thres).float()\n    left_kidney = (logit[:, 2]>thres).float()\n    right_kidney = (logit[:, 3]>thres).float()\n\n    organs = [liver, spleen, left_kidney+right_kidney]\n\n    coordinates = []\n    for organ in organs:\n        ones_coordinates = np.argwhere(organ!=0)\n\n        min_z, min_y, min_x = ones_coordinates.min(axis=1).values\n        max_z, max_y, max_x = ones_coordinates.max(axis=1).values\n        coordinate = [min_z, min_y, min_x, max_z, max_y, max_x]\n        coordinate = torch.tensor(coordinate)\n        coordinates.append(coordinate)\n\n    coordinates = torch.stack(coordinates).numpy()\n    return coordinates\n\ndef logit2box(seg_output):\n    try:\n        coordinates = get_coordinates(seg_output, thres=0.5)\n    except:\n        try:\n            #print(f'{patient_id}-{series_id} has no logit for thres=0.5')\n            coordinates = get_coordinates(seg_output, thres=0.1)\n        except:\n            #print(f'{patient_id}-{series_id} has no logit for thres=0.1')\n            coordinates = np.zeros([3, 6])    \n    return coordinates\n\ndef get_cropped_organs(video, box, ratio=(512/320)):\n    organs = []\n    for i in range(box.shape[0]):\n        min_z, min_y, min_x, max_z, max_y, max_x = box[i]\n        if 0.0 not in [max_z - min_z, max_y - min_y, max_x - min_x]:\n            min_y, min_x, max_y, max_x = int(ratio*min_y), int(ratio*min_x), int(ratio*max_y), int(ratio*max_x)\n            min_y, min_x, max_y, max_x = get_stride_box(min_y, min_x, max_y, max_x)\n            organ = video[min_z:max_z, min_y:max_y, min_x:max_x]\n        else:\n            organ = video\n\n        organ = F.interpolate(\n            organ.unsqueeze(0).unsqueeze(0),\n            size=[96, 224, 224],\n            mode='trilinear'\n            ).squeeze(0).squeeze(0)\n        organs.append(organ)\n    return organs\n\ndef get_crop_inputs(video, box):\n    video = torch.tensor(video, dtype=torch.float)\n    organs = get_cropped_organs(video, box)\n    crop_liver, crop_spleen, crop_kidney = organs\n    \n    video = F.interpolate(\n        video.unsqueeze(0).unsqueeze(0),\n        size=[128, 224, 224],\n        mode='trilinear'\n        ).squeeze(0).squeeze(0)\n    \n    video = torch.tensor(video.numpy().astype(np.uint8), dtype=torch.float)\n    crop_liver = torch.tensor(crop_liver.numpy().astype(np.uint8), dtype=torch.float)\n    crop_spleen = torch.tensor(crop_spleen.numpy().astype(np.uint8), dtype=torch.float)\n    crop_kidney = torch.tensor(crop_kidney.numpy().astype(np.uint8), dtype=torch.float)\n    \n    video, crop_liver, crop_spleen, crop_kidney = video/255.0, crop_liver/255.0, crop_spleen/255.0, crop_kidney/255.0\n    return video, crop_liver, crop_spleen, crop_kidney","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:16.635485Z","iopub.execute_input":"2023-10-13T15:14:16.635815Z","iopub.status.idle":"2023-10-13T15:14:16.654959Z","shell.execute_reply.started":"2023-10-13T15:14:16.635785Z","shell.execute_reply":"2023-10-13T15:14:16.654061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch.nn.functional as F\n\nimg_h, img_w = 512, 512\ndown_sampling = 1#4\nmax_frame = 1024#256\n\nmodel.eval()\n\ntest_series_meta = pd.read_csv('/kaggle/input/rsna-2023-abdominal-trauma-detection/test_series_meta.csv')\n#test_series_meta = get_high_aortic_hu(test_series_meta)\n\nbowel_healthy = []\nbowel_injury = []\nextravasation_healthy = []\nextravasation_injury = []\nkidney_healthy = []\nkidney_low = []\nkidney_high = []\nliver_healthy = []\nliver_low = []\nliver_high = []\nspleen_healthy = []\nspleen_low = []\nspleen_high = []\nfor i in tqdm(range(len(test_series_meta))):\n    patient_id, series_id = test_series_meta.loc[i]['patient_id'], test_series_meta.loc[i]['series_id']\n    path = f'/kaggle/input/rsna-2023-abdominal-trauma-detection/test_images/{int(patient_id)}/{int(series_id)}/'\n    dcm_paths = glob.glob(path + '*.dcm')\n    \n    imgs = {}\n    for f in sorted(dcm_paths, key = lambda x : x.split('/')[-1].split('.')[0]):\n        try:\n            dicom = pydicom.dcmread(f)\n            pos_z = dicom[(0x20, 0x32)].value[-1]\n\n            img = standardize_pixel_array(dicom)\n            img = (img - img.min()) / (img.max() - img.min() + 1e-6)\n\n            if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n                img = 1 - img\n\n            img = cv2.resize((img * 255).astype(np.uint8), dsize=(img_h, img_w))\n        except:\n            img = np.zeros([img_h, img_w])\n            \n        imgs[pos_z] = img\n        \n    video = []\n    seg_video = []\n    for i, k in enumerate(sorted(imgs.keys())):\n        video.append(cv2.resize(imgs[k], dsize=(512, 512)))\n        seg_video.append(cv2.resize(imgs[k], dsize=(224, 224)))\n        \n    del imgs\n\n    \n    \n    if len(video) > 0:\n        video = np.stack(video)\n        seg_video = np.stack(seg_video)\n    else:\n        video = np.zeros([1, 512, 512])\n        seg_video = np.zeros([1, 224, 224])\n        \n        \n    video = video[::down_sampling][:max_frame]\n    video = torch.tensor(video, dtype=torch.float)\n                         \n    seg_video = seg_video[::down_sampling][:max_frame]\n    seg_video = torch.tensor(seg_video, dtype=torch.float)\n\n    seg_video = F.interpolate(\n        seg_video.unsqueeze(0).unsqueeze(0),\n        size=[256, 224, 224],\n        mode='trilinear'\n        ).squeeze(0).squeeze(0)\n    seg_video = seg_video.numpy()\n    seg_video = seg_video.astype(np.uint8) \n    \n    seg_inputs = get_segmentation_inputs(seg_video)\n    seg_logit = seg_pipeline(seg_inputs.to(device)).cpu()\n    \n    box = logit2box(seg_logit)\n    \n    video = F.interpolate(\n        video.unsqueeze(0).unsqueeze(0),\n        size=[256, 512, 512],\n        mode='trilinear'\n        ).squeeze(0).squeeze(0)\n    video = video.numpy()\n    #video = video.astype(np.uint8) \n    \n    crop_inputs = get_crop_inputs(video, box)\n    video, crop_liver, crop_spleen, crop_kidney = [x[None].to(device) for x in crop_inputs]\n    \n    with torch.no_grad():\n        pred = model(video, crop_liver, crop_spleen, crop_kidney)\n        \n    bowel_healthy.append(pred[0][0])\n    bowel_injury.append(pred[0][1])\n    extravasation_healthy.append(pred[1][0])\n    extravasation_injury.append(pred[1][1])\n    kidney_healthy.append(pred[2][0])\n    kidney_low.append(pred[2][1])\n    kidney_high.append(pred[2][2])\n    liver_healthy.append(pred[3][0])\n    liver_low.append(pred[3][1])\n    liver_high.append(pred[3][2])\n    spleen_healthy.append(pred[4][0])\n    spleen_low.append(pred[4][1])\n    spleen_high.append(pred[4][2])\n    \ntest_series_meta['bowel_healthy'] = bowel_healthy\ntest_series_meta['bowel_injury'] = bowel_injury\ntest_series_meta['extravasation_healthy'] = extravasation_healthy\ntest_series_meta['extravasation_injury'] = extravasation_injury\ntest_series_meta['kidney_healthy'] = kidney_healthy\ntest_series_meta['kidney_low'] = kidney_low\ntest_series_meta['kidney_high'] = kidney_high\ntest_series_meta['liver_healthy'] = liver_healthy\ntest_series_meta['liver_low'] = liver_low\ntest_series_meta['liver_high'] = liver_high\ntest_series_meta['spleen_healthy'] = spleen_healthy\ntest_series_meta['spleen_low'] = spleen_low\ntest_series_meta['spleen_high'] = spleen_high\n\ntest_series_meta = test_series_meta.drop(columns = ['series_id', 'aortic_hu'])\ntest_series_meta = test_series_meta.groupby('patient_id').mean().reset_index()\n\n#test_series_meta['bowel_injury'] *= 0.2\n#test_series_meta['kidney_low'] *= 1\n#test_series_meta['liver_low'] *= 2\n#test_series_meta['spleen_low'] *= 1\n#test_series_meta['kidney_high'] *= 1\n#test_series_meta['liver_high'] *= 3\n#test_series_meta['spleen_high'] *= 3\n#test_series_meta['extravasation_injury'] *= 4\n\n\ntest_series_meta","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:16.658194Z","iopub.execute_input":"2023-10-13T15:14:16.658526Z","iopub.status.idle":"2023-10-13T15:14:49.38907Z","shell.execute_reply.started":"2023-10-13T15:14:16.658504Z","shell.execute_reply":"2023-10-13T15:14:49.388067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# normilize the predictions before ensembling\nfor cols in [CFG.target_cols[:2], CFG.target_cols[2:4], CFG.target_cols[4:7], \n             CFG.target_cols[7:10], CFG.target_cols[10:13]]:\n    test_series_meta[cols] = test_series_meta[cols].div(test_series_meta[cols].sum(1), axis=0)\n    sub__[cols] = sub__[cols].div(sub__[cols].sum(1), axis=0)\nsub__ = pd.concat([sub__, test_series_meta[~test_series_meta['patient_id'].isin(sub__['patient_id'])]])\ntest_series_meta = pd.concat([test_series_meta, sub__[~sub__['patient_id'].isin(test_series_meta['patient_id'])]])\n\ntest_series_meta[CFG.target_cols] *= 0.65\nsub__[CFG.target_cols] *= 0.35\n\n# cols1 = ['bowel_healthy', 'bowel_injury', 'extravasation_healthy', 'extravasation_injury']\n# cols2 = ['kidney_healthy', 'kidney_low', 'kidney_high',\n#          'liver_healthy', 'liver_low', 'liver_high', \n#          'spleen_healthy', 'spleen_low', 'spleen_high']\n# test_series_meta[cols1] *= 0.5\n# sub__[cols2] *= 0.5\n\n# test_series_meta[cols1] *= 0.8\n# sub__[cols2] *= 0.2\n\ntest_series_meta = pd.concat([test_series_meta, sub__])\ntest_series_meta = test_series_meta.groupby('patient_id').sum().reset_index()\n\n","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:49.390622Z","iopub.execute_input":"2023-10-13T15:14:49.391267Z","iopub.status.idle":"2023-10-13T15:14:49.440388Z","shell.execute_reply.started":"2023-10-13T15:14:49.391235Z","shell.execute_reply":"2023-10-13T15:14:49.439438Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub = pd.read_csv('/kaggle/input/rsna-2023-abdominal-trauma-detection/sample_submission.csv')\nsample_sub = sample_sub[['patient_id']].merge(test_series_meta, how = 'left').fillna(0.33)\nsample_sub.to_csv('submission.csv', index = False)\nsample_sub","metadata":{"execution":{"iopub.status.busy":"2023-10-13T15:14:49.441653Z","iopub.execute_input":"2023-10-13T15:14:49.442481Z","iopub.status.idle":"2023-10-13T15:14:49.466017Z","shell.execute_reply.started":"2023-10-13T15:14:49.442448Z","shell.execute_reply":"2023-10-13T15:14:49.465009Z"},"trusted":true},"execution_count":null,"outputs":[]}]}