{"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":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"}],"dockerImageVersionId":30787,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# -*- coding: utf-8 -*-\nimport os\nimport numpy as np\nimport pandas as pd\nimport cv2\nimport pydicom\nimport tensorflow as tf\nfrom tensorflow.keras.applications import ResNet50\nfrom tensorflow.keras.layers import Dense, GlobalAveragePooling2D, Input\nfrom tensorflow.keras.models import Model\nfrom sklearn.model_selection import KFold\nfrom tqdm import tqdm\nimport albumentations as A\nimport re\nimport glob\n\nrd = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification'\nOUTPUT_DIR = '/content/'\ndevice = '/GPU:0' if tf.config.list_physical_devices('GPU') else '/CPU:0'\n\n# Configuration\nSEED = 8620\nIMG_SIZE = (512, 512)\nIN_CHANS = 42\nN_LABELS = 25\nN_CLASSES = 3 * N_LABELS\nN_FOLDS = 5\nBATCH_SIZE = 1\ndata_dir = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification'\n\n# Load DataFrames\ndf = pd.read_csv(f'{data_dir}/test_series_descriptions.csv')\nstudy_ids = df['study_id'].unique().tolist()\n\nsample_sub = pd.read_csv(f'{data_dir}/sample_submission.csv')\nLABELS = sample_sub.columns[1:].tolist()\n\n# Conditions and Levels\nCONDITIONS = [\n    'spinal_canal_stenosis',\n    'left_neural_foraminal_narrowing',\n    'right_neural_foraminal_narrowing',\n    'left_subarticular_stenosis',\n    'right_subarticular_stenosis'\n]\n\nLEVELS = [\n    'l1_l2',\n    'l2_l3',\n    'l3_l4',\n    'l4_l5',\n    'l5_s1',\n]\n\n# Helper functions\ndef atoi(text):\n    return int(text) if text.isdigit() else text\n\ndef natural_keys(text):\n    return [atoi(c) for c in re.split(r'(\\d+)', text)]\n\n\"\"\"Feature Engineering\"\"\"\n\nclass RSNA24TestDataset(): #Removed tf.data.Dataset inheritance\n    def __init__(self, df, study_ids, phase='test', transform=None):\n        self.df = df\n        self.study_ids = study_ids\n        self.transform = transform\n        self.phase = phase\n\n    def __len__(self):\n        return len(self.study_ids)\n\n    def get_img_paths(self, study_id, series_desc):\n        series_df = self.df[(self.df['study_id'] == study_id) &\n                            (self.df['series_description'] == series_desc)]\n        img_paths = []\n        for _, row in series_df.iterrows():\n            paths = sorted(glob.glob(f'{data_dir}/test_images/{study_id}/{row[\"series_id\"]}/*.dcm'),\n                           key=natural_keys)\n            img_paths.extend(paths)\n        return img_paths\n\n    def read_dcm_image(self, src_path):\n        dicom_data = pydicom.dcmread(src_path)\n        image = dicom_data.pixel_array\n        norm_img = (image - image.min()) / (image.max() - image.min() + 1e-6) * 255\n        resized_img = cv2.resize(norm_img, IMG_SIZE, interpolation=cv2.INTER_CUBIC)\n        #return resized_img.astype(\n        return resized_img.astype(np.uint8)\n\n    def load_series_images(self, study_id, series_desc, start_idx):\n\n\n        images = np.zeros((IMG_SIZE[0], IMG_SIZE[1], 14), dtype=np.uint8)\n        img_paths = self.get_img_paths(study_id, series_desc)\n\n        if not img_paths:\n            print(f'{study_id}: {series_desc} has no images')\n            return images\n\n        step = len(img_paths) / 14.0\n        mid_point = len(img_paths) / 2.0 - 6.0 * step\n\n        for j, i in enumerate(np.arange(mid_point, len(img_paths), step)):\n            try:\n                idx = max(0, int(round(i - 0.5)))\n                images[..., j] = self.read_dcm_image(img_paths[idx])\n            except Exception as e:\n                print(f'Failed to load {series_desc} for {study_id}: {e}')\n\n        return images\n\n    def __getitem__(self, idx):\n        study_id = self.study_ids[idx]\n        channels = 42\n        x = np.zeros((IMG_SIZE[0], IMG_SIZE[1], channels), dtype=np.uint8)\n\n        # Load images for each series\n        x[..., :14] = self.load_series_images(study_id, 'Sagittal T1', 0)\n        x[..., 14:28] = self.load_series_images(study_id, 'Sagittal T2/STIR', 14)\n        x[..., 28:] = self.load_series_images(study_id, 'Axial T2', 28)\n\n        # Apply transformations\n        if self.transform:\n            x = self.transform(image=x)['image']\n\n        x = np.transpose(x, (2, 0, 1))  # Channels-first for TensorFlow\n        return x, study_id\n\n# Transformations\ntransforms_test = A.Compose([\n    A.Resize(IMG_SIZE[0], IMG_SIZE[1]),\n    A.Normalize(mean=0.5, std=0.5)\n])\n\n# Dataset and DataLoader\ntest_ds = RSNA24TestDataset(df, study_ids, transform=transforms_test)\n\n# Define the ResNet50 model\ndef build_model(input_shape, n_classes):\n    # Remove weights='imagenet' to avoid loading pre-trained weights\n    base_model = ResNet50(include_top=False, weights=None, input_tensor=Input(shape=input_shape))\n    x = base_model.output\n    x = GlobalAveragePooling2D()(x)\n    output = Dense(n_classes, activation='softmax')(x)\n    model = Model(inputs=base_model.input, outputs=output)\n    return model\n\n# Initialize model\nwith tf.device(device):\n    model = build_model((IMG_SIZE[0], IMG_SIZE[1], IN_CHANS), N_CLASSES)\n\n# Predictions and Submission\ny_preds = []\nrow_names = []\n\nfor x, study_id in tqdm(test_ds, leave=True):\n    x = np.expand_dims(x, axis=0)  # Add batch dimension\n    pred_per_study = np.zeros((N_LABELS, 3))\n\n    # Generate row names for submission\n    for cond in CONDITIONS:\n        for level in LEVELS:\n            row_names.append(f'{study_id}_{cond}_{level}')\n\n    with tf.device(device):\n        # Transpose the dimensions of x to match the expected input shape\n        x = x.transpose(0, 2, 3, 1)  # Batch, Height, Width, Channels\n\n    y = model.predict(x)[0]\n    for col in range(N_LABELS):\n        pred = y[col * 3 : (col + 1) * 3]\n        pred_per_study[col] = pred\n\n    y_preds.append(pred_per_study)\n\n# Combine and save predictions\ny_preds = np.concatenate(y_preds, axis=0)\n\nsubmission_df = pd.DataFrame({\n    'row_id': row_names,\n    **{label: y_preds[:, i] for i, label in enumerate(LABELS)}\n})\n\nsubmission_df.to_csv('submission.csv', index=False)\n\n# Verify Submission\nprint(pd.read_csv('submission.csv').head(3))","metadata":{"execution":{"iopub.status.busy":"2024-10-06T10:20:30.020529Z","iopub.execute_input":"2024-10-06T10:20:30.020840Z","iopub.status.idle":"2024-10-06T10:20:53.012836Z","shell.execute_reply.started":"2024-10-06T10:20:30.020806Z","shell.execute_reply":"2024-10-06T10:20:53.011808Z"},"trusted":true},"execution_count":null,"outputs":[]}]}