{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":36363,"databundleVersionId":4050810,"sourceType":"competition"},{"sourceId":2021296,"sourceType":"datasetVersion","datasetId":1121486},{"sourceId":3170856,"sourceType":"datasetVersion","datasetId":1927562},{"sourceId":3899138,"sourceType":"datasetVersion","datasetId":2316152},{"sourceId":4204135,"sourceType":"datasetVersion","datasetId":2478634},{"sourceId":4311652,"sourceType":"datasetVersion","datasetId":2539716},{"sourceId":4905775,"sourceType":"datasetVersion","datasetId":2845090}],"dockerImageVersionId":30236,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"DEBUG = False","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport sys\nsys.path = [\n    '../input/covn3d-same',\n    '../input/timm20221011/pytorch-image-models-master',\n    '../input/smp20210127/segmentation_models.pytorch-master/segmentation_models.pytorch-master',\n    '../input/smp20210127/pretrained-models.pytorch-master/pretrained-models.pytorch-master',\n    '../input/smp20210127/EfficientNet-PyTorch-master/EfficientNet-PyTorch-master',\n] + sys.path\n\n!pip -q install ../input/pylibjpeg140py3/pylibjpeg-1.4.0-py3-none-any.whl\n!pip -q install ../input/pylibjpeg140py3/python_gdcm-3.0.17.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n\n!cp -r ../input/timm-20220211/pytorch-image-models-master/timm ./timm4smp","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-08-05T05:44:02.35728Z","iopub.execute_input":"2023-08-05T05:44:02.357614Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import gc\nimport ast\nimport cv2\nimport time\nimport timm\nimport timm4smp\nimport pickle\nimport random\nimport pydicom\nimport argparse\nimport warnings\nimport threading\nimport numpy as np\nimport pandas as pd\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom glob import glob\nimport albumentations\nimport matplotlib.pyplot as plt\nimport segmentation_models_pytorch as smp\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nimport torch.cuda.amp as amp\nimport torch.nn.functional as F\nfrom torch.utils.data import DataLoader, Dataset\nfrom pylab import rcParams\n\n%matplotlib inline\ndevice = torch.device('cuda')\ntorch.backends.cudnn.benchmark = True\n\ntimm.__version__, timm4smp.__version__","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_dir = '../input/rsna-2022-cervical-spine-fracture-detection/'\nimage_size_seg = (128, 128, 128)\nmsk_size = image_size_seg[0]\nimage_size_cls = 384\nn_slice_per_c = 15\nn_ch = 5\n\nbatch_size_seg = 1\nnum_workers = 2","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df2 = pd.read_csv('/kaggle/input/rsnamodelstoronto/RSNA_Kaggle_Experiment.csv')\ndf2['exclude'] = 1\ndf = pd.read_csv(os.path.join(data_dir, 'train.csv'))\n\ndf = df.merge(df2[['StudyInstanceUID', 'exclude']], on='StudyInstanceUID', how='left')\ndf = df[df['exclude'].isna()].reset_index(drop=True)\ndf['image_folder'] = df['StudyInstanceUID'].apply(lambda x: os.path.join(data_dir, 'train_images', x))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Dataset","metadata":{}},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    data = cv2.resize(data, (image_size_seg[0], image_size_seg[1]), interpolation = cv2.INTER_AREA)\n    return data\n\n\ndef load_dicom_line_par(path):\n\n    t_paths = sorted(glob(os.path.join(path, \"*\")), key=lambda x: int(x.split('/')[-1].split(\".\")[0]))\n\n    n_scans = len(t_paths)\n#     print(n_scans)\n    indices = np.quantile(list(range(n_scans)), np.linspace(0., 1., image_size_seg[2])).round().astype(int)\n    t_paths = [t_paths[i] for i in indices]\n\n    images = []\n    for filename in t_paths:\n        images.append(load_dicom(filename))\n    images = np.stack(images, -1)\n    \n    images = images - np.min(images)\n    images = images / (np.max(images) + 1e-4)\n    images = (images * 255).astype(np.uint8)\n\n    return images\n\n\nclass SegTestDataset(Dataset):\n\n    def __init__(self, df):\n        self.df = df.reset_index()\n\n    def __len__(self):\n        return self.df.shape[0]\n\n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n\n        image = load_dicom_line_par(row.image_folder)\n        if image.ndim < 4:\n            image = np.expand_dims(image, 0)\n        image = image.astype(np.float32).repeat(3, 0)  # to 3ch\n        image = image / 255.\n        return torch.tensor(image).float()\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ndataset_seg = SegTestDataset(df)\nloader_seg = torch.utils.data.DataLoader(dataset_seg, batch_size=batch_size_seg, shuffle=False, num_workers=num_workers)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nrcParams['figure.figsize'] = 20,8\nfor i in range(2):\n    f, axarr = plt.subplots(1,4)\n    for p in range(4):\n        idx = i*4+p\n        img = dataset_seg[idx]\n        img = img[:, :, :, 60]\n        axarr[p].imshow(img.transpose(0, 1).transpose(1,2).squeeze())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nrcParams['figure.figsize'] = 20,8\nfor i in range(2):\n    f, axarr = plt.subplots(1,4)\n    for p in range(4):\n        idx = i*4+p\n        img = dataset_seg[idx]\n        img = img[:, :, 60, :]\n        axarr[p].imshow(img.transpose(0, 1).transpose(1,2).squeeze())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nrcParams['figure.figsize'] = 20,8\nfor i in range(2):\n    f, axarr = plt.subplots(1,4)\n    for p in range(4):\n        idx = i*4+p\n        img = dataset_seg[idx]\n        img = img[:, 60, :, :]\n        axarr[p].imshow(img.transpose(0, 1).transpose(1,2).squeeze())","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"from timm4smp.models.layers.conv2d_same import Conv2dSame\nfrom conv3d_same import Conv3dSame\n\ndef convert_3d(module):\n\n    module_output = module\n    if isinstance(module, torch.nn.BatchNorm2d):\n        module_output = torch.nn.BatchNorm3d(\n            module.num_features,\n            module.eps,\n            module.momentum,\n            module.affine,\n            module.track_running_stats,\n        )\n        if module.affine:\n            with torch.no_grad():\n                module_output.weight = module.weight\n                module_output.bias = module.bias\n        module_output.running_mean = module.running_mean\n        module_output.running_var = module.running_var\n        module_output.num_batches_tracked = module.num_batches_tracked\n        if hasattr(module, \"qconfig\"):\n            module_output.qconfig = module.qconfig\n            \n    elif isinstance(module, Conv2dSame):\n        module_output = Conv3dSame(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.Conv2d):\n        module_output = torch.nn.Conv3d(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n            padding_mode=module.padding_mode\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.MaxPool2d):\n        module_output = torch.nn.MaxPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            dilation=module.dilation,\n            ceil_mode=module.ceil_mode,\n        )\n    elif isinstance(module, torch.nn.AvgPool2d):\n        module_output = torch.nn.AvgPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            ceil_mode=module.ceil_mode,\n        )\n\n    for name, child in module.named_children():\n        module_output.add_module(\n            name, convert_3d(child)\n        )\n    del module\n\n    return module_output\n\n\n\nclass TimmSegModel(nn.Module):\n    def __init__(self, backbone, segtype='unet', pretrained=False):\n        super(TimmSegModel, self).__init__()\n\n        self.encoder = timm4smp.create_model(\n            backbone,\n            in_chans=3,\n            features_only=True,\n            pretrained=pretrained\n        )\n        g = self.encoder(torch.rand(1, 3, 64, 64))\n        encoder_channels = [1] + [_.shape[1] for _ in g]\n        decoder_channels = [256, 128, 64, 32, 16]\n        if segtype == 'unet':\n            self.decoder = smp.unet.decoder.UnetDecoder(\n                encoder_channels=encoder_channels[:n_blocks+1],\n                decoder_channels=decoder_channels[:n_blocks],\n                n_blocks=n_blocks,\n            )\n        self.segmentation_head = nn.Conv2d(decoder_channels[n_blocks-1], 7, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n\n    def forward(self,x):\n        global_features = [0] + self.encoder(x)[:n_blocks]\n        seg_features = self.decoder(*global_features)\n        seg_features = self.segmentation_head(seg_features)\n        return seg_features\n    \n    \nclass TimmModel(nn.Module):\n    def __init__(self, backbone, image_size, pretrained=False):\n        super(TimmModel, self).__init__()\n        self.image_size = image_size\n        self.encoder = timm.create_model(\n            backbone,\n            in_chans=in_chans,\n            num_classes=1,\n            features_only=False,\n            drop_rate=0,\n            drop_path_rate=0,\n            pretrained=pretrained\n        )\n\n        if 'efficient' in backbone:\n            hdim = self.encoder.conv_head.out_channels\n            self.encoder.classifier = nn.Identity()\n        elif 'convnext' in backbone or 'nfnet' in backbone:\n            hdim = self.encoder.head.fc.in_features\n            self.encoder.head.fc = nn.Identity()\n\n        self.lstm = nn.LSTM(hdim, 256, num_layers=2, dropout=0, bidirectional=True, batch_first=True)\n        self.head = nn.Sequential(\n            nn.Linear(512, 256),\n            nn.BatchNorm1d(256),\n            nn.Dropout(0),\n            nn.LeakyReLU(0.1),\n            nn.Linear(256, 1),\n        )\n        self.lstm2 = nn.LSTM(hdim, 256, num_layers=2, dropout=0, bidirectional=True, batch_first=True)\n        self.head2 = nn.Sequential(\n            nn.Linear(512, 256),\n            nn.BatchNorm1d(256),\n            nn.Dropout(0),\n            nn.LeakyReLU(0.1),\n            nn.Linear(256, 1),\n        )\n\n\n    def forward(self, x):  # (bs, nc*7, ch, sz, sz)\n        bs = x.shape[0]\n        x = x.view(bs * n_slice_per_c * 7, in_chans, self.image_size, self.image_size)\n        feat = self.encoder(x)\n        feat = feat.view(bs, n_slice_per_c * 7, -1)\n        feat1, _ = self.lstm(feat)\n        feat1 = feat1.contiguous().view(bs * n_slice_per_c * 7, 512)\n        feat2, _ = self.lstm2(feat)\n\n        return self.head(feat1), self.head2(feat2[:, 0])\n    \n    \n    \n    \nclass Timm1BoneModel(nn.Module):\n    def __init__(self, backbone, image_size, pretrained=False):\n        super(Timm1BoneModel, self).__init__()\n        self.image_size = image_size\n\n        self.encoder = timm.create_model(\n            backbone,\n            in_chans=in_chans,\n            num_classes=1,\n            features_only=False,\n            drop_rate=0,\n            drop_path_rate=0,\n            pretrained=pretrained\n        )\n\n        if 'efficient' in backbone:\n            hdim = self.encoder.conv_head.out_channels\n            self.encoder.classifier = nn.Identity()\n        elif 'convnext' in backbone or 'nfnet' in backbone:\n            hdim = self.encoder.head.fc.in_features\n            self.encoder.head.fc = nn.Identity()\n\n        self.lstm = nn.LSTM(hdim, 256, num_layers=2, dropout=0, bidirectional=True, batch_first=True)\n        self.head = nn.Sequential(\n            nn.Linear(512, 256),\n            nn.BatchNorm1d(256),\n            nn.Dropout(0),\n            nn.LeakyReLU(0.1),\n            nn.Linear(256, 1),\n        )\n\n\n    def forward(self, x):  # (bs, nslice, ch, sz, sz)\n        bs = x.shape[0]\n        x = x.view(bs * n_slice_per_c, in_chans, self.image_size, self.image_size)\n        feat = self.encoder(x)\n        feat = feat.view(bs, n_slice_per_c, -1)\n        feat, _ = self.lstm(feat)\n        feat = feat.contiguous().view(bs * n_slice_per_c, -1)\n        feat = self.head(feat)\n        feat = feat.view(bs, n_slice_per_c).contiguous()\n\n        return feat\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Load Models","metadata":{}},{"cell_type":"code","source":"models_seg = []\nkernel_type = 'timm3d_v2s_unet4b_128_128_128_dsv2_flip12_shift333p7_gd1p5_mixup1_lr1e3_20x50ep'\nbackbone = 'tf_efficientnetv2_s_in21ft1k'\nmodel_dir_seg = '../input/rsnamodelstoronto/'\nn_blocks = 4\nfor fold in range(1):\n    model = TimmSegModel(backbone, pretrained=False)\n    model = convert_3d(model)\n    model = model.to(device)\n    load_model_file = os.path.join(model_dir_seg, f'{kernel_type}_fold{fold}_best.pth.pth.pth')\n    sd = torch.load(load_model_file)\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model.load_state_dict(sd, strict=True)\n    model.eval()\n    models_seg.append(model)\n\nlen(models_seg)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"kernel_type = '0920_1bonev2_convnt_384_15_6ch_augv2_mixupp5_dpr3_drl3_rov1p2_bs21_lr14e6_eta14e6_50ep_ddp'\nmodel_dir_cls = '../input/rsnamodelstoronto/'\nbackbone = 'convnext_tiny_in22ft1k'\nin_chans = 6\nmodels_cls1 = []\nfor fold in range(1):\n    model = Timm1BoneModel(backbone, image_size=384, pretrained=False)\n    load_model_file = os.path.join(model_dir_cls, f'{kernel_type}_fold{fold}_best.pth.pth.pth')\n    sd = torch.load(load_model_file, map_location='cpu')\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model.load_state_dict(sd, strict=True)\n    model = model.to(device)\n    model.eval()\n    models_cls1.append(model)\n\nlen(models_cls1)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"kernel_type = '0920_2d_lstmv22headv2_convnt_384_15_6ch_lossv3_augv2_mixupv3p5_dpr3_drl3_rov1p2_rov3p2_bs4_lr10e6_eta10e6_lw151_50ep_ddp'\nmodel_dir_cls = '../input/rsnamodelstoronto'\nbackbone = 'convnext_tiny_in22ft1k'\nin_chans = 6\nmodels_cls2 = []\nfor fold in range(1):\n    model = TimmModel(backbone, image_size=384, pretrained=False)\n    model = model.to(device)\n    load_model_file = os.path.join(model_dir_cls, f'{kernel_type}_fold{fold}_best.pth.pth.pth')\n    sd = torch.load(load_model_file)\n    if 'model_state_dict' in sd.keys():\n        sd = sd['model_state_dict']\n    sd = {k[7:] if k.startswith('module.') else k: sd[k] for k in sd.keys()}\n    model.load_state_dict(sd, strict=True)\n    model.eval()\n    models_cls2.append(model)\n\nlen(models_cls2)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!nvidia-smi","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_bone(msk, cid, t_paths, cropped_images):\n    n_scans = len(t_paths)\n    bone = []\n    try:\n        msk_b = msk[cid] > 0.2\n        msk_c = msk[cid] > 0.05\n\n        x = np.where(msk_b.sum(1).sum(1) > 0)[0]\n        y = np.where(msk_b.sum(0).sum(1) > 0)[0]\n        z = np.where(msk_b.sum(0).sum(0) > 0)[0]\n\n        if len(x) == 0 or len(y) == 0 or len(z) == 0:\n            x = np.where(msk_c.sum(1).sum(1) > 0)[0]\n            y = np.where(msk_c.sum(0).sum(1) > 0)[0]\n            z = np.where(msk_c.sum(0).sum(0) > 0)[0]\n\n        x1, x2 = max(0, x[0] - 1), min(msk.shape[1], x[-1] + 1)\n        y1, y2 = max(0, y[0] - 1), min(msk.shape[2], y[-1] + 1)\n        z1, z2 = max(0, z[0] - 1), min(msk.shape[3], z[-1] + 1)\n        zz1, zz2 = int(z1 / msk_size * n_scans), int(z2 / msk_size * n_scans)\n\n        inds = np.linspace(zz1 ,zz2-1 ,n_slice_per_c).astype(int)\n        inds_ = np.linspace(z1 ,z2-1 ,n_slice_per_c).astype(int)\n        for sid, (ind, ind_) in enumerate(zip(inds, inds_)):\n\n            msk_this = msk[cid, :, :, ind_]\n\n            images = []\n            for i in range(-n_ch//2+1, n_ch//2+1):\n                try:\n                    dicom = pydicom.read_file(t_paths[ind+i])\n                    images.append(dicom.pixel_array)\n                except:\n                    images.append(np.zeros((512, 512)))\n\n            data = np.stack(images, -1)\n            data = data - np.min(data)\n            data = data / (np.max(data) + 1e-4)\n            data = (data * 255).astype(np.uint8)\n            msk_this = msk_this[x1:x2, y1:y2]\n            xx1 = int(x1 / msk_size * data.shape[0])\n            xx2 = int(x2 / msk_size * data.shape[0])\n            yy1 = int(y1 / msk_size * data.shape[1])\n            yy2 = int(y2 / msk_size * data.shape[1])\n            data = data[xx1:xx2, yy1:yy2]\n            data = np.stack([cv2.resize(data[:, :, i], (image_size_cls, image_size_cls), interpolation = cv2.INTER_LINEAR) for i in range(n_ch)], -1)\n            msk_this = (msk_this * 255).astype(np.uint8)\n            msk_this = cv2.resize(msk_this, (image_size_cls, image_size_cls), interpolation = cv2.INTER_LINEAR)\n\n            data = np.concatenate([data, msk_this[:, :, np.newaxis]], -1)\n\n            bone.append(torch.tensor(data))\n\n    except:\n        for sid in range(n_slice_per_c):\n            bone.append(torch.ones((image_size_cls, image_size_cls, n_ch+1)).int())\n\n    cropped_images[cid] = torch.stack(bone, 0)\n\n\ndef load_cropped_images(msk, image_folder, n_ch=n_ch):\n\n    t_paths = sorted(glob(os.path.join(image_folder, \"*\")), key=lambda x: int(x.split('/')[-1].split(\".\")[0]))\n    for cid in range(7):\n        threads[cid] = threading.Thread(target=load_bone, args=(msk, cid, t_paths, cropped_images))\n        threads[cid].start()\n    for cid in range(7):\n        threads[cid].join()\n\n    return torch.cat(cropped_images, 0)\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Predict","metadata":{}},{"cell_type":"code","source":"outputs1 = []\noutputs2 = []\n\nbar = tqdm(loader_seg)\nwith torch.no_grad():\n    for batch_id, (images) in enumerate(bar):\n        images = images.cuda()\n\n        # SEG\n        pred_masks = []\n        for model in models_seg:\n            pmask = model(images).sigmoid()\n            pred_masks.append(pmask)\n        pred_masks = torch.stack(pred_masks, 0).mean(0).cpu().numpy()\n\n        # Build cls input\n        cls_inp = []\n        threads = [None] * 7\n        cropped_images = [None] * 7\n\n        for i in range(pred_masks.shape[0]):\n            row = df.iloc[batch_id*batch_size_seg+i]\n            cropped_images = load_cropped_images(pred_masks[i], row.image_folder)\n            cls_inp.append(cropped_images.permute(0, 3, 1, 2).float() / 255.)\n        cls_inp = torch.stack(cls_inp, 0).to(device)  # (1, 105, 6, 224, 224)\n\n        pred_cls1, pred_cls2 = [], []\n        # CLS 2\n        for _, model in enumerate(models_cls2):\n            logits, logits2 = model(cls_inp)\n            pred_cls1.append(logits.sigmoid().view(-1, 7, n_slice_per_c))\n            pred_cls2.append(logits2.sigmoid())\n\n        # CLS 1\n        cls_inp = cls_inp.view(7, 15, 6, image_size_cls, image_size_cls).contiguous()\n        for _, model in enumerate(models_cls1):\n            logits = model(cls_inp)\n            pred_cls1.append(logits.sigmoid().view(-1, 7, n_slice_per_c))\n\n        pred_cls1 = torch.stack(pred_cls1, 0).mean(0)\n        pred_cls2 = torch.stack(pred_cls2, 0).mean(0)\n        outputs1.append(pred_cls1.cpu())\n        outputs2.append(pred_cls2.cpu())\n","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Output","metadata":{}},{"cell_type":"code","source":"outputs1 = torch.cat(outputs1)\noutputs2 = torch.cat(outputs2)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"PRED1 = (outputs1.mean(-1)).clamp(0.0001, 0.9999)\nPRED2 = (outputs2.view(-1)).clamp(0.0001, 0.9999)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"row_ids = []\nfor _, row in df.iterrows():\n    for i in range(7):\n        row_ids.append(row.StudyInstanceUID + f'_C{i+1}')\n    row_ids.append(row.StudyInstanceUID + '_patient_overall')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_sub = pd.DataFrame({\n    'row_id': row_ids,\n    'fractured': torch.cat([PRED1, PRED2.unsqueeze(1)], 1).view(-1),\n})","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_sub.to_csv('submission.csv', index=False)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df_sub","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Evaluation","metadata":{}},{"cell_type":"code","source":"bce = nn.BCELoss(reduction='none')\n\ndef criterion(logits, targets):\n    logits = logits.contiguous().view(-1)\n    targets = targets.contiguous().view(-1)\n    losses = bce(logits, targets)\n    losses[targets > 0] *= 2.\n    norm = torch.ones(logits.view(-1).shape[0])\n    norm[targets > 0] *= 2\n    return losses.sum() / norm.sum()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metric_c = criterion(\n    PRED1,\n    torch.tensor(df[['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7']].values).float(),\n)\n\nmetric_a = criterion(\n    PRED2,\n    torch.tensor(df['patient_overall'].values).float(),\n)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"metric_c, metric_a","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"(metric_c + metric_a) / 2","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{},"outputs":[],"execution_count":null}]}