{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":9297927,"sourceType":"datasetVersion","datasetId":5247413},{"sourceId":14156754,"sourceType":"datasetVersion","datasetId":9023231},{"sourceId":14157985,"sourceType":"datasetVersion","datasetId":9024033},{"sourceId":14167439,"sourceType":"datasetVersion","datasetId":9030642},{"sourceId":14168727,"sourceType":"datasetVersion","datasetId":9031469},{"sourceId":14167355,"sourceType":"datasetVersion","datasetId":9030587}],"dockerImageVersionId":30733,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"\n!pip install /kaggle/input/rsna-monai-pydicom-nibabel-wheels/monai-1.3.1-py3-none-any.whl\n!pip install /kaggle/input/rsna-monai-pydicom-nibabel-wheels/pydicom-2.4.4-py3-none-any.whl\n!pip install /kaggle/input/rsna-monai-pydicom-nibabel-wheels/nibabel-5.2.1-py3-none-any.whl","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2025-12-15T21:25:45.504721Z","iopub.execute_input":"2025-12-15T21:25:45.505530Z","iopub.status.idle":"2025-12-15T21:27:47.612175Z","shell.execute_reply.started":"2025-12-15T21:25:45.505500Z","shell.execute_reply":"2025-12-15T21:27:47.611289Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install /kaggle/input/rsna-monai-pydicom-nibabel-wheels/typed_argument_parser-1.10.1-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:27:47.614244Z","iopub.execute_input":"2025-12-15T21:27:47.614532Z","iopub.status.idle":"2025-12-15T21:28:28.280539Z","shell.execute_reply.started":"2025-12-15T21:27:47.614508Z","shell.execute_reply":"2025-12-15T21:28:28.279673Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\nimport os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nfrom torch.optim.lr_scheduler import CosineAnnealingLR\nimport numpy as np\nimport pandas as pd\nimport pandas.api.types\nimport sklearn.metrics\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport tqdm\nimport monai\nfrom monai.transforms import (\n    CastToTyped,\n    CenterScaleCropd,\n    Compose,\n    CropForeground,\n    CropForegroundd,\n    EnsureChannelFirstd,\n    InvertibleTransform,\n    LoadImaged,\n    MapTransform,\n    RandCropByPosNegLabel,\n    RandCropByPosNegLabeld,\n    RandFlipd,\n    RandGaussianNoised,\n    RandGridDistortiond,\n    Resize,\n    Resized,\n    Spacing,\n    Spacingd,\n    SpatialCrop,\n    SpatialPad,\n    SpatialPadd,\n    ToTensord,\n    TraceableTransform,\n)\nimport itertools\nfrom collections.abc import Sequence\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.utils.checkpoint as checkpoint\nfrom torch.nn import LayerNorm\nfrom typing_extensions import Final\nfrom sklearn.model_selection import train_test_split\n\nfrom monai.networks.blocks import MLPBlock as Mlp\nfrom monai.networks.blocks import PatchEmbed, UnetOutBlock, UnetrBasicBlock, UnetrUpBlock\nfrom monai.networks.layers import DropPath, trunc_normal_\nfrom monai.utils import ensure_tuple_rep, look_up_option, optional_import\nfrom monai.utils.deprecate_utils import deprecated_arg\nfrom monai.networks.nets.swin_unetr import SwinTransformer, MERGING_MODE\n\nfrom monai.networks.nets import SEResNet50, SEResNet101, SEResNext101\nfrom monai.networks.blocks.squeeze_and_excitation import SEBottleneck, SEResNetBottleneck","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.282073Z","iopub.execute_input":"2025-12-15T21:28:28.282440Z","iopub.status.idle":"2025-12-15T21:28:28.292256Z","shell.execute_reply.started":"2025-12-15T21:28:28.282407Z","shell.execute_reply":"2025-12-15T21:28:28.291400Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#đã sửa model path\nMODEL_PATH = \"/kaggle/input/checkpoint-data\"\n","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.294014Z","iopub.execute_input":"2025-12-15T21:28:28.294247Z","iopub.status.idle":"2025-12-15T21:28:28.307145Z","shell.execute_reply.started":"2025-12-15T21:28:28.294228Z","shell.execute_reply":"2025-12-15T21:28:28.306382Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tap import Tap\n\nclass SimpleArgumentParser(Tap):\n    workdir = \"./workdir\"\n    task_name = \"SEResNext101_custom_[no_resample]_[augs1]_32x128x256_[v2]\"\n    project_name = \"kaggle_rsna2024\"\n    data_dir = \"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification\"\n    eval_before_training = False\n\n    # model config\n    in_channels=1\n    spatial_dims=3\n    layers=(3, 4, 23, 3)\n    dropout_prob=0.2\n    inplanes=64\n    model_name = \"SEResNext101_custom\"\n    checkpoint = \"/mnt/sda/RSNA_2024/workdir/SEResNext101_custom_[no_resample]_[augs1]_32x128x256/model_best.pth\"\n\n    # data config\n    modality = \"Sagittal T2/STIR\"\n    test_size = 0.2\n    random_state = 42\n    batch_size = 3\n    num_workers = 0\n    image_size = (32, 128, 256) # (384, 384)\n    resample_z_slices = None\n    cache_dir = \"cache_dir_[no_resample]_32x128x256\"\n\n    # train config\n    epochs = 50\n    accumulation_steps = 2  # Number of batches to accumulate gradients\n    label_smoothing_epsilon = 0.01\n    lr = 0.001\n    class_weights = [1.0, 2.0, 4.0]\n\nargs = SimpleArgumentParser()\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.308084Z","iopub.execute_input":"2025-12-15T21:28:28.308372Z","iopub.status.idle":"2025-12-15T21:28:28.320096Z","shell.execute_reply.started":"2025-12-15T21:28:28.308346Z","shell.execute_reply":"2025-12-15T21:28:28.319464Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nclass CropBySpineMRI(monai.transforms.MapTransform):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n\n\n    def crop_volume_by_black_border(self, vol, threshold=30):\n        \"\"\"\n        Crops the input volume along the h axis based on the given threshold.\n        \n        Parameters:\n        vol (np.ndarray): Input volume with shape (d, h, w)\n        threshold (float): Threshold value for cropping (default is 50)\n        \n        Returns:\n        np.ndarray: Cropped volume\n        \"\"\"\n\n        def crop_by_h(vol, thr):\n            # Compute the mean along the h axis\n            means = np.mean(vol, axis=(0, 2))\n            \n            # Apply the threshold\n            above_threshold = means > thr\n            \n            # Find the first and last indices where the condition is True\n            start = np.argmax(above_threshold)\n            end = len(above_threshold) - np.argmax(above_threshold[::-1])\n            \n            # Crop the volume\n            cropped_vol = vol[:, start:end, :]\n            \n            return cropped_vol\n\n        def crop_by_w(vol, thr):\n            # Compute the mean along the h axis\n            means = np.mean(vol, axis=(0, 1))\n            \n            # Apply the threshold\n            above_threshold = means > thr\n            \n            # Find the first and last indices where the condition is True\n            start = np.argmax(above_threshold)\n            end = len(above_threshold) - np.argmax(above_threshold[::-1])\n            \n            # Crop the volume\n            cropped_vol = vol[:, :, start:end]\n            \n            return cropped_vol\n\n        vol = crop_by_h(vol, threshold)\n        vol = crop_by_w(vol, threshold)\n        return vol\n\n    def __call__(self, data):\n        d = dict(data)\n        for key in self.keys:\n            img = d[key]\n            dim = len(img.shape)\n\n            if dim == 4:\n                img = np.squeeze(img, axis=0)\n\n            # Assuming img has shape (D, H, W)\n            new_img = self.crop_volume_by_black_border(img)\n            _, h, w = new_img.shape\n\n            if key == \"Sagittal T1\":\n                new_img = new_img[:, int(h * 0.3):int(h * 0.7), :]\n            elif key == \"Sagittal T2/STIR\":\n                new_img = new_img[:, int(h * 0.3):int(h * 0.7), :]\n            elif key == \"Axial T2\":\n                pass\n            else:\n                raise ValueError(f\"{key} not modality\")\n\n            if dim == 4:\n                new_img = np.expand_dims(new_img, axis=0)\n\n            d[key] = new_img\n\n        return d\n\n\nclass ExpandChannelFirstd(monai.transforms.MapTransform):\n    def __init__(self, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n\n    def __call__(self, data):\n        d = dict(data)\n\n        for key in self.keys:\n            img = d[key]\n            dim = len(img.shape)\n            # Assuming img has shape (D, H, W)\n\n            if dim == 3 and args.spatial_dims == 3:\n                img = img.unsqueeze(0)\n\n            d[key] = img\n\n        return d\n    \n\nclass ResampleZ(monai.transforms.MapTransform):\n    def __init__(self, new_depth, *args, **kwargs):\n        super().__init__(*args, **kwargs)\n        self.new_depth = new_depth\n\n    def __call__(self, data):\n        d = dict(data)\n\n        if self.new_depth is None:\n            return d\n\n        for key in self.keys:\n            img = d[key]\n            dim = len(img.shape)\n            # Assuming img has shape (D, H, W)\n            if dim == 3:\n                _, h, w = img.shape\n                # Add channel dimension (C, D, H, W) where C=1\n                img = img.unsqueeze(0)\n            else:\n                _, _, h, w = img.shape\n\n            # Interpolate\n            img = F.interpolate(img.unsqueeze(0), size=(self.new_depth, h, w), mode='trilinear', align_corners=False)\n\n            # Remove added dimensions\n            if dim == 3:\n                img = img.squeeze(0).squeeze(0)\n\n            d[key] = img\n\n        return d\n\n\nclass RSNADataset(monai.data.Dataset):\n    def __init__(self, df=None, train_series_descriptions=None, is_train=True, cache_dir=None, hash_func=None):\n        self.is_train = is_train\n        self.df = df\n        self.cache_dir = cache_dir\n        self.hash_func = hash_func\n        \n        if is_train:\n            self.study_ids = list(set(df['study_id'].values.tolist()))\n        else:\n            self.study_ids = list(set(train_series_descriptions['study_id'].values.tolist()))\n\n        self.train_series_descriptions = train_series_descriptions\n        self.labels = [\n            'spinal_canal_stenosis_l1_l2',\n            'spinal_canal_stenosis_l2_l3',\n            'spinal_canal_stenosis_l3_l4',\n            'spinal_canal_stenosis_l4_l5',\n            'spinal_canal_stenosis_l5_s1',\n            'left_neural_foraminal_narrowing_l1_l2',\n            'left_neural_foraminal_narrowing_l2_l3',\n            'left_neural_foraminal_narrowing_l3_l4',\n            'left_neural_foraminal_narrowing_l4_l5',\n            'left_neural_foraminal_narrowing_l5_s1',\n            'right_neural_foraminal_narrowing_l1_l2',\n            'right_neural_foraminal_narrowing_l2_l3',\n            'right_neural_foraminal_narrowing_l3_l4',\n            'right_neural_foraminal_narrowing_l4_l5',\n            'right_neural_foraminal_narrowing_l5_s1',\n            'left_subarticular_stenosis_l1_l2', \n            'left_subarticular_stenosis_l2_l3',\n            'left_subarticular_stenosis_l3_l4', \n            'left_subarticular_stenosis_l4_l5',\n            'left_subarticular_stenosis_l5_s1', \n            'right_subarticular_stenosis_l1_l2',\n            'right_subarticular_stenosis_l2_l3',\n            'right_subarticular_stenosis_l3_l4',\n            'right_subarticular_stenosis_l4_l5',\n            'right_subarticular_stenosis_l5_s1'\n        ]\n        self.target_mapping = {\n            \"Normal/Mild\": [1, 0, 0],\n            \"Moderate\":[0, 1, 0],\n            \"Severe\": [0, 0, 1]\n        }\n        self.ss_mapping = {\n            0: \"normal_mild\", 1: \"moderate\", 2: \"severe\"\n        }\n        self.data_dir = args.data_dir\n        self.transform = self.get_transform()\n\n    def __len__(self):\n        return len(self.study_ids)\n\n    def __getitem__(self, index):\n        study_id = self.study_ids[index]\n        series_descriptions = self.train_series_descriptions.loc[self.train_series_descriptions.study_id == study_id]  # series_id, series_description\n\n        data = {}\n        data[\"study_id\"] = str(study_id)\n\n        if self.cache_dir:\n            fpath_hash = self.hash_func(data).decode(\"utf-8\")\n            hashfile = os.path.join(self.cache_dir, f\"{fpath_hash}.pt\")\n            if os.path.isfile(hashfile):\n                return data\n\n        for series_id, series_description in series_descriptions[[\"series_id\", \"series_description\"]].values:\n            if series_description == args.modality:\n\n                if self.is_train:\n                    path_to_dicom_dir = f\"{self.data_dir}/train_images/{study_id}/{series_id}\"\n                else:\n                    path_to_dicom_dir = f\"{self.data_dir}/test_images/{study_id}/{series_id}\"\n                # dicom = self.apply_transform(path_to_dicom_dir)\n                # data[series_description] = dicom\n\n                data[series_description] = path_to_dicom_dir\n        \n        if self.is_train:\n            data[\"target\"] = self.target_processing(index)\n\n        return data\n    \n    def target_processing(self, index):\n        row = self.df.iloc[[index]]\n        \n        data = []\n        for label in self.labels:\n            severity = row[[label]].values[0][0]\n            target = self.target_mapping[severity]\n            data.append(target)\n            \n        return np.asarray(data)\n\n    def apply_transform(self, path_to_dicom_dir):\n        return self.transform(path_to_dicom_dir)\n\n    def get_transform(self):\n        return monai.transforms.Compose([\n            monai.transforms.LoadImaged(keys=[args.modality]),\n            monai.transforms.EnsureChannelFirstd(keys=[args.modality], channel_dim=-1),\n            ResampleZ(keys=[args.modality], new_depth=args.resample_z_slices),\n            CropBySpineMRI(keys=[args.modality]),\n            ExpandChannelFirstd(keys=[args.modality]),\n            monai.transforms.Resized(keys=[args.modality], spatial_size=args.image_size, mode='trilinear'),\n            monai.transforms.NormalizeIntensityd(keys=[args.modality]),\n            monai.transforms.ToTensord(keys=[args.modality])\n        ])\n\ndef get_dataset(df, train_series_descriptions, is_train=True):\n    ds = RSNADataset(\n        df=df, \n        train_series_descriptions=train_series_descriptions, \n        is_train=is_train, \n        cache_dir=args.cache_dir,\n        hash_func=f_name_hash\n    )\n\n    if args.cache_dir is not None:\n        return monai.data.PersistentDataset(\n            data=ds,\n            transform=ds.get_transform(),\n            cache_dir=args.cache_dir,\n            hash_func=f_name_hash,\n        )\n    else:\n        return monai.data.Dataset(data=ds, transform=ds.get_transform())","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.321064Z","iopub.execute_input":"2025-12-15T21:28:28.321289Z","iopub.status.idle":"2025-12-15T21:28:28.349369Z","shell.execute_reply.started":"2025-12-15T21:28:28.321271Z","shell.execute_reply":"2025-12-15T21:28:28.348423Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SEResNext101_custom(SEResNext101):\n    def __init__(\n        self,\n        in_channels=args.in_channels,\n        spatial_dims=args.spatial_dims,\n        dropout_prob=args.dropout_prob,\n        **kwargs,\n    ):\n        super().__init__(\n            in_channels=in_channels,\n            spatial_dims=spatial_dims,\n            dropout_prob=dropout_prob,\n            num_classes=75,\n            **kwargs,\n        )\n\n    def forward(self, x: torch.Tensor) -> torch.Tensor:\n        x = self.features(x)\n        x = self.logits(x)\n        x = x.view(x.size(0), 25, 3)\n        return x\n\n\ndef load_net():\n    if args.model_name == \"SEResNext101_custom\":\n        net = SEResNext101_custom(\n            in_channels=args.in_channels,\n            spatial_dims=args.spatial_dims,\n        )\n    return net","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.350353Z","iopub.execute_input":"2025-12-15T21:28:28.350617Z","iopub.status.idle":"2025-12-15T21:28:28.361664Z","shell.execute_reply.started":"2025-12-15T21:28:28.350597Z","shell.execute_reply":"2025-12-15T21:28:28.360942Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# net = SEResNet50Custom(in_channels=1, spatial_dims=2, layers=(3, 4, 6, 3), dropout_prob=0.2, inplanes=64)\nnet = load_net()\n\n# net = torch.nn.DataParallel(net)\nnet.load_state_dict(torch.load(os.path.join(MODEL_PATH, \"model_best.pth\"), map_location=\"cpu\")[\"state_dict\"])\nnet = net.to(device)\n\nif device == 'cuda':\n    net = torch.compile(net)\n    net(torch.randn(1, 224, 224).to(device))","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:28.362739Z","iopub.execute_input":"2025-12-15T21:28:28.363315Z","iopub.status.idle":"2025-12-15T21:28:31.291726Z","shell.execute_reply.started":"2025-12-15T21:28:28.363285Z","shell.execute_reply":"2025-12-15T21:28:31.290807Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def logloss(target, predict):\n    target = torch.mean(target.float(), dim=0).argmax(dim=-1).cpu().detach().numpy()\n    predict = torch.median(predict, dim=0).values.cpu().detach().numpy()\n    labels = [0,1,2]\n    mapping = {0: 1, 1: 2, 2: 4}\n    sample_weight = [mapping[y] for y in target]\n\n    return sklearn.metrics.log_loss(\n        y_true=target,\n        y_pred=predict,\n        labels=labels,\n        sample_weight=sample_weight\n    )\n\ndef format_val_to_submission(val, val_predictions, labels):\n    submission = []\n\n    for idx, row in val.iterrows():\n        study_id = row['study_id']\n        predictions = val_predictions[idx % len(val_predictions)]\n\n        for i, label in enumerate(labels):\n            row_id = f\"{study_id}_{label}\"\n            normal_mild_value = float(predictions[i][0])\n            moderate_value = float(predictions[i][1])\n            severe_value = float(predictions[i][2])\n            submission.append([row_id, normal_mild_value, moderate_value, severe_value])\n    \n    submission_df = pd.DataFrame(submission, columns=['row_id', 'normal_mild', 'moderate', 'severe'])\n    return submission_df\n\ndef prepare_tensor(tensor):\n    # Check if tensor has shape (25, 3), expand dims to (1, 25, 3)\n    if tensor.shape == torch.Size([25, 3]):\n        tensor = tensor.unsqueeze(0)  # Adds a batch dimension\n\n    return tensor\n\ndef validate_model_with_submission_format(net, val_dataloader, val_df, labels):\n    net.eval()  # Set the model to evaluation mode\n    val_predictions = []\n    val_targets = []\n\n    with torch.no_grad():  # Disable gradient computation\n        for batch in tqdm.tqdm(val_dataloader, desc=\"Val\", total=len(val_dataloader)):\n#             in_tensor = batch['Sagittal T2/STIR'].view(batch['Sagittal T2/STIR'].shape[1], 1, *batch['Sagittal T2/STIR'].shape[2:])\n            in_tensor = batch[args.modality]\n            target = batch['target']\n\n            in_tensor = in_tensor.to(device)\n            target = target.to(device).squeeze(0)  # Adjust target shape to match predict\n            \n            predict = net(in_tensor).softmax(dim=-1)\n            # predict = torch.median(predict, dim=0).values  # Apply median after softmax\n\n            predict = prepare_tensor(predict)\n            target = prepare_tensor(target)\n\n            val_predictions.append(predict)\n            val_targets.append(target)\n\n    # Concatenate all tensors in the lists along the batch dimension\n    val_predictions = torch.cat(val_predictions, dim=0)  # Shape (N, 25, 3)\n    val_targets = torch.cat(val_targets, dim=0)    # Shape (N, 25, 3)\n\n    val_predictions = val_predictions.cpu().numpy()\n    val_targets = val_targets.cpu().numpy()\n\n    # Format the validation data to submission format\n    formatted_submission = format_val_to_submission(val_df.reset_index(drop=True), val_predictions, labels)\n\n    # Calculate log loss\n    target_labels = []\n    predict_labels = []\n    sample_weights = []\n\n    for i, row in formatted_submission.iterrows():\n        row_id_parts = row['row_id'].split('_')\n        study_id = row_id_parts[0]\n        label = '_'.join(row_id_parts[1:])\n        \n        true_values = val_df[val_df['study_id'] == int(study_id)][label].values[0]\n        true_class = ['Normal/Mild', 'Moderate', 'Severe'].index(true_values)\n        target_labels.append(true_class)\n        \n        predict_values = row[['normal_mild', 'moderate', 'severe']].values\n        predict_labels.append(predict_values)\n        \n        mapping = {0: 1, 1: 2, 2: 4}\n        sample_weights.append(mapping[true_class])\n\n    target_labels = np.array(target_labels)\n    predict_labels = np.array(predict_labels)\n\n    log_loss_value = sklearn.metrics.log_loss(\n        y_true=target_labels,\n        y_pred=predict_labels,\n        labels=[0, 1, 2],\n        sample_weight=sample_weights\n    )\n\n    return log_loss_value\n","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:31.293292Z","iopub.execute_input":"2025-12-15T21:28:31.293661Z","iopub.status.idle":"2025-12-15T21:28:31.307562Z","shell.execute_reply.started":"2025-12-15T21:28:31.293610Z","shell.execute_reply":"2025-12-15T21:28:31.306686Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nif len(os.listdir(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_images\")) == 1:\n    \n    train = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train.csv\")\n    train_label_coordinates = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_label_coordinates.csv\")\n    train_series_descriptions = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv\")\n    train = train.dropna()\n\n    train, val = train_test_split(train, test_size=0.2, random_state=42)\n\n    val_dataset = RSNADataset(df=val, train_series_descriptions=train_series_descriptions)\n    val_dataset = monai.data.Dataset(data=val_dataset, transform=val_dataset.get_transform())\n    val_dataloader = monai.data.DataLoader(val_dataset, batch_size=1, shuffle=False, num_workers=0)\n\n    val_loss = validate_model_with_submission_format(net, val_dataloader, val, val_dataset.data.labels)\n\n    print('LOGLOSS:', val_loss,)","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:28:31.309625Z","iopub.execute_input":"2025-12-15T21:28:31.309920Z","iopub.status.idle":"2025-12-15T21:30:22.009290Z","shell.execute_reply.started":"2025-12-15T21:28:31.309901Z","shell.execute_reply":"2025-12-15T21:30:22.008321Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_series_descriptions = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_series_descriptions.csv\")\nss = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/sample_submission.csv\")\n\ntest_dataset = RSNADataset(df=None, train_series_descriptions=test_series_descriptions, is_train=False)\ntest_dataset = monai.data.Dataset(data=test_dataset, transform=test_dataset.get_transform())\ntest_dataloader = monai.data.DataLoader(test_dataset, batch_size=1, shuffle=False, num_workers=0)\n","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:30:22.010272Z","iopub.execute_input":"2025-12-15T21:30:22.010496Z","iopub.status.idle":"2025-12-15T21:30:22.023844Z","shell.execute_reply.started":"2025-12-15T21:30:22.010478Z","shell.execute_reply":"2025-12-15T21:30:22.023099Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Validation function\ndef inference_model(net, test_dataloader, ss, labels):\n    \n    new_ss = pd.DataFrame(columns=ss.columns)\n\n    net.eval()  # Set the model to evaluation mode\n    with torch.no_grad():  # Disable gradient computation\n        for batch in test_dataloader:\n            in_tensor = batch[args.modality]\n            in_tensor = in_tensor.to(device)\n\n            study_id = int(batch['study_id'][0])\n\n            predict = net(in_tensor).softmax(dim=-1).cpu().numpy()[0]\n\n            for i in range(25):\n                label = labels[i]\n                row_id = f\"{study_id}_{label}\"\n                normal_mild_value = float(predict[i][0])\n                moderate_value = float(predict[i][1])\n                severe_value = float(predict[i][2])\n                \n                data = [[row_id, normal_mild_value, moderate_value, severe_value]]\n                data_df = pd.DataFrame(data, columns=ss.columns)\n                \n                # Concatenate the new DataFrame to new_ss\n                new_ss = pd.concat([new_ss, data_df], axis=0, ignore_index=True)\n\n\n    return new_ss\n","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:30:22.024782Z","iopub.execute_input":"2025-12-15T21:30:22.025018Z","iopub.status.idle":"2025-12-15T21:30:22.034222Z","shell.execute_reply.started":"2025-12-15T21:30:22.024999Z","shell.execute_reply":"2025-12-15T21:30:22.033361Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_ss = inference_model(net, test_dataloader, ss, test_dataset.data.labels)","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:30:22.035220Z","iopub.execute_input":"2025-12-15T21:30:22.035445Z","iopub.status.idle":"2025-12-15T21:30:23.105245Z","shell.execute_reply.started":"2025-12-15T21:30:22.035426Z","shell.execute_reply":"2025-12-15T21:30:23.104308Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_ss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-15T21:30:23.106366Z","iopub.execute_input":"2025-12-15T21:30:23.106621Z","iopub.status.idle":"2025-12-15T21:30:23.118264Z","shell.execute_reply.started":"2025-12-15T21:30:23.106601Z","shell.execute_reply":"2025-12-15T21:30:23.117329Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"new_ss.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2025-12-15T21:30:23.119326Z","iopub.execute_input":"2025-12-15T21:30:23.119555Z","iopub.status.idle":"2025-12-15T21:30:23.128944Z","shell.execute_reply.started":"2025-12-15T21:30:23.119537Z","shell.execute_reply":"2025-12-15T21:30:23.128295Z"},"trusted":true},"outputs":[],"execution_count":null}]}