{"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":"markdown","source":"# Baseline template for OOP-style inference\n\n* **This pipeline can be a template for your inference engine.**\n* **The pipeline contains handlers for data loading and preprocessing.**\n* **Don't expect to get well metrics using this model.**\n* **If you know some good ideas for optimizing inference, please post them in a comment.**","metadata":{}},{"cell_type":"code","source":"from tqdm import tqdm\nfrom os.path import join\nfrom os import getcwd\nfrom pandas import read_csv, DataFrame\nimport SimpleITK as sitk  # lib for correct loading .dcm images\nfrom torch import cuda, device\nfrom torch import Size, Tensor, no_grad, load\nfrom torch.nn.functional import interpolate\nimport torch.nn as nn\nimport torch.jit as jit\nfrom torch.utils.data import DataLoader\nfrom torchvision.models.densenet import densenet121\nfrom torchvision.transforms import RandomVerticalFlip\n\nKAGGLE_DATA = r'../input/rsna-2022-cervical-spine-fracture-detection'\nKERNEL_TYPE = 'densenet121'\nRESIZE_H = 150\nRESIZE_W = 150\nRESIZE_C = 50\nTEST_BATCH_SIZE = 128\nOUT_DIM = 8\n\ntest_df = read_csv(join(KAGGLE_DATA, \"test.csv\"))\ntest_img_path = join(KAGGLE_DATA, \"test_images\")\n\nprint('test shape:', test_df.shape)","metadata":{"execution":{"iopub.status.busy":"2022-10-13T01:48:53.867249Z","iopub.execute_input":"2022-10-13T01:48:53.867669Z","iopub.status.idle":"2022-10-13T01:48:53.880386Z","shell.execute_reply.started":"2022-10-13T01:48:53.867632Z","shell.execute_reply":"2022-10-13T01:48:53.879311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference pipeline\n\nDefine pipeline objects","metadata":{}},{"cell_type":"code","source":"class CustomDenseNet(nn.Module):\n    def __init__(self, inp_c, count_labels):\n        super(CustomDenseNet, self).__init__()\n        self.prep_layer = nn.Conv2d(in_channels=inp_c, out_channels=3, kernel_size=3, padding='same')\n        self.backbone = densenet121(num_classes=count_labels)\n        self.out = nn.Softmax()\n\n    def forward(self, x):\n        x = self.prep_layer(x)\n        x = self.backbone(x)\n        x = self.out(x)\n        return x\n\n\nclass RSNADataset:\n    def load_data(self):\n        return self.data_path\n\n    def __init__(self, csv_data, img_path, transform=None, target_cols=None, device='cpu'):\n        self.target_cols = target_cols\n        self.img_path = img_path\n        self.device = device\n        self.dataset = csv_data\n        self.transform = transform\n        self.reader = sitk.ImageSeriesReader()\n        self.client_ids = self.dataset['StudyInstanceUID'].tolist()\n\n    def __len__(self):\n        return self.dataset.shape[0]\n\n    def __getitem__(self, index):\n        self.reader.SetFileNames(self.reader.GetGDCMSeriesFileNames(join(self.img_path, self.client_ids[index])))\n        client_imgs = sitk.GetArrayFromImage(\n            sitk.Cast(\n                sitk.RescaleIntensity(self.reader.Execute(), 0, 255),\n                sitk.sitkUInt8\n            )\n        )\n        client_imgs = Tensor(client_imgs).to(self.device)\n        return self.transform(client_imgs), self.dataset.iloc[index, :].to_dict()\n\n\nclass TorchDeviceManager:\n    def __init__(self):\n        self.GPU_DEVICES = {}\n        self.CPU_DEVICE = device('cpu')\n        if cuda.is_available():\n            print('TORCH: CUDA IS AVAILABLE\\nGPU DEVICES:')\n            for i in range(cuda.device_count()):\n                self.GPU_DEVICES[i] = device(f\"cuda:{i}\")\n                print(f\"    {i}: {cuda.get_device_name(self.GPU_DEVICES[i])}\")\n        else:\n            print('TORCH: CUDA IS NOT AVAILABLE')\n\n\nclass ValidationTransforms(nn.Module):\n    def __init__(self, c, h, w):\n        super(ValidationTransforms, self).__init__()\n        self.window = Size([c, h, w])\n\n    def forward(self, x):\n        x = interpolate(x[None, None, :], size=self.window).clamp(min=0, max=255)[0, 0]\n        x /= 255\n        return x\n\n\nclass PipelineRSNA:\n    def __init__(self, test_labels_path=None, test_img_path=None, test_transform=None):\n        self.target_cols = ['C1', 'C2', 'C3', 'C4', 'C5', 'C6', 'C7', 'patient_overall']\n        self.test_cols = ['row_id', 'StudyInstanceUID', 'prediction_type']\n        self.test_transform = test_transform\n        self.target_map = {self.target_cols[i]: i for i in range(len(self.target_cols))}\n        print(f\"Load data from: {test_labels_path}\")\n        self.test_set = read_csv(test_labels_path)\n        self.test_img_path = test_img_path\n\n    def test(self, _device, model_path=None):\n        print(f\"Test: {model_path}\")\n        \n        model = CustomDenseNet(RESIZE_C, OUT_DIM).eval().to(_device)\n        model.load_state_dict(load(model_path, map_location=_device))\n        \n        test_set = RSNADataset(\n            csv_data=self.test_set,\n            img_path=self.test_img_path,\n            transform=self.test_transform,\n            target_cols=self.test_cols,\n            device=device\n        )\n        test_loader = DataLoader(\n            test_set,\n            batch_size=TEST_BATCH_SIZE,\n            shuffle=False,\n            drop_last=False\n        )\n\n        props = []\n        r_names = []\n        with no_grad():\n            for img_batch, meta in tqdm(test_loader):\n                predict = model(img_batch)\n                for b_i, r_name, p in zip(range(img_batch.shape[0]), meta['row_id'], meta['prediction_type']):\n                    r_names.append(r_name)\n                    props.append(predict[b_i, self.target_map[p]].cpu().numpy())\n        DataFrame({'row_id': r_names, 'fractured': props}).to_csv('submission.csv', index=False)\n","metadata":{"execution":{"iopub.status.busy":"2022-10-13T01:48:53.882863Z","iopub.execute_input":"2022-10-13T01:48:53.883557Z","iopub.status.idle":"2022-10-13T01:48:53.905321Z","shell.execute_reply.started":"2022-10-13T01:48:53.883521Z","shell.execute_reply":"2022-10-13T01:48:53.90449Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Running code below will give you the error\n\n\n> ...File names information is empty. Cannot read series\n\nThis is due to a naming error in the example test dataset.\n\nJust ignore it, the submissive will send correctly.","metadata":{"execution":{"iopub.status.busy":"2022-10-13T01:36:06.891303Z","iopub.execute_input":"2022-10-13T01:36:06.892054Z","iopub.status.idle":"2022-10-13T01:36:06.899Z","shell.execute_reply.started":"2022-10-13T01:36:06.892016Z","shell.execute_reply":"2022-10-13T01:36:06.897523Z"}}},{"cell_type":"code","source":"DM = TorchDeviceManager()\ntransform = ValidationTransforms(RESIZE_C, RESIZE_H, RESIZE_W)\n\npipe = PipelineRSNA(\n        test_labels_path=join(KAGGLE_DATA, 'test.csv'),\n        test_img_path=join(KAGGLE_DATA, 'test_images'),\n        test_transform=transform\n    )\n\npipe.test(\n    DM.GPU_DEVICES[0],\n    model_path=r'../input/baseline-pretrained/densenet121_e4.pt'  # Just uploaded trained model as a dataset file\n)","metadata":{"execution":{"iopub.status.busy":"2022-10-13T01:48:53.907741Z","iopub.execute_input":"2022-10-13T01:48:53.908793Z","iopub.status.idle":"2022-10-13T01:48:54.502436Z","shell.execute_reply.started":"2022-10-13T01:48:53.908759Z","shell.execute_reply":"2022-10-13T01:48:54.501068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}