{"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 nibabel\n!pip install pillow-jpls python-gdcm pylibjpeg pylibjpeg-libjpeg pydicom ","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:36:21.286223Z","iopub.execute_input":"2022-09-18T15:36:21.286875Z","iopub.status.idle":"2022-09-18T15:36:45.011664Z","shell.execute_reply.started":"2022-09-18T15:36:21.286774Z","shell.execute_reply":"2022-09-18T15:36:45.010435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install torchvision==0.13.0","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:39:06.720674Z","iopub.execute_input":"2022-09-18T15:39:06.721429Z","iopub.status.idle":"2022-09-18T15:40:19.164234Z","shell.execute_reply.started":"2022-09-18T15:39:06.721389Z","shell.execute_reply":"2022-09-18T15:40:19.162828Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import gc\nimport os\n\nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport pickle\nimport pydicom as dicom\nimport torch\nimport torchvision as tv\n\nimport torchvision.transforms as T\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.model_selection import GroupKFold, KFold\nfrom torch.cuda.amp import GradScaler\nfrom torch.cuda.amp import autocast\nfrom torchvision.models.feature_extraction import create_feature_extractor\nfrom tqdm.notebook import tqdm\n\nimport wandb\n\ntorch.__version__, tv.__version__\n# expected: ('1.12.0+cu102', '0.13.0+cu102')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:40:19.168001Z","iopub.execute_input":"2022-09-18T15:40:19.169018Z","iopub.status.idle":"2022-09-18T15:40:22.486019Z","shell.execute_reply.started":"2022-09-18T15:40:19.168975Z","shell.execute_reply":"2022-09-18T15:40:22.48484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class dict2obj(object):\n    def __init__(self, d):\n        for a, b in d.items():\n            if isinstance(b, (list, tuple)):\n               setattr(self, a, [dict2obj(x) if isinstance(x, dict) else x for x in b])\n            else:\n               setattr(self, a, dict2obj(b) if isinstance(b, dict) else b)\n\n\ncfg = dict(\n    N_FOLDS=5,\n    DATA=dict(\n        TARGET_MODE=\"hard\",\n        TRAIN_IMAGES_PATH='../input/rsna-2022-cervical-spine-fracture-detection/train_images',\n        TEST_IMAGES_PATH='../input/rsna-2022-cervical-spine-fracture-detection/test_images',\n        METADATA_SEGMAP='../input/rsna2022segmappixelcount/meta_segmentation_pixelcount.csv',\n        METADATA_MAX_PIXELCOUNT='../input/rsna2022segmappixelcount/max_pixelcount.pkl',\n    ),\n    DATALOADER=dict(\n        BATCH_SIZE=32,\n    ),\n    MODEL=dict(\n    \n    ),\n    TRAINING=dict(\n        MAX_STEPS=10000,\n        SCHEDULER=dict(\n            ONE_CYCLE_MAX_LR=0.0004,\n            ONE_CYCLE_PCT_START=0.3,\n        ),\n        CHECKPOINT_PATH='../input/vertebrae-detection-checkpoints',\n    ),\n    EVAL=dict(\n        EVAL_EVERY_N_STEP=500,\n        MAX_BATCHES=1000,\n    ),\n    DEVICE=\"cuda\",\n)\n\ncfg = dict2obj(cfg)\ndefault_weight = tv.models.efficientnet.EfficientNet_V2_S_Weights.DEFAULT","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:42:14.654016Z","iopub.execute_input":"2022-09-18T15:42:14.654394Z","iopub.status.idle":"2022-09-18T15:42:14.663932Z","shell.execute_reply.started":"2022-09-18T15:42:14.65436Z","shell.execute_reply":"2022-09-18T15:42:14.662817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom(path):\n    \"\"\"\n    This supports loading both regular and compressed JPEG images. \n    See the first sell with `pip install` commands for the necessary dependencies\n    \"\"\"\n    img=dicom.dcmread(path)\n    img.PhotometricInterpretation = 'YBR_FULL'\n    data = img.pixel_array\n    data = data - np.min(data)\n    if np.max(data) != 0:\n        data = data / np.max(data)\n    data=(data * 255).astype(np.uint8)\n    return cv2.cvtColor(data, cv2.COLOR_GRAY2RGB), img\n\n\nim, meta = load_dicom(f'{cfg.DATA.TRAIN_IMAGES_PATH}/1.2.826.0.1.3680043.10001/1.dcm')\nplt.figure()\nplt.imshow(im)\nplt.title('regular image')\n\nim, meta = load_dicom(f'{cfg.DATA.TRAIN_IMAGES_PATH}/1.2.826.0.1.3680043.10014/1.dcm')\nplt.figure()\nplt.imshow(im)\nplt.title('jpeg')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:42:14.843206Z","iopub.execute_input":"2022-09-18T15:42:14.843909Z","iopub.status.idle":"2022-09-18T15:42:15.459123Z","shell.execute_reply.started":"2022-09-18T15:42:14.843864Z","shell.execute_reply":"2022-09-18T15:42:15.457955Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# assign splits: split\trandom_split\tSliceRatio\n\nimport pandas as pd\ndf_seg = pd.read_csv(cfg.DATA.METADATA_SEGMAP)\n\nsplit = GroupKFold(cfg.N_FOLDS)\nfor k, (train_idx, test_idx) in enumerate(split.split(df_seg, groups=df_seg.StudyInstanceUID)):\n    df_seg.loc[test_idx, 'split'] = k\n\nsplit = KFold(cfg.N_FOLDS)\nfor k, (train_idx, test_idx) in enumerate(split.split(df_seg)):\n    df_seg.loc[test_idx, 'random_split'] = k\n\nslice_max_seg = df_seg.groupby('StudyInstanceUID')['Slice'].max().to_dict()\ndf_seg['SliceRatio'] = 0\ndf_seg['SliceRatio'] = df_seg['Slice'] / df_seg['StudyInstanceUID'].map(slice_max_seg)\n\ndf_seg.sample(10)\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:42:30.272877Z","iopub.execute_input":"2022-09-18T15:42:30.273723Z","iopub.status.idle":"2022-09-18T15:42:30.476999Z","shell.execute_reply.started":"2022-09-18T15:42:30.273689Z","shell.execute_reply":"2022-09-18T15:42:30.475813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class VertebraeSegmentDataSet(torch.utils.data.Dataset):\n    def __init__(self, df, data_cfg, transforms=None, target_mode=None):\n        super().__init__()\n        self.df = df\n        self.img_path = data_cfg.TRAIN_IMAGES_PATH\n        \n        with open(data_cfg.METADATA_MAX_PIXELCOUNT,'rb') as f:\n            self.max_pixelcounts = pickle.load(f)\n\n        self.transforms = transforms\n        if target_mode is None:\n            self.target_mode = data_cfg.TARGET_MODE\n        else:\n            self.target_mode = target_mode\n        \n        self.get_image = True\n    \n    def __getitem__(self, i):\n        r = {}\n        if self.get_image:\n            path = os.path.join(self.img_path, self.df.iloc[i].StudyInstanceUID, f'{self.df.iloc[i].Slice}.dcm')\n            try:\n                img = load_dicom(path)[0]\n                img = np.transpose(img, (2, 0, 1))  # Pytorch uses (batch, channel, height, width) order. Converting (height, width, channel) -> (channel, height, width)\n                if self.transforms is not None:\n                    img = self.transforms(torch.as_tensor(img))\n            except Exception as ex:\n                print(ex)\n                return None\n\n            r[\"images\"] = img\n        if 'C1' in self.df.columns:\n            r[\"target_vert\"] = self.get_target_vert(i)\n        return r\n    \n    def get_target_vert(self, i):\n        targets = self.df.iloc[i][['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7']].astype('float32').values\n        if self.target_mode == \"relative-ratio\":\n            return torch.as_tensor(targets)\n        elif self.target_mode == \"hard\":\n            return torch.as_tensor((targets != 0.0).astype('float32'))\n        elif self.target_mode == \"ratio-to-max\":\n            uid = self.df.iloc[i][\"StudyInstanceUID\"]\n            pixels = self.df.iloc[i][\"pixels\"]\n            return targets * pixels / self.max_pixelcounts[uid]\n        elif self.target_mode == \"segmentation\":\n            # load segmap\n            uid = self.df.iloc[i][\"StudyInstanceUID\"]\n            p = f\"{INPUT_DATA_PATH}/segmentations/{uid}.nii\"\n            example = nib.load(p)\n            return \n        else:\n            raise ValueError(f\"Invalid mode {self.target_mode}\")\n    def __len__(self):\n        return len(self.df)\n\n\ntrn_transform = T.Compose([\n    T.ToTensor(),\n    #T.Normalize([.5, .5, .5], [.25, .25, .25]),\n])\nds_seg = VertebraeSegmentDataSet(\n    df_seg,\n    cfg.DATA,\n    transforms=default_weight.transforms(),\n)\nX = ds_seg[300]\nX[\"images\"].shape, X[\"target_vert\"].shape\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:55:51.977738Z","iopub.execute_input":"2022-09-18T15:55:51.978426Z","iopub.status.idle":"2022-09-18T15:55:52.030405Z","shell.execute_reply.started":"2022-09-18T15:55:51.978391Z","shell.execute_reply":"2022-09-18T15:55:52.02932Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Vis","metadata":{}},{"cell_type":"code","source":"d = []\nds_seg.get_image = False\nfor x in range(500):\n    d.append(np.array(ds_seg[x][\"target_vert\"]))\n    ","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.746052Z","iopub.status.idle":"2022-09-12T14:06:33.747048Z","shell.execute_reply.started":"2022-09-12T14:06:33.74672Z","shell.execute_reply":"2022-09-12T14:06:33.746751Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#target_mode=\"hard\"\nplt.figure(figsize=(15, 4))\nplt.plot(np.array(d))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.748866Z","iopub.status.idle":"2022-09-12T14:06:33.749918Z","shell.execute_reply.started":"2022-09-12T14:06:33.74959Z","shell.execute_reply":"2022-09-12T14:06:33.74962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#target_mode=\"relative-ratio\"\nplt.figure(figsize=(15, 4))\nplt.plot(np.array(d))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.751788Z","iopub.status.idle":"2022-09-12T14:06:33.752768Z","shell.execute_reply.started":"2022-09-12T14:06:33.752448Z","shell.execute_reply":"2022-09-12T14:06:33.752492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#target_mode=\"ratio-to-max\"\nplt.figure(figsize=(15, 4))\nplt.plot(np.array(d))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.754571Z","iopub.status.idle":"2022-09-12T14:06:33.755545Z","shell.execute_reply.started":"2022-09-12T14:06:33.755233Z","shell.execute_reply":"2022-09-12T14:06:33.755263Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# model\n","metadata":{}},{"cell_type":"code","source":"class SegEffnetModel(torch.nn.Module):\n    def __init__(self):\n        super().__init__()\n        effnet = tv.models.efficientnet_v2_s(weights=default_weight)\n        self.model = create_feature_extractor(effnet, ['flatten'])\n        self.nn_vertebrae = torch.nn.Sequential(\n            torch.nn.Linear(1280, 7),\n        )\n\n    def forward(self, x):\n        # returns logits\n        x = self.model(x)['flatten']\n        return self.nn_vertebrae(x)\n\n    def predict(self, x):\n        pred = self.forward(x)\n        return torch.sigmoid(pred)\n\n# quick test\nmodel = SegEffnetModel()\nmodel.predict(torch.randn(1, 3, 512, 512))\ndel model\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:43:17.313677Z","iopub.execute_input":"2022-09-18T15:43:17.314666Z","iopub.status.idle":"2022-09-18T15:43:20.626232Z","shell.execute_reply.started":"2022-09-18T15:43:17.314622Z","shell.execute_reply":"2022-09-18T15:43:20.625149Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gc_collect():\n    gc.collect()\n    torch.cuda.empty_cache()\ndef filter_nones(b):\n    return torch.utils.data.default_collate([v for v in b if v is not None])\ndef save_model(name, model, optim, scheduler):\n    torch.save({\n        'model': model.state_dict(),\n        'optim': optim.state_dict(),\n        'scheduler': scheduler\n    }, f'{name}.tph')\n\ndef load_model(model, name, path='.'):\n    data = torch.load(os.path.join(path, f'{name}.tph'), map_location=cfg.DEVICE)\n    model.load_state_dict(data['model'])\n    optim = torch.optim.Adam(model.parameters())\n    optim.load_state_dict(data['optim'])\n    return model, optim, data['scheduler']\n\n# quick test\nmodel = torch.nn.Linear(2, 1)\noptim = torch.optim.Adam(model.parameters())\nsave_model('testmodel', model, optim, None)\n\nmodel1, optim1, scheduler1 = load_model(torch.nn.Linear(2, 1), 'testmodel')\nassert torch.all(next(iter(model1.parameters())) == next(iter(model.parameters()))).item(), \"Loading/saving is inconsistent!\"\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:43:23.979686Z","iopub.execute_input":"2022-09-18T15:43:23.980365Z","iopub.status.idle":"2022-09-18T15:43:25.928347Z","shell.execute_reply.started":"2022-09-18T15:43:23.98033Z","shell.execute_reply":"2022-09-18T15:43:25.92738Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def evaluate_segeffnet(model: SegEffnetModel, ds, max_batches=1e9, shuffle=False):\n    torch.manual_seed(42)\n    model = model.to(cfg.DEVICE)\n    dl_test = torch.utils.data.DataLoader(\n        ds, \n        batch_size=cfg.DATALOADER.BATCH_SIZE, \n        shuffle=shuffle, \n        num_workers=os.cpu_count(),\n        collate_fn=filter_nones\n    )\n    with torch.no_grad():\n        model.eval()\n        pred = []\n        y = []\n        progress = tqdm(dl_test, desc='Eval', miniters=100)\n        for i, X in enumerate(progress):\n            with autocast():\n                y_vert_pred = model.predict(X[\"images\"].to(cfg.DEVICE))\n            pred.append(y_vert_pred.cpu().numpy())\n            y.append(X[\"target_vert\"].numpy())\n            acc = np.mean(np.mean((pred[-1] > 0.5) == y[-1], axis=0))\n            progress.set_description(f'Eval acc: {acc:.02f}')\n            if i >= max_batches:\n                break\n        pred = np.concatenate(pred)\n        y = np.concatenate(y)\n        # if pred > 0.5 threshold, considered vertebrae\n        acc = np.mean(np.mean((pred > 0.5) == y, axis=0))\n        mae = np.mean(np.mean(np.abs(pred - y), axis=0))\n        return (acc, mae), pred\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:54:51.816304Z","iopub.execute_input":"2022-09-18T15:54:51.816853Z","iopub.status.idle":"2022-09-18T15:54:51.829509Z","shell.execute_reply.started":"2022-09-18T15:54:51.8168Z","shell.execute_reply":"2022-09-18T15:54:51.82821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_vertebrae(df, seg_models):\n    df = df.copy()\n    ds = VertebraeSegmentDataSet(\n            df,\n            cfg.DATA,\n            transforms=default_weight.transforms(),\n    )\n    dl_test = torch.utils.data.DataLoader(\n        ds,\n        batch_size=cfg.DATALOADER.BATCH_SIZE, \n        shuffle=False, \n        num_workers=os.cpu_count(),\n        collate_fn=filter_nones\n    )\n    predictions = []\n    with torch.no_grad():\n        with tqdm(dl_test, desc='Eval', miniters=10) as progress:\n            for i, X in enumerate(progress):\n                X = X[\"images\"]\n                with autocast():\n                    pred = torch.zeros(len(X), 7).to(cfg.DEVICE)\n                    for model in seg_models:\n                        pred += model.predict(X.to(cfg.DEVICE)) / len(seg_models)\n                    predictions.append(pred)\n    predictions = torch.concat(predictions).cpu().numpy()\n    return predictions\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:43:41.719201Z","iopub.execute_input":"2022-09-18T15:43:41.719773Z","iopub.status.idle":"2022-09-18T15:43:41.727924Z","shell.execute_reply.started":"2022-09-18T15:43:41.719708Z","shell.execute_reply":"2022-09-18T15:43:41.726787Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# c2d65ededc510e41ecf954a9cee88af27cf74a3a\n\ndef train_segeffnet(ds_train, ds_eval, logger, name):\n    torch.manual_seed(42)\n    dl_train = torch.utils.data.DataLoader(\n        ds_train,\n        batch_size=cfg.DATALOADER.BATCH_SIZE,\n        shuffle=True,\n        num_workers=os.cpu_count(), \n        collate_fn=filter_nones\n    )\n\n\n    model = SegEffnetModel().to(cfg.DEVICE)\n    optim = torch.optim.Adam(model.parameters())\n    scheduler = torch.optim.lr_scheduler.OneCycleLR(\n        optim,\n        max_lr=cfg.TRAINING.SCHEDULER.ONE_CYCLE_MAX_LR,\n        epochs=1,\n        steps_per_epoch=min(cfg.TRAINING.MAX_STEPS, len(dl_train)),\n        pct_start=cfg.TRAINING.SCHEDULER.ONE_CYCLE_PCT_START\n    )\n    model.train()\n    scaler = GradScaler()\n\n    progress = tqdm(dl_train, desc='Train', miniters=10)\n    for batch_idx, X in enumerate(progress):\n        X,  y_vert = X[\"images\"], X[\"target_vert\"]\n        if batch_idx % cfg.EVAL.EVAL_EVERY_N_STEP == 0 and cfg.EVAL.MAX_BATCHES > 0:\n            eval_loss = evaluate_segeffnet(model, ds_eval, max_batches=cfg.EVAL.MAX_BATCHES, shuffle=True)[0]\n            model.train()\n            if logger is not None:\n                logger.log({'eval_acc': eval_loss[0], 'eval_mae': eval_loss[1]})\n            if batch_idx > 0:  # don't save untrained model\n                save_model(name, model, optim, scheduler)\n\n        if batch_idx >= cfg.TRAINING.MAX_STEPS:\n            break\n\n        optim.zero_grad()\n        with autocast():\n            y_vert_pred = model.forward(X.to(cfg.DEVICE))\n            loss = torch.nn.functional.binary_cross_entropy_with_logits(y_vert_pred, y_vert.to(cfg.DEVICE))\n\n            if np.isinf(loss.item()) or np.isnan(loss.item()):\n                print(f'Bad loss, skipping the batch {batch_idx}')\n                del y_vert_pred, loss\n                gc_collect()\n                continue\n\n        scaler.scale(loss).backward()\n        scaler.step(optim)\n        scaler.update()\n        scheduler.step()\n\n        progress.set_description(f'Train loss: {loss.item():.02f}')\n        if logger is not None:\n            logger.log({'loss': loss.item(), 'lr': scheduler.get_last_lr()[0]})\n\n\n    eval_loss = evaluate_segeffnet(model, ds_eval, max_batches=cfg.EVAL.MAX_BATCHES, shuffle=True)[0]\n    if logger is not None:\n        logger.log({'eval_acc': eval_loss[0], 'eval_mae': eval_loss[1]})\n\n    save_model(name, model, optim, scheduler)\n    return model\n\n\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:43:49.754701Z","iopub.execute_input":"2022-09-18T15:43:49.7551Z","iopub.status.idle":"2022-09-18T15:43:49.770278Z","shell.execute_reply.started":"2022-09-18T15:43:49.755069Z","shell.execute_reply":"2022-09-18T15:43:49.769329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%wandb\nseg_models = []\nfold=0\nfname = os.path.join(f'{cfg.TRAINING.CHECKPOINT_PATH}/segeffnetv2-f{fold}.tph')\nif os.path.exists(fname):\n    print(f'Found cached model {fname}')\n    seg_models.append(load_model(\n        SegEffnetModel(),\n        f'segeffnetv2-f{fold}', cfg.TRAINING.CHECKPOINT_PATH)[0].to(cfg.DEVICE)\n    )\nelse:\n    with wandb.init(project='RSNA-2022', name=f'SegEffNet-v2-fold{fold}') as run:\n        gc_collect()\n        ds_train = VertebraeSegmentDataSet(\n            df_seg,#.query('split != @fold'),\n            cfg.DATA,\n            transforms=default_weight.transforms(),\n        )\n        ds_eval = VertebraeSegmentDataSet(\n            df_seg.query('split == @fold'),\n            cfg.DATA,\n            transforms=default_weight.transforms(),\n            target_mode=\"hard\"\n        )\n        seg_models.append(train_segeffnet(ds_train, ds_eval, run, f'segeffnetv2-f{fold}'))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T15:56:04.827506Z","iopub.execute_input":"2022-09-18T15:56:04.827898Z","iopub.status.idle":"2022-09-18T16:13:13.09854Z","shell.execute_reply.started":"2022-09-18T15:56:04.827859Z","shell.execute_reply":"2022-09-18T16:13:13.097555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fold, model = (0, seg_models[0])\nds = VertebraeSegmentDataSet(\n    df_seg.query('split == @fold'),\n    cfg.DATA,\n    transforms=default_weight.transforms(),\n    target_mode=\"hard\"\n)\nacc, pred = evaluate_segeffnet(model, ds, max_batches=1e9, shuffle=False)\ndf_seg.loc[df_seg[df_seg.split == fold].index, ['C1_pred', 'C2_pred', 'C3_pred', 'C4_pred', 'C5_pred', 'C6_pred', 'C7_pred']] = pred\nprint(f'Acc: {acc[0]}      mae: {acc[1]}')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-18T16:13:13.105375Z","iopub.execute_input":"2022-09-18T16:13:13.107605Z","iopub.status.idle":"2022-09-18T16:14:43.022886Z","shell.execute_reply.started":"2022-09-18T16:13:13.107563Z","shell.execute_reply":"2022-09-18T16:14:43.021292Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train","metadata":{"execution":{"iopub.status.busy":"2022-09-18T16:20:07.145832Z","iopub.execute_input":"2022-09-18T16:20:07.146204Z","iopub.status.idle":"2022-09-18T16:20:07.167937Z","shell.execute_reply.started":"2022-09-18T16:20:07.146174Z","shell.execute_reply":"2022-09-18T16:20:07.166802Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_train_clean_path = \"../input/rsna-2022-spine-fracture-detection-metadata/meta_train_clean.csv\"\n\npred = predict_vertebrae(df_train.query('StudyInstanceUID == @uid'), seg_models[:2])\n\ndf_train = pd.read_csv(meta_train_clean_path)\n\ndf_train[[f'C{i}' for i in range(1, 8)]] = pred\ndf_train.to_csv('train_segmented.csv', index=False)\n\ndf_train","metadata":{"execution":{"iopub.status.busy":"2022-09-18T16:19:53.420448Z","iopub.execute_input":"2022-09-18T16:19:53.421015Z","iopub.status.idle":"2022-09-18T16:19:54.058124Z","shell.execute_reply.started":"2022-09-18T16:19:53.420981Z","shell.execute_reply":"2022-09-18T16:19:54.056581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfor uid in [\"1.2.826.0.1.3680043.10633\", \"1.2.826.0.1.3680043.1480\", \"1.2.826.0.1.3680043.9926\"]:\n    pred = predict_vertebrae(df_train.query('StudyInstanceUID == @uid'), seg_models)\n    plt.figure(figsize=(20, 5))\n    plt.plot(pred)\n    plt.title(f'Vertebrae prediction by slice for UID: {uid}')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-14T07:58:30.639577Z","iopub.status.idle":"2022-09-14T07:58:30.640304Z","shell.execute_reply.started":"2022-09-14T07:58:30.640046Z","shell.execute_reply":"2022-09-14T07:58:30.640071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%wandb\nseg_models = []\nfold=0\nfname = os.path.join(f'{cfg.TRAINING.CHECKPOINT_PATH}/segeffnetv2-f{fold}.tph')\nif os.path.exists(fname):\n    print(f'Found cached model {fname}')\n    seg_models.append(load_model(SegEffnetModel(), f'segeffnetv2-f{fold}', cfg.TRAINING.CHECKPOINT_PATH)[0].to(cfg.DEVICE))\nelse:\n    with wandb.init(project='RSNA-2022', name=f'SegEffNet-v2-fold{fold}') as run:\n        gc_collect()\n        ds_train = VertebraeSegmentDataSet(\n            df_seg.query('split != @fold'),\n            cfg.DATA,\n            transforms=default_weight.transforms(),\n            target_mode=\"ratio-to-max\"\n        )\n        ds_eval = VertebraeSegmentDataSet(\n            df_seg.query('split == @fold'),\n            cfg.DATA,\n            transforms=default_weight.transforms(),\n            target_mode=\"hard\"\n        )\n        seg_models.append(train_segeffnet(ds_train, ds_eval, run, f'segeffnetv2-f{fold}'))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-14T07:58:30.642695Z","iopub.status.idle":"2022-09-14T07:58:30.643815Z","shell.execute_reply.started":"2022-09-14T07:58:30.643508Z","shell.execute_reply":"2022-09-14T07:58:30.643532Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seg_models[0] == _seg_models[0]","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:49:11.341361Z","iopub.execute_input":"2022-09-13T12:49:11.341778Z","iopub.status.idle":"2022-09-13T12:49:11.351014Z","shell.execute_reply.started":"2022-09-13T12:49:11.341739Z","shell.execute_reply":"2022-09-13T12:49:11.349837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fold, model = (0, _seg_models[0])\nds = VertebraeSegmentDataSet(\n    df_seg.query('split == @fold'),\n    cfg.DATA,\n    transforms=default_weight.transforms(),\n    target_mode=\"hard\"\n)\nacc, pred = evaluate_segeffnet(model, ds, max_batches=1e9, shuffle=False)\ndf_seg.loc[df_seg[df_seg.split == fold].index, ['C1_pred', 'C2_pred', 'C3_pred', 'C4_pred', 'C5_pred', 'C6_pred', 'C7_pred']] = pred\nprint(f'Acc: {acc[0]}      mae: {acc[1]}')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:49:14.300742Z","iopub.execute_input":"2022-09-13T12:49:14.301227Z","iopub.status.idle":"2022-09-13T12:50:40.247535Z","shell.execute_reply.started":"2022-09-13T12:49:14.301184Z","shell.execute_reply":"2022-09-13T12:50:40.246337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"acc = (df_seg[[f'C{i}_pred' for i in range(1, 8)]] > 0.5).values == (df_seg[[f'C{i}' for i in range(1, 8)]] > 0.5).values\nprint('Effnetv2 accuracy per vertebrae', np.mean(acc, axis=0))\nprint('Effnetv2 average accuracy', np.mean(np.mean(acc, axis=0)))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:34:58.586788Z","iopub.execute_input":"2022-09-13T12:34:58.58796Z","iopub.status.idle":"2022-09-13T12:34:58.600069Z","shell.execute_reply.started":"2022-09-13T12:34:58.587902Z","shell.execute_reply":"2022-09-13T12:34:58.598858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_train.query('StudyInstanceUID == @uid'),\nMETADATA_PATH = '../input/rsna-2022-spine-fracture-detection-metadata'\n\ndf_train = pd.read_csv(os.path.join(METADATA_PATH, 'meta_train_clean.csv'))\n","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:34:58.601375Z","iopub.execute_input":"2022-09-13T12:34:58.602492Z","iopub.status.idle":"2022-09-13T12:34:59.102427Z","shell.execute_reply.started":"2022-09-13T12:34:58.602456Z","shell.execute_reply":"2022-09-13T12:34:59.101434Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nfor uid in [\"1.2.826.0.1.3680043.10633\", \"1.2.826.0.1.3680043.1480\", \"1.2.826.0.1.3680043.9926\"]:\n    pred = predict_vertebrae(df_train.query('StudyInstanceUID == @uid'), seg_models)\n    plt.figure(figsize=(20, 5))\n    plt.plot(pred)\n    plt.title(f'Vertebrae prediction by slice for UID: {uid}')\n","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:34:59.104687Z","iopub.execute_input":"2022-09-13T12:34:59.105125Z","iopub.status.idle":"2022-09-13T12:35:20.914072Z","shell.execute_reply.started":"2022-09-13T12:34:59.105082Z","shell.execute_reply":"2022-09-13T12:35:20.912938Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:44:32.890338Z","iopub.execute_input":"2022-09-13T12:44:32.891019Z","iopub.status.idle":"2022-09-13T12:44:32.899Z","shell.execute_reply.started":"2022-09-13T12:44:32.890982Z","shell.execute_reply":"2022-09-13T12:44:32.897977Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(\"../input/rsna2022segmappixelcount/max_pixelcount.pkl\", \"rb\") as f:\n    meta = pickle.load(f)\n    \ndef plot_vertebrae(meta_seg, uid):\n    gt = meta_seg[meta_seg['StudyInstanceUID'] == uid]\n\n    plt.figure(figsize=(20, 5))\n    for x in range(1, 7 + 1):\n        plt.plot(np.arange(len(gt)), gt[f\"C{x}\"] * gt[\"pixels\"] / meta[uid][x-1])\n    plt.title(f\"Vertebrae distribution(pixel): {uid}\")\n    plt.show()\n\nplot_vertebrae(df_seg, \"1.2.826.0.1.3680043.10633\")\nplot_vertebrae(df_seg, \"1.2.826.0.1.3680043.1480\")\nplot_vertebrae(df_seg, \"1.2.826.0.1.3680043.9926\")","metadata":{"execution":{"iopub.status.busy":"2022-09-13T12:45:27.251011Z","iopub.execute_input":"2022-09-13T12:45:27.251446Z","iopub.status.idle":"2022-09-13T12:45:28.080833Z","shell.execute_reply.started":"2022-09-13T12:45:27.251399Z","shell.execute_reply":"2022-09-13T12:45:28.079901Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for x in seg_models:\n    x.eval()","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pred = predict_vertebrae(df_train, seg_models)\n\ndf_train[[f'C{i}' for i in range(1, 8)]] = pred\ndf_train.to_csv('train_segmented.csv', index=False)\n\n# you can find checkpoints along with the output dataset in https://www.kaggle.com/datasets/vslaykovsky/vertebrae-detection-checkpoints\n","metadata":{"execution":{"iopub.status.busy":"2022-09-13T13:26:24.058727Z","iopub.execute_input":"2022-09-13T13:26:24.059187Z","iopub.status.idle":"2022-09-13T13:27:40.737173Z","shell.execute_reply.started":"2022-09-13T13:26:24.059149Z","shell.execute_reply":"2022-09-13T13:27:40.733166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"for uid in [\"1.2.826.0.1.3680043.10633\", \"1.2.826.0.1.3680043.1480\", \"1.2.826.0.1.3680043.9926\"]:\n    print(df_seg[df_seg[\"StudyInstanceUID\"] == uid][\"split\"])","metadata":{"execution":{"iopub.status.busy":"2022-09-13T13:36:01.05128Z","iopub.execute_input":"2022-09-13T13:36:01.051893Z","iopub.status.idle":"2022-09-13T13:36:01.072891Z","shell.execute_reply.started":"2022-09-13T13:36:01.051856Z","shell.execute_reply":"2022-09-13T13:36:01.071694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import nibabel as nib\nsegmentations = nib.load(f\"../input/rsna-2022-cervical-spine-fracture-detection/segmentations/1.2.826.0.1.3680043.10921.nii\").get_fdata()[:, ::-1, ::-1].transpose(2, 1, 0)\n\nimport matplotlib.pyplot as plt\n\nfor x in segmentations:\n    print(np.unique(x))\n    if len(np.unique(x)) == 3:\n        plt.imshow(x)\n        plt.show()\n# bone C6\n\"\"\"\nSo, lets analyse the current situation, we have 87 patients studies for segmentation, we will have to learn from these patients, \nwhich bone is presented in which image, BUT, why is knowing which image is which bone so important? Answering this question takes\nus to the last part of this discussion, which is, Submission.\n\nThe submission file will in the format where each patient will have 8 rows, and 8 predictions, 7 rows for C1-C7 and the last row\nfor overall, overall refers to weather the patient have a fracture in any one of the vertibrates are fractured.\n\n**cross validation with grouping by StudyInstanceUID\n\n\"\"\"","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.794515Z","iopub.status.idle":"2022-09-12T14:06:33.795604Z","shell.execute_reply.started":"2022-09-12T14:06:33.795255Z","shell.execute_reply":"2022-09-12T14:06:33.795289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"segmentations.shape","metadata":{"execution":{"iopub.status.busy":"2022-09-12T14:06:33.797577Z","iopub.status.idle":"2022-09-12T14:06:33.798647Z","shell.execute_reply.started":"2022-09-12T14:06:33.798294Z","shell.execute_reply":"2022-09-12T14:06:33.798327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}