{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"},{"sourceId":197684910,"sourceType":"kernelVersion"},{"sourceId":198302853,"sourceType":"kernelVersion"},{"sourceId":198397448,"sourceType":"kernelVersion"},{"sourceId":198315283,"sourceType":"kernelVersion"}],"dockerImageVersionId":30762,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom torch.utils.data import DataLoader, Dataset\nimport cv2\nimport glob\nimport pydicom\nimport torch\nfrom torch import nn\nimport timm\nimport os\nfrom tqdm import tqdm\nimport albumentations as A\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-09-26T18:17:08.340831Z","iopub.execute_input":"2024-09-26T18:17:08.341137Z","iopub.status.idle":"2024-09-26T18:17:40.126059Z","shell.execute_reply.started":"2024-09-26T18:17:08.341104Z","shell.execute_reply":"2024-09-26T18:17:40.125067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Loading In Our Test Data","metadata":{}},{"cell_type":"code","source":"test_df = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_series_descriptions.csv\")\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:40.127544Z","iopub.execute_input":"2024-09-26T18:17:40.128039Z","iopub.status.idle":"2024-09-26T18:17:40.165865Z","shell.execute_reply.started":"2024-09-26T18:17:40.128004Z","shell.execute_reply":"2024-09-26T18:17:40.165001Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df_st1 = test_df[test_df[\"series_description\"] == \"Sagittal T1\"]\ntest_df_st2 = test_df[test_df[\"series_description\"] == \"Sagittal T2/STIR\"]\ntest_df_at2 = test_df[test_df[\"series_description\"] == \"Axial T2\"]","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:40.166918Z","iopub.execute_input":"2024-09-26T18:17:40.167229Z","iopub.status.idle":"2024-09-26T18:17:40.180242Z","shell.execute_reply.started":"2024-09-26T18:17:40.167197Z","shell.execute_reply":"2024-09-26T18:17:40.179223Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_sub = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/sample_submission.csv\")\nsub_cols = sample_sub.columns[1:]\nprint(sub_cols)\nsample_sub.head()","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:40.183101Z","iopub.execute_input":"2024-09-26T18:17:40.183424Z","iopub.status.idle":"2024-09-26T18:17:40.208363Z","shell.execute_reply.started":"2024-09-26T18:17:40.183389Z","shell.execute_reply":"2024-09-26T18:17:40.207439Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Creating the Dataset Class","metadata":{}},{"cell_type":"code","source":"class RSNADataset(Dataset):\n    def __init__(self, df, transform = None):\n        self.df = df\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        img_paths = []\n        current_df = self.df.iloc[idx]\n        current_study_id = int(current_df[\"study_id\"])\n        \n        for series_id in current_df[[\"series_id\"]]:\n            img_paths.extend(glob.glob(f\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_images/{current_study_id}/{str(int(series_id))}/*.dcm\"))\n        \n        # Currently only looks at the last instance\n        image = np.zeros((512, 512, 10), dtype=np.uint8)\n        \n        # Choose somewhat-evenly spaced instances from the available features\n        n_instances = len(img_paths)\n        n_spaces = n_instances / 10\n        \n        for i, instance_num in enumerate(np.arange(0, n_instances, n_spaces)):\n            instance_num = int(round(instance_num, 0))\n            dicom_data = pydicom.dcmread(img_paths[instance_num])\n            raw_image = dicom_data.pixel_array\n            raw_image = (raw_image - raw_image.min()) / (raw_image.max() - raw_image.min() + 1e-6) * 255\n            resized_image = cv2.resize(raw_image, (512, 512), interpolation=cv2.INTER_CUBIC)\n            image[..., i] = np.array(resized_image).astype(np.uint8)\n        \n        if self.transform is not None:\n            image = self.transform(image=image)[\"image\"]\n            \n        image = image.transpose(2, 0, 1)\n        \n        return image, str(current_study_id)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:40.209716Z","iopub.execute_input":"2024-09-26T18:17:40.210129Z","iopub.status.idle":"2024-09-26T18:17:40.223079Z","shell.execute_reply.started":"2024-09-26T18:17:40.210095Z","shell.execute_reply":"2024-09-26T18:17:40.222127Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_ds = RSNADataset(test_df_st1)\ntest_dl = DataLoader(test_ds, batch_size=1, shuffle=False, num_workers=os.cpu_count(), pin_memory=True, drop_last=False)\n\nfor x, i in test_dl:\n    print(x.shape)\n    print(i)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:40.224472Z","iopub.execute_input":"2024-09-26T18:17:40.225345Z","iopub.status.idle":"2024-09-26T18:17:41.191873Z","shell.execute_reply.started":"2024-09-26T18:17:40.225299Z","shell.execute_reply":"2024-09-26T18:17:41.190746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Transformations","metadata":{}},{"cell_type":"code","source":"transforms_test = A.Compose([\n    A.Resize(512, 512),\n    A.Normalize(mean=0.5, std=0.5)\n])","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:41.193630Z","iopub.execute_input":"2024-09-26T18:17:41.194593Z","iopub.status.idle":"2024-09-26T18:17:41.200878Z","shell.execute_reply.started":"2024-09-26T18:17:41.194542Z","shell.execute_reply":"2024-09-26T18:17:41.199959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Creating the Model Class","metadata":{}},{"cell_type":"code","source":"class RSNAModel(nn.Module):\n    def __init__(self, model_name, in_channels=10, n_classes=30, pretrained=True):\n        super().__init__()\n        self.model = timm.create_model(model_name=model_name, pretrained=pretrained, in_chans=in_channels, num_classes=n_classes)\n        \n    def forward(self, x):\n        y = self.model(x)\n        return y","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:41.202463Z","iopub.execute_input":"2024-09-26T18:17:41.202867Z","iopub.status.idle":"2024-09-26T18:17:41.211828Z","shell.execute_reply.started":"2024-09-26T18:17:41.202811Z","shell.execute_reply":"2024-09-26T18:17:41.210962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda:0') if torch.cuda.is_available() else torch.device('cpu')","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:17:41.213076Z","iopub.execute_input":"2024-09-26T18:17:41.213494Z","iopub.status.idle":"2024-09-26T18:17:41.228462Z","shell.execute_reply.started":"2024-09-26T18:17:41.213450Z","shell.execute_reply":"2024-09-26T18:17:41.227588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Loading In Models","metadata":{}},{"cell_type":"code","source":"st1_models, st2_models, at2_models = [], [], []","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:18:22.303522Z","iopub.execute_input":"2024-09-26T18:18:22.303898Z","iopub.status.idle":"2024-09-26T18:18:22.308400Z","shell.execute_reply.started":"2024-09-26T18:18:22.303861Z","shell.execute_reply":"2024-09-26T18:18:22.307510Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Sagittal T1\nst1_paths = glob.glob(\"/kaggle/input/rsna2024-st1-training-nb/rsna-st1-models/best-st1-*.pt\")\nst1_paths = sorted(st1_paths)\n\n# Sagittal T2\nst2_paths = glob.glob(\"/kaggle/input/rsna2024-st2-training-nb/rsna-st2-models/best-st2-*.pt\")\nst2_paths = sorted(st2_paths)\n\n# Axial T2\nat2_paths = glob.glob(\"/kaggle/input/rsna2024-at2-training-nb/rsna-at2-models/best-at2-*.pt\")\nat2_paths = sorted(at2_paths)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:21:44.150377Z","iopub.execute_input":"2024-09-26T18:21:44.151307Z","iopub.status.idle":"2024-09-26T18:21:44.180374Z","shell.execute_reply.started":"2024-09-26T18:21:44.151269Z","shell.execute_reply":"2024-09-26T18:21:44.179659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"MODEL_NAME = \"tf_efficientnet_b5.ns_jft_in1k\"\n\nfor path in st1_paths:\n    model = RSNAModel(MODEL_NAME, pretrained=False)\n    model.load_state_dict(torch.load(path))\n    model.eval()\n    model.half()\n    model.to(device)\n    st1_models.append(model)\n    \nfor path in st2_paths:\n    model = RSNAModel(MODEL_NAME, n_classes=15, pretrained=False)\n    model.load_state_dict(torch.load(path))\n    model.eval()\n    model.half()\n    model.to(device)\n    st2_models.append(model)\n    \nfor path in at2_paths:\n    model = RSNAModel(MODEL_NAME, pretrained=False)\n    model.load_state_dict(torch.load(path))\n    model.eval()\n    model.half()\n    model.to(device)\n    at2_models.append(model)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:21:48.815435Z","iopub.execute_input":"2024-09-26T18:21:48.815817Z","iopub.status.idle":"2024-09-26T18:22:07.048455Z","shell.execute_reply.started":"2024-09-26T18:21:48.815778Z","shell.execute_reply":"2024-09-26T18:22:07.047523Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference","metadata":{}},{"cell_type":"code","source":"cond_dict = {}\ncond_dict[\"st1\"] = [\"left_neural_foraminal_narrowing\", \"right_neural_foraminal_narrowing\"]\ncond_dict[\"st2\"] = [\"spinal_canal_stenosis\"]\ncond_dict[\"at2\"] = [\"left_subarticular_stenosis\", \"right_subarticular_stenosis\"]\n\nspine_lvls = [\"l1_l2\", \"l2_l3\", \"l3_l4\", \"l4_l5\", \"l5_s1\"]","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:22:07.050087Z","iopub.execute_input":"2024-09-26T18:22:07.050396Z","iopub.status.idle":"2024-09-26T18:22:07.055587Z","shell.execute_reply.started":"2024-09-26T18:22:07.050362Z","shell.execute_reply":"2024-09-26T18:22:07.054651Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_preds = []\nrow_names = []\n\nfor category in [\"st1\", \"st2\", \"at2\"]:\n    autocast = torch.cuda.amp.autocast(enabled=True, dtype=torch.half)\n    n_labels = 10\n    \n    if category == \"st1\":\n        df = test_df_st1\n        models = st1_models\n    elif category == \"st2\":\n        df = test_df_st2\n        models = st2_models\n        n_labels = 5\n    elif category == \"at2\":\n        df = test_df_at2\n        models = at2_models\n        \n    test_ds = RSNADataset(df, transform=transforms_test)\n    test_dl = DataLoader(test_ds, batch_size=1, shuffle=False, num_workers=os.cpu_count(), pin_memory=True, drop_last=False)\n    \n    with tqdm(test_dl, leave=True) as pbar:\n        with torch.no_grad():\n            for idx, (x, study_id) in enumerate(pbar):\n                x = x.to(device).float()\n                if category == \"st2\":\n                    pred_per_study = np.zeros((5, 3))\n                else:\n                    pred_per_study = np.zeros((10, 3))\n            \n                for cond in cond_dict[category]:\n                    for spine_lvl in spine_lvls:\n                        row_names.append(f\"{study_id[0]}_{cond}_{spine_lvl}\")\n                        \n                with autocast:\n                    for model in models:\n                        y = model(x)[0]\n                        for col in range(n_labels):\n                            pred = y[col*3:col*3+3]\n                            y_pred = pred.float().softmax(0).cpu().numpy()\n                            pred_per_study[col] += y_pred / len(models)\n                        \n                    y_preds.append(pred_per_study)\n                    \ny_preds = np.concatenate(y_preds, axis=0)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:22:07.056777Z","iopub.execute_input":"2024-09-26T18:22:07.057070Z","iopub.status.idle":"2024-09-26T18:22:09.268262Z","shell.execute_reply.started":"2024-09-26T18:22:07.057039Z","shell.execute_reply":"2024-09-26T18:22:09.267047Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create the Submission Dataframe","metadata":{}},{"cell_type":"code","source":"submission_df = pd.DataFrame()\nsubmission_df[\"row_id\"] = row_names\nsubmission_df[sub_cols] = y_preds\nsubmission_df = submission_df.groupby(\"row_id\").mean().reset_index()\nsubmission_df.head(25)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:22:09.271167Z","iopub.execute_input":"2024-09-26T18:22:09.271860Z","iopub.status.idle":"2024-09-26T18:22:09.296467Z","shell.execute_reply.started":"2024-09-26T18:22:09.271821Z","shell.execute_reply":"2024-09-26T18:22:09.295492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_df = sample_sub[[\"row_id\"]].merge(submission_df, how=\"left\", on=\"row_id\", validate=\"1:1\").fillna(float(1/3))\nsubmission_df.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:22:16.536581Z","iopub.execute_input":"2024-09-26T18:22:16.537005Z","iopub.status.idle":"2024-09-26T18:22:16.549870Z","shell.execute_reply.started":"2024-09-26T18:22:16.536965Z","shell.execute_reply":"2024-09-26T18:22:16.548988Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"pd.read_csv(\"/kaggle/working/submission.csv\")","metadata":{"execution":{"iopub.status.busy":"2024-09-26T18:22:16.765232Z","iopub.execute_input":"2024-09-26T18:22:16.765796Z","iopub.status.idle":"2024-09-26T18:22:16.782886Z","shell.execute_reply.started":"2024-09-26T18:22:16.765760Z","shell.execute_reply":"2024-09-26T18:22:16.781979Z"},"trusted":true},"execution_count":null,"outputs":[]}]}