{"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,"sourceType":"competition"},{"sourceId":8776139,"sourceType":"datasetVersion","datasetId":5274724},{"sourceId":8841383,"sourceType":"datasetVersion","datasetId":5321134},{"sourceId":69711,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":58166}],"dockerImageVersionId":30733,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"In this notebook I have demonstrated:\n* EDA: RSNA 2024 Lumbar Spine Degenerative dataset\n* Result of Unet inference model\n\n# 📒 Notebooks\n📌 **UNet**:\n* EDA: [EDA: Lumbar Spine Segmentation](https://www.kaggle.com/code/tabassumnova/eda-lumbar-spine-segmentation)\n* Train: [Spine Segmentation: Unet training](https://www.kaggle.com/code/tabassumnova/spine-segmentation-unet-training)\n* Infer: [Spine Segmentation: Unet Inference](https://www.kaggle.com/code/tabassumnova/spine-segmentation-unet-inference)\n\n📌 **Segmentation Dataset**:\n* [Lumbar-Spine-Segmentation](https://www.kaggle.com/datasets/tabassumnova/lumbar-spine-segmentation)\n","metadata":{}},{"cell_type":"markdown","source":"# EDA","metadata":{}},{"cell_type":"code","source":"import seaborn as sns\n\nimport matplotlib.pyplot as plt\nimport os\nimport time\nimport numpy as np\nimport glob\nimport json\nimport collections\nimport torch\nimport torch.nn as nn\n\nimport pydicom as dicom\nimport matplotlib.patches as patches\n\nfrom matplotlib import animation, rc\nimport pandas as pd\n\nimport pydicom as dicom # dicom\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:03:25.456905Z","iopub.execute_input":"2024-07-10T07:03:25.457222Z","iopub.status.idle":"2024-07-10T07:03:31.294332Z","shell.execute_reply.started":"2024-07-10T07:03:25.457197Z","shell.execute_reply":"2024-07-10T07:03:31.293351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# read data\ntrain_path = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/'\n\ntrain  = pd.read_csv(train_path + 'train.csv')\nlabel = pd.read_csv(train_path + 'train_label_coordinates.csv')\ntrain_desc  = pd.read_csv(train_path + 'train_series_descriptions.csv')\ntest_desc   = pd.read_csv(train_path + 'test_series_descriptions.csv')\nsub         = pd.read_csv(train_path + 'sample_submission.csv')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-07-10T07:03:31.296357Z","iopub.execute_input":"2024-07-10T07:03:31.296989Z","iopub.status.idle":"2024-07-10T07:03:31.455940Z","shell.execute_reply.started":"2024-07-10T07:03:31.296957Z","shell.execute_reply":"2024-07-10T07:03:31.455146Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Function to generate image paths based on directory structure\ndef generate_image_paths(df, data_dir):\n    image_paths = []\n    for study_id, series_id in zip(df['study_id'], df['series_id']):\n        study_dir = os.path.join(data_dir, str(study_id))\n        series_dir = os.path.join(study_dir, str(series_id))\n        images = os.listdir(series_dir)\n        image_paths.extend([os.path.join(series_dir, img) for img in images])\n    return image_paths\n\n# Generate image paths for train and test data\ntrain_image_paths = generate_image_paths(train_desc, f'{train_path}/train_images')\ntest_image_paths = generate_image_paths(test_desc, f'{train_path}/test_images')","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-07-10T07:03:31.457314Z","iopub.execute_input":"2024-07-10T07:03:31.457743Z","iopub.status.idle":"2024-07-10T07:04:11.735217Z","shell.execute_reply.started":"2024-07-10T07:03:31.457711Z","shell.execute_reply":"2024-07-10T07:04:11.734340Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\n\n# Function to open and display DICOM images\ndef display_dicom_images(image_paths):\n    plt.figure(figsize=(15, 5))  # Adjust figure size if needed\n    for i, path in enumerate(image_paths[:3]):\n        ds = pydicom.dcmread(path)\n        plt.subplot(1, 3, i+1)\n        plt.imshow(ds.pixel_array, cmap=plt.cm.bone)\n        plt.title(f\"Image {i+1}\")\n        plt.axis('off')\n    plt.show()\n\n# Display the first three DICOM images\ndisplay_dicom_images(train_image_paths)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:11.737289Z","iopub.execute_input":"2024-07-10T07:04:11.737627Z","iopub.status.idle":"2024-07-10T07:04:12.349237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport pydicom\nimport matplotlib.pyplot as plt\nimport pandas as pd\n\n# Function to open and display DICOM images along with coordinates\ndef display_dicom_with_coordinates(image_paths, label_df):\n    fig, axs = plt.subplots(1, len(image_paths), figsize=(18, 6))\n    \n    for idx, path in enumerate(image_paths):  # Display images\n        study_id = int(path.split('/')[-3])\n        series_id = int(path.split('/')[-2])\n        \n        # Filter label coordinates for the current study and series\n        filtered_labels = label_df[(label_df['study_id'] == study_id) & (label_df['series_id'] == series_id)]\n        \n        # Read DICOM image\n        ds = pydicom.dcmread(path)\n        \n        # Plot DICOM image\n        axs[idx].imshow(ds.pixel_array, cmap='gray')\n        axs[idx].set_title(f\"Study ID: {study_id}, Series ID: {series_id}\")\n        axs[idx].axis('off')\n        \n        # Plot coordinates\n        for _, row in filtered_labels.iterrows():\n            axs[idx].plot(row['x'], row['y'], 'ro', markersize=5)\n        \n    plt.tight_layout()\n    plt.show()\n\n# Load DICOM files from a folder\ndef load_dicom_files(path_to_folder):\n    files = [os.path.join(path_to_folder, f) for f in os.listdir(path_to_folder) if f.endswith('.dcm')]\n    files.sort(key=lambda x: int(os.path.splitext(os.path.basename(x))[0].split('-')[-1]))\n    return files\n\n# Display DICOM images with coordinates\nstudy_id = \"100206310\"\nstudy_folder = f'{train_path}/train_images/{study_id}'\n\nimage_paths = []\nfor series_folder in os.listdir(study_folder):\n    series_folder_path = os.path.join(study_folder, series_folder)\n    dicom_files = load_dicom_files(series_folder_path)\n    if dicom_files:\n        image_paths.append(dicom_files[0])  # Add the first image from each series\n\n\ndisplay_dicom_with_coordinates(image_paths, label)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:12.350381Z","iopub.execute_input":"2024-07-10T07:04:12.350691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Preprocessing","metadata":{}},{"cell_type":"code","source":"# Define function to reshape a single row of the DataFrame\ndef reshape_row(row):\n    data = {'study_id': [], 'condition': [], 'level': [], 'severity': []}\n    \n    for column, value in row.items():\n        if column not in ['study_id', 'series_id', 'instance_number', 'x', 'y', 'series_description']:\n            parts = column.split('_')\n            condition = ' '.join([word.capitalize() for word in parts[:-2]])\n            level = parts[-2].capitalize() + '/' + parts[-1].capitalize()\n            data['study_id'].append(row['study_id'])\n            data['condition'].append(condition)\n            data['level'].append(level)\n            data['severity'].append(value)\n    \n    return pd.DataFrame(data)\n\n# Reshape the DataFrame for all rows\nnew_train_df = pd.concat([reshape_row(row) for _, row in train.iterrows()], ignore_index=True)\n\n# Display the first few rows of the reshaped dataframe\nnew_train_df.head(5)","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.execute_input":"2024-07-10T07:04:13.155347Z","iopub.status.idle":"2024-07-10T07:04:14.619072Z","shell.execute_reply.started":"2024-07-10T07:04:13.155320Z","shell.execute_reply":"2024-07-10T07:04:14.617918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Print columns in a neat way\nprint(\"\\nColumns in new_train_df:\")\nprint(\",\".join(new_train_df.columns))\n\nprint(\"\\nColumns in label:\")\nprint(\",\".join(label.columns))\n\nprint(\"\\nColumns in test_desc:\")\nprint(\",\".join(test_desc.columns))\n\nprint(\"\\nColumns in sub:\")\nprint(\",\".join(sub.columns))","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:14.620608Z","iopub.execute_input":"2024-07-10T07:04:14.621174Z","iopub.status.idle":"2024-07-10T07:04:14.628775Z","shell.execute_reply.started":"2024-07-10T07:04:14.621137Z","shell.execute_reply":"2024-07-10T07:04:14.627745Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merge the dataframes on the common columns\nmerged_df = pd.merge(new_train_df, label, on=['study_id', 'condition', 'level'], how='inner')\n# Merge the dataframes on the common column 'series_id'\nfinal_merged_df = pd.merge(merged_df, train_desc, on='series_id', how='inner')","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:14.630043Z","iopub.execute_input":"2024-07-10T07:04:14.630326Z","iopub.status.idle":"2024-07-10T07:04:14.710982Z","shell.execute_reply.started":"2024-07-10T07:04:14.630303Z","shell.execute_reply":"2024-07-10T07:04:14.709897Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Merge the dataframes on the common column 'series_id'\nfinal_merged_df = pd.merge(merged_df, train_desc, on=['series_id','study_id'], how='inner')\n# Display the first few rows of the final merged dataframe\nfinal_merged_df.head(5)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:14.712224Z","iopub.execute_input":"2024-07-10T07:04:14.712552Z","iopub.status.idle":"2024-07-10T07:04:14.745549Z","shell.execute_reply.started":"2024-07-10T07:04:14.712518Z","shell.execute_reply":"2024-07-10T07:04:14.744642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\n\n# Create the row_id column\nfinal_merged_df['row_id'] = (\n    final_merged_df['study_id'].astype(str) + '_' +\n    final_merged_df['condition'].str.lower().str.replace(' ', '_') + '_' +\n    final_merged_df['level'].str.lower().str.replace('/', '_')\n)\n\n# Create the image_path column\nfinal_merged_df['image_path'] = (\n    f'{train_path}/train_images/' + \n    final_merged_df['study_id'].astype(str) + '/' +\n    final_merged_df['series_id'].astype(str) + '/' +\n    final_merged_df['instance_number'].astype(str) + '.dcm'\n)\n\n# Note: Check image path, since there's 1 instance id, for 1 image, but there's many more images other than the ones labelled in the instance ID. \n\n# Display the updated dataframe\nfinal_merged_df.head(5)","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:14.749297Z","iopub.execute_input":"2024-07-10T07:04:14.749620Z","iopub.status.idle":"2024-07-10T07:04:15.021743Z","shell.execute_reply.started":"2024-07-10T07:04:14.749590Z","shell.execute_reply":"2024-07-10T07:04:15.020635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the base path for test images\nbase_path = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_images/'\n\n# Function to get image paths for a series\ndef get_image_paths(row):\n    series_path = os.path.join(base_path, str(row['study_id']), str(row['series_id']))\n    if os.path.exists(series_path):\n        return [os.path.join(series_path, f) for f in os.listdir(series_path) if os.path.isfile(os.path.join(series_path, f))]\n    return []\n\n# Mapping of series_description to conditions\ncondition_mapping = {\n    'Sagittal T1': {'left': 'left_neural_foraminal_narrowing', 'right': 'right_neural_foraminal_narrowing'},\n    'Axial T2': {'left': 'left_subarticular_stenosis', 'right': 'right_subarticular_stenosis'},\n    'Sagittal T2/STIR': 'spinal_canal_stenosis'\n}\n\n# Create a list to store the expanded rows\nexpanded_rows = []\n\n# Expand the dataframe by adding new rows for each file path\nfor index, row in test_desc.iterrows():\n    image_paths = get_image_paths(row)\n    conditions = condition_mapping.get(row['series_description'], {})\n    if isinstance(conditions, str):  # Single condition\n        conditions = {'left': conditions, 'right': conditions}\n    for side, condition in conditions.items():\n        for image_path in image_paths:\n            expanded_rows.append({\n                'study_id': row['study_id'],\n                'series_id': row['series_id'],\n                'series_description': row['series_description'],\n                'image_path': image_path,\n                'condition': condition,\n                'row_id': f\"{row['study_id']}_{condition}\"\n            })\n\n# Create a new dataframe from the expanded rows\nexpanded_test_desc = pd.DataFrame(expanded_rows)\n\n# Display the resulting dataframe\nexpanded_test_desc.head(5)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:15.026399Z","iopub.execute_input":"2024-07-10T07:04:15.026766Z","iopub.status.idle":"2024-07-10T07:04:15.100774Z","shell.execute_reply.started":"2024-07-10T07:04:15.026736Z","shell.execute_reply":"2024-07-10T07:04:15.099743Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# change severity column labels\n#Normal/Mild': 'normal_mild', 'Moderate': 'moderate', 'Severe': 'severe'}\nfinal_merged_df['severity'] = final_merged_df['severity'].map({'Normal/Mild': 'normal_mild', 'Moderate': 'moderate', 'Severe': 'severe'})","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:15.104920Z","iopub.execute_input":"2024-07-10T07:04:15.105178Z","iopub.status.idle":"2024-07-10T07:04:15.116618Z","shell.execute_reply.started":"2024-07-10T07:04:15.105156Z","shell.execute_reply":"2024-07-10T07:04:15.115634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_data = expanded_test_desc\ntrain_data = final_merged_df","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:15.121040Z","iopub.execute_input":"2024-07-10T07:04:15.121349Z","iopub.status.idle":"2024-07-10T07:04:15.125871Z","shell.execute_reply.started":"2024-07-10T07:04:15.121315Z","shell.execute_reply":"2024-07-10T07:04:15.124967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\n\n# Define a function to check if a path exists\ndef check_exists(path):\n    return os.path.exists(path)\n\n# Define a function to check if a study ID directory exists\ndef check_study_id(row):\n    study_id = row['study_id']\n    path = f'{train_path}/train_images/{study_id}'\n    return check_exists(path)\n\n# Define a function to check if a series ID directory exists\ndef check_series_id(row):\n    study_id = row['study_id']\n    series_id = row['series_id']\n    path = f'{train_path}/train_images/{study_id}/{series_id}'\n    return check_exists(path)\n\n# Define a function to check if an image file exists\ndef check_image_exists(row):\n    image_path = row['image_path']\n    return check_exists(image_path)\n\n# Apply the functions to the train_data dataframe\ntrain_data['study_id_exists'] = train_data.apply(check_study_id, axis=1)\ntrain_data['series_id_exists'] = train_data.apply(check_series_id, axis=1)\ntrain_data['image_exists'] = train_data.apply(check_image_exists, axis=1)\n\n# Filter train_data\ntrain_data = train_data[(train_data['study_id_exists']) & (train_data['series_id_exists']) & (train_data['image_exists'])]","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:15.126946Z","iopub.execute_input":"2024-07-10T07:04:15.127483Z","iopub.status.idle":"2024-07-10T07:04:31.605016Z","shell.execute_reply.started":"2024-07-10T07:04:15.127459Z","shell.execute_reply":"2024-07-10T07:04:31.604214Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.head(3)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:31.606122Z","iopub.execute_input":"2024-07-10T07:04:31.606472Z","iopub.status.idle":"2024-07-10T07:04:31.622181Z","shell.execute_reply.started":"2024-07-10T07:04:31.606442Z","shell.execute_reply":"2024-07-10T07:04:31.621192Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.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 data","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:31.623245Z","iopub.execute_input":"2024-07-10T07:04:31.623500Z","iopub.status.idle":"2024-07-10T07:04:31.632268Z","shell.execute_reply.started":"2024-07-10T07:04:31.623479Z","shell.execute_reply":"2024-07-10T07:04:31.631240Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load images randomly\nimport random\nimages = []\nrow_ids = []\nselected_indices = random.sample(range(len(train_data)), 2)\nfor i in selected_indices:\n    image = load_dicom(train_data['image_path'][i])\n    images.append(image)\n    row_ids.append(train_data['row_id'][i])\n\n# Plot images\nfig, ax = plt.subplots(1, 2, figsize=(8, 4))\nfor i in range(2):\n    ax[i].imshow(images[i], cmap='gray')\n    ax[i].set_title(f'Row ID: {row_ids[i]}', fontsize=8)\n    ax[i].axis('off')\nplt.tight_layout()\nplt.show()","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-07-10T07:04:31.633613Z","iopub.execute_input":"2024-07-10T07:04:31.634033Z","iopub.status.idle":"2024-07-10T07:04:31.974322Z","shell.execute_reply.started":"2024-07-10T07:04:31.633994Z","shell.execute_reply":"2024-07-10T07:04:31.973450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Segmentation","metadata":{}},{"cell_type":"markdown","source":"# Segmentation using Unet trained from Zenodo Dataset\n--------------------------------------------------------","metadata":{}},{"cell_type":"code","source":"!pip install -q segmentation_models_pytorch\n# Albumentations for augmentations\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\nimport cv2\n\nfrom torch.utils.data import Dataset, DataLoader\n\nfrom tqdm import tqdm\ntqdm.pandas()\n\nimport pydicom\nimport gc\n","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:31.975605Z","iopub.execute_input":"2024-07-10T07:04:31.975889Z","iopub.status.idle":"2024-07-10T07:04:52.409144Z","shell.execute_reply.started":"2024-07-10T07:04:31.975865Z","shell.execute_reply":"2024-07-10T07:04:52.408201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BASE_PATH  = '/kaggle/input/lumbar-spine-segmentation/dataset.csv'\nCKPT_DIR = '/kaggle/input/spine-segmentation-inference-model'","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:52.410772Z","iopub.execute_input":"2024-07-10T07:04:52.412163Z","iopub.status.idle":"2024-07-10T07:04:52.416608Z","shell.execute_reply.started":"2024-07-10T07:04:52.412124Z","shell.execute_reply":"2024-07-10T07:04:52.415638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## ⚙️ Configuration ","metadata":{}},{"cell_type":"code","source":"class CFG:\n    seed          = 101\n    debug         = False # set debug=False for Full Training\n    exp_name      = 'Baseline'\n    comment       = 'unet-efficientnet_b1-224x224'\n    model_name    = 'Unet'\n    backbone      = 'efficientnet-b1'\n    train_bs      = 64\n    valid_bs      = train_bs*2\n    img_size      = [224, 224]\n    epochs        = 15\n    lr            = 2e-3\n    scheduler     = 'CosineAnnealingLR'\n    min_lr        = 1e-6\n    T_max         = int(30000/train_bs*epochs)+50\n    T_0           = 25\n    warmup_epochs = 0\n    wd            = 1e-6\n    n_accumulate  = max(1, 32//train_bs)\n    n_fold        = 5\n    num_classes   = 3\n    device        = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n    thr           = 0.45\n    ttas          = [0]","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:52.417836Z","iopub.execute_input":"2024-07-10T07:04:52.418168Z","iopub.status.idle":"2024-07-10T07:04:52.453552Z","shell.execute_reply.started":"2024-07-10T07:04:52.418144Z","shell.execute_reply":"2024-07-10T07:04:52.452642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🔨 Utility","metadata":{}},{"cell_type":"code","source":"def load_img(path):\n    if(path[-4:]=='.dcm'):\n        img = pydicom.dcmread(path).pixel_array\n    else:\n        img = cv2.imread(path, cv2.IMREAD_UNCHANGED)\n    img = np.tile(img[...,None], [1, 1, 3]) # gray to rgb\n    img = img.astype('float32') # original is uint16\n    mx = np.max(img)\n    if mx:\n        img/=mx # scale image to [0, 1]\n    return img\n\ndef load_msk(path):\n    msk = np.load(path)\n    msk = msk.astype('float32')\n    msk/=255.0\n    return msk\n    \n\ndef show_img(img, mask=None):\n    clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))\n    plt.imshow(img, cmap='bone')\n    \n    if mask is not None:\n        plt.imshow(mask, alpha=0.5)\n        handles = [Rectangle((0,0),1,1, color=_c) for _c in [(0.667,0.0,0.0), (0.0,0.667,0.0), (0.0,0.0,0.667)]]\n\n    plt.axis('off')","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:52.454830Z","iopub.execute_input":"2024-07-10T07:04:52.455091Z","iopub.status.idle":"2024-07-10T07:04:52.465493Z","shell.execute_reply.started":"2024-07-10T07:04:52.455068Z","shell.execute_reply":"2024-07-10T07:04:52.464609Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import cupy as cp\n\ndef mask2rle(msk, thr=0.5):\n    '''\n    img: numpy array, 1 - mask, 0 - background\n    Returns run length as string formated\n    '''\n    msk    = cp.array(msk)\n    pixels = msk.flatten()\n    pad    = cp.array([0])\n    pixels = cp.concatenate([pad, pixels, pad])\n    runs   = cp.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\ndef masks2rles(msks, ids, heights, widths):\n    pred_strings = []; pred_ids = []; pred_classes = [];\n    for idx in range(msks.shape[0]):\n        height = heights[idx].item()\n        width = widths[idx].item()\n        msk = cv2.resize(msks[idx], \n                         dsize=(width, height), \n                         interpolation=cv2.INTER_NEAREST) # back to original shape\n        rle = [None]*3\n        for midx in [0, 1, 2]:\n            rle[midx] = mask2rle(msk[...,midx])\n        pred_strings.extend(rle)\n        pred_ids.extend([ids[idx]]*len(rle))\n        pred_classes.extend(['large_bowel', 'small_bowel', 'stomach'])\n    return pred_strings, pred_ids, pred_classes","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:52.467119Z","iopub.execute_input":"2024-07-10T07:04:52.468072Z","iopub.status.idle":"2024-07-10T07:04:53.585463Z","shell.execute_reply.started":"2024-07-10T07:04:52.468046Z","shell.execute_reply":"2024-07-10T07:04:53.584686Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🍚 Dataset","metadata":{}},{"cell_type":"code","source":"class BuildDataset(torch.utils.data.Dataset):\n    def __init__(self, df, label=False, transforms=None):\n        self.df         = df\n        self.label      = label\n        self.img_paths  = df['image_path'].tolist()\n        self.ids        = df['study_id'].tolist()\n        if 'msk_path' in df.columns:\n            self.msk_paths  = df['mask_path'].tolist()\n        else:\n            self.msk_paths = None\n        self.transforms = transforms\n        \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, index):\n        img_path  = self.img_paths[index]\n        id_       = self.ids[index]\n        img = []\n        img = load_img(img_path)\n        h, w = img.shape[:2]\n        if self.label:\n            msk_path = self.msk_paths[index]\n            msk = load_msk(msk_path)\n            if self.transforms:\n                data = self.transforms(image=img, mask=msk)\n                img  = data['image']\n                msk  = data['mask']\n            img = np.transpose(img, (2, 0, 1))\n            msk = np.transpose(msk, (2, 0, 1))\n            return torch.tensor(img), torch.tensor(msk)\n        else:\n            if self.transforms:\n                data = self.transforms(image=img)\n                img  = data['image']\n            img = np.transpose(img, (2, 0, 1))\n            return torch.tensor(img), id_, h, w","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:53.586797Z","iopub.execute_input":"2024-07-10T07:04:53.587228Z","iopub.status.idle":"2024-07-10T07:04:53.598711Z","shell.execute_reply.started":"2024-07-10T07:04:53.587194Z","shell.execute_reply":"2024-07-10T07:04:53.597746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 🌈 Augmentations","metadata":{}},{"cell_type":"code","source":"data_transforms = {\n    \"train\": A.Compose([\n        A.Resize(*CFG.img_size, interpolation=cv2.INTER_NEAREST),\n        A.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n#         A.ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.05, rotate_limit=5, p=0.5),\n        A.OneOf([\n            A.GridDistortion(num_steps=5, distort_limit=0.05, p=1.0),\n# #             A.OpticalDistortion(distort_limit=0.05, shift_limit=0.05, p=1.0),\n            A.ElasticTransform(alpha=1, sigma=50, alpha_affine=50, p=1.0)\n        ], p=0.25),\n#         A.CoarseDropout(max_holes=8, max_height=CFG.img_size[0]//20, max_width=CFG.img_size[1]//20,\n#                          min_holes=5, fill_value=0, mask_fill_value=0, p=0.5),\n        ], p=1.0),\n    \n    \"valid\": A.Compose([\n        A.Resize(*CFG.img_size, interpolation=cv2.INTER_NEAREST),\n        ], p=1.0)\n}","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:53.599918Z","iopub.execute_input":"2024-07-10T07:04:53.600194Z","iopub.status.idle":"2024-07-10T07:04:53.614378Z","shell.execute_reply.started":"2024-07-10T07:04:53.600171Z","shell.execute_reply":"2024-07-10T07:04:53.613477Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📦 Model","metadata":{}},{"cell_type":"code","source":"import segmentation_models_pytorch as smp\n\ndef build_model():\n    model = smp.Unet(\n        encoder_name=CFG.backbone,      # choose encoder, e.g. mobilenet_v2 or efficientnet-b7\n        encoder_weights=None,     # use `imagenet` pre-trained weights for encoder initialization\n        in_channels=3,                  # model input channels (1 for gray-scale images, 3 for RGB, etc.)\n        classes=CFG.num_classes,        # model output channels (number of classes in your dataset)\n        activation=None,\n    )\n    model.to(CFG.device)\n    return model\n\ndef load_model(path):\n    model = build_model()\n    model.load_state_dict(torch.load(path))\n    model.eval()\n    return model","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:53.619954Z","iopub.execute_input":"2024-07-10T07:04:53.620222Z","iopub.status.idle":"2024-07-10T07:04:57.518435Z","shell.execute_reply.started":"2024-07-10T07:04:53.620201Z","shell.execute_reply":"2024-07-10T07:04:57.517418Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## inference","metadata":{}},{"cell_type":"code","source":"@torch.no_grad()\ndef infer(model_paths, test_loader, num_log=1, thr=CFG.thr):\n    msks = []; imgs = [];\n    pred_strings = []; pred_ids = []; pred_classes = [];\n    for idx, (img, ids, heights, widths) in enumerate(tqdm(test_loader, total=len(test_loader), desc='Infer ')):\n        img = img.to(CFG.device, dtype=torch.float) # .squeeze(0)\n        size = img.size()\n        msk = []\n        msk = torch.zeros((size[0], 3, size[2], size[3]), device=CFG.device, dtype=torch.float32)\n        for path in model_paths:\n            model = load_model(path)\n            out   = model(img) # .squeeze(0) # removing batch axis\n            out   = nn.Sigmoid()(out) # removing channel axis\n            msk+=out/len(model_paths)\n        msk = (msk.permute((0,2,3,1))>thr).to(torch.uint8).cpu().detach().numpy() # shape: (n, h, w, c)\n        result = masks2rles(msk, ids, heights, widths)\n        pred_strings.extend(result[0])\n        pred_ids.extend(result[1])\n        pred_classes.extend(result[2])\n        if idx<num_log:\n            img = img.permute((0,2,3,1)).cpu().detach().numpy()\n            imgs.append(img[:10])\n            msks.append(msk[:10])\n        del img, msk, out, model, result\n        gc.collect()\n        torch.cuda.empty_cache()\n    return pred_strings, pred_ids, pred_classes, imgs, msks","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.519648Z","iopub.execute_input":"2024-07-10T07:04:57.519914Z","iopub.status.idle":"2024-07-10T07:04:57.531201Z","shell.execute_reply.started":"2024-07-10T07:04:57.519891Z","shell.execute_reply":"2024-07-10T07:04:57.530233Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def predict_mask(condition='Sagittal T2/STIR'):\n    test_df = train_data.loc[train_data['series_description'] == condition]\n\n    test_dataset = BuildDataset(test_df, transforms=data_transforms['valid'])\n    test_loader  = DataLoader(test_dataset, batch_size=CFG.valid_bs, \n                              num_workers=4, shuffle=False, pin_memory=False)\n    model_paths  = glob.glob(f'{CKPT_DIR}/best_epoch*.bin')\n    pred_strings, pred_ids, pred_classes, imgs, msks = infer(model_paths, test_loader)\n    \n    ########### Visualization ###################\n    for img, msk in zip(imgs[0][:5], msks[0][:5]):\n        plt.figure(figsize=(12, 7))\n        plt.subplot(1, 3, 1); plt.imshow(img, cmap='bone');\n        plt.axis('OFF'); plt.title('image')\n        plt.subplot(1, 3, 2); plt.imshow(msk*255); plt.axis('OFF'); plt.title('mask')\n        plt.subplot(1, 3, 3); plt.imshow(img, cmap='bone'); plt.imshow(msk*255, alpha=0.4);\n        plt.axis('OFF'); plt.title('overlay')\n        plt.tight_layout()\n        plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.534115Z","iopub.execute_input":"2024-07-10T07:04:57.534403Z","iopub.status.idle":"2024-07-10T07:04:57.550227Z","shell.execute_reply.started":"2024-07-10T07:04:57.534373Z","shell.execute_reply":"2024-07-10T07:04:57.549305Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📈 Sagittal T2/STIR Visualization","metadata":{}},{"cell_type":"code","source":"predict_mask(condition = 'Sagittal T2/STIR')","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.551776Z","iopub.execute_input":"2024-07-10T07:04:57.552109Z","iopub.status.idle":"2024-07-10T07:04:57.563065Z","shell.execute_reply.started":"2024-07-10T07:04:57.552079Z","shell.execute_reply":"2024-07-10T07:04:57.562037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📈 Sagittal T1 Visualization","metadata":{}},{"cell_type":"code","source":"predict_mask(condition = 'Sagittal T1')","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.564153Z","iopub.execute_input":"2024-07-10T07:04:57.564449Z","iopub.status.idle":"2024-07-10T07:04:57.572494Z","shell.execute_reply.started":"2024-07-10T07:04:57.564424Z","shell.execute_reply":"2024-07-10T07:04:57.571633Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Segmentation using Unet trained from Spider Dataset\n--------------------------------------------------------","metadata":{}},{"cell_type":"code","source":"import numpy as np \nimport pandas as pd \nimport os\nfrom pathlib import Path\nfrom PIL import Image\nfrom matplotlib.patches import Rectangle\n\nfrom sklearn.model_selection import KFold\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom torch.utils.data import Dataset\n\nfrom segmentation_models_pytorch import Unet\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.573634Z","iopub.execute_input":"2024-07-10T07:04:57.573898Z","iopub.status.idle":"2024-07-10T07:04:57.789025Z","shell.execute_reply.started":"2024-07-10T07:04:57.573876Z","shell.execute_reply":"2024-07-10T07:04:57.787960Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#transforms\nnewsize = (256, 256)\n#dataset\nfold = 1\n#dataloader\nbatch_size = 64\nnum_workers = 4\n#model\nnum_classes = 20\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")#run\nepochs = 100\nlearning_rate = 1e-3\n\nTRAIN = False #or False for inference only","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.790245Z","iopub.execute_input":"2024-07-10T07:04:57.790546Z","iopub.status.idle":"2024-07-10T07:04:57.798556Z","shell.execute_reply.started":"2024-07-10T07:04:57.790522Z","shell.execute_reply":"2024-07-10T07:04:57.797752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = Unet(\n  encoder_name=\"resnet34\",  # Choose encoder (e.g. resnet18, efficientnet-b0)\n  classes=num_classes,  # Number of output classes\n  in_channels=3  # Number of input channels (e.g. 3 for RGB)\n)","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:57.799834Z","iopub.execute_input":"2024-07-10T07:04:57.800197Z","iopub.status.idle":"2024-07-10T07:04:58.921246Z","shell.execute_reply.started":"2024-07-10T07:04:57.800148Z","shell.execute_reply":"2024-07-10T07:04:58.920450Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SEGDataset(Dataset):\n    def __init__(self, df, mode, transforms=None):\n        self.df = df.reset_index()\n        self.mode = mode\n        self.transforms = transforms\n\n    def __len__(self):\n        return self.df.shape[0]\n\n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n        image_path = row.image_path\n\n        # Open image\n        image = pydicom.dcmread(image_path).pixel_array\n        image = Image.fromarray(image)\n        if image.mode != 'RGB':  # Ensure image is RGB\n            image = image.convert('RGB')\n        image = np.asarray(image)\n        if (image > 1).any():  # Normalize if pixel values are between 0-255\n            image = image / 255.0\n        mask = np.zeros((image.shape[0], image.shape[1]))\n        \n        if(self.mode=='train'):\n            mask_path = os.path.join(mask_dir, row.image)\n            # Open mask\n            mask = Image.open(mask_path)\n            mask = np.asarray(mask)\n            assert mask.max() < num_classes, f\"Mask value {mask.max()} exceeds number of classes {num_classes}\"\n\n            # Apply transformations\n            if self.transforms is not None:\n                transformed = self.transforms(image=image, mask=mask)\n                image = transformed[\"image\"]\n                mask = transformed[\"mask\"]\n\n            # Create one layer for each label\n            mask = torch.as_tensor(mask).long()\n            mask = torch.nn.functional.one_hot(mask, num_classes=num_classes).permute(2,0,1).float()\n            #mask = torch.nn.functional.one_hot(mask, num_classes=num_classes).permute(0,3,1,2).squeeze(0).float()\n        else:\n            if self.transforms is not None:\n                transformed = self.transforms(image=image, mask=mask)\n                image = transformed[\"image\"]\n                mask = transformed[\"mask\"]\n\n    # Create one layer for each label\n        mask = torch.as_tensor(mask).long()\n        mask = torch.nn.functional.one_hot(mask, num_classes=num_classes).permute(2,0,1).float()\n        #mask = torch.nn.functional.one_hot(mask, num_classes=num_classes).permute(0,3,1,2).squeeze(0).float()    \n    # Convert image to tensor\n        image = torch.as_tensor(image).float()\n\n        return image, mask          ","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:58.922386Z","iopub.execute_input":"2024-07-10T07:04:58.922684Z","iopub.status.idle":"2024-07-10T07:04:58.935593Z","shell.execute_reply.started":"2024-07-10T07:04:58.922660Z","shell.execute_reply":"2024-07-10T07:04:58.934546Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\ntransforms_train = A.Compose([\n    A.Resize(newsize[0], newsize[1]),\n    A.HorizontalFlip(),\n    A.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225],\n    ),\n    ToTensorV2()\n])\n\ntransforms_valid = A.Compose([\n    A.Resize(newsize[0], newsize[1]),\n    A.Normalize(\n        mean=[0.485, 0.456, 0.406],\n        std=[0.229, 0.224, 0.225],\n    ),\n    ToTensorV2()\n])","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:58.936834Z","iopub.execute_input":"2024-07-10T07:04:58.937370Z","iopub.status.idle":"2024-07-10T07:04:58.948668Z","shell.execute_reply.started":"2024-07-10T07:04:58.937336Z","shell.execute_reply":"2024-07-10T07:04:58.947842Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class CombinedLoss(nn.Module):\n    def __init__(self, weight_ce=1.0, weight_iou=1.0):\n        super(CombinedLoss, self).__init__()\n        self.weight_ce = weight_ce\n        self.weight_iou = weight_iou\n        self.cross_entropy_loss = nn.CrossEntropyLoss()\n\n    def forward(self, inputs, targets):\n        # Cross-Entropy Loss\n        ce_loss = self.cross_entropy_loss(inputs, targets)\n\n        # IoU Loss\n        # Apply softmax to the inputs to get probabilities\n        probs = F.softmax(inputs, dim=1)\n\n        intersection = torch.sum(probs * targets, dim=(2, 3))\n        union = torch.sum(probs + targets, dim=(2, 3)) - intersection\n        iou = (intersection + 1e-6) / (union + 1e-6)\n        iou_loss = 1 - iou.mean()\n\n        # Combine losses\n        loss = self.weight_ce * ce_loss + self.weight_iou * iou_loss\n        return loss","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:58.949887Z","iopub.execute_input":"2024-07-10T07:04:58.950187Z","iopub.status.idle":"2024-07-10T07:04:58.959794Z","shell.execute_reply.started":"2024-07-10T07:04:58.950163Z","shell.execute_reply":"2024-07-10T07:04:58.958834Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test = train_data.loc[train_data['series_description'] == 'Sagittal T2/STIR'].reset_index(drop=True)\ntest_df = test[['image_path']]\n\ndataset_valid = SEGDataset(test_df, 'valid',  transforms_valid)\n\nval_loader = torch.utils.data.DataLoader(dataset_valid, batch_size=20, shuffle=False, num_workers=num_workers, pin_memory=False)","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:58.960902Z","iopub.execute_input":"2024-07-10T07:04:58.961252Z","iopub.status.idle":"2024-07-10T07:04:58.987908Z","shell.execute_reply.started":"2024-07-10T07:04:58.961216Z","shell.execute_reply":"2024-07-10T07:04:58.987094Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = CombinedLoss()\nmodel.to(device)\n\nif TRAIN:\n    run(train_loader, val_loader, model, learning_rate, criterion, epochs, device)\nelse:\n    model.load_state_dict(torch.load(\"/kaggle/input/simple_unet_2d_lspine/pytorch/one/1/simple_unet.pth\"))\n                      ","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:04:58.988967Z","iopub.execute_input":"2024-07-10T07:04:58.989238Z","iopub.status.idle":"2024-07-10T07:05:00.318947Z","shell.execute_reply.started":"2024-07-10T07:04:58.989215Z","shell.execute_reply":"2024-07-10T07:05:00.318138Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef inference(model, dataloader, device, num_samples=16):\n    model.eval()\n    images_batch = []\n    preds_batch = []\n    \n    with torch.no_grad():\n        print('inference start')\n        for images, _ in dataloader:\n            print(images.shape)\n            images = images.to(device)\n            outputs = model(images)\n            preds = torch.argmax(outputs, dim=1)\n            \n            images_batch.append(images.cpu())\n            preds_batch.append(preds.cpu())\n            \n            if len(images_batch) * images.size(0) >= num_samples:\n                break\n#     print(len(images_batch))\n    images_batch = torch.cat(images_batch)[:num_samples]\n    preds_batch = torch.cat(preds_batch)[:num_samples]\n    \n    return images_batch, preds_batch\n\n\n# Define a color map with fixed colors for each label\ndef get_label_colors(num_classes):\n    colors = plt.cm.tab20(np.linspace(0, 1, num_classes))\n    return colors\n\nlabel_dict = {1 : '1: L5', 2 : '2: L4', 3 : '3: L3', 4 : '4: L2', 5 : '5: L1', 6 : '6: T12',\n                7 : '7: unknown', 8 : '8: unknown', 9 : '9: unknown',\n                10: '10: spinal canal', 11: '11: L5-S1', 12: '12: L4-L5', 13: '13: L3-L4',\n                14: '14: L2-L3', 15: '15: L1-L2', 16: '16: T12-L1',\n                17: '17: unknown', 18: '18: unknown', 19: '19: unknown'\n             }\n\ndef visualize_predictions(images, masks, num_classes=20, num_samples=16):\n#     print(images[0])\n    num_samples = min(num_samples, len(images))\n    plt.figure(figsize=(25, 20))\n    \n    label_colors = get_label_colors(num_classes)\n    \n    for i in range(num_samples):\n        plt.subplot(4, 8, i * 2 + 1)\n        im = images[i].numpy()\n        im = np.transpose(im, (1, 2, 0))\n        #denormalize\n        im = ((im * [0.229, 0.224, 0.225]) + [0.485, 0.456, 0.406]) * 255\n        plt.imshow(im)\n        plt.title(\"Input Image\")\n        plt.axis('off')\n        \n        plt.subplot(4, 8, i * 2 + 2)\n        mask = masks[i].numpy()\n\n        color_mask = np.zeros((mask.shape[0], mask.shape[1], 3))\n        for label in range(num_classes):\n            color_mask[mask == label] = label_colors[label][:3] * 255\n        \n        plt.imshow(color_mask.astype(np.uint8))\n        plt.title(\"Predicted Mask\")\n        plt.axis('off')\n    ## for legend\n    plt.subplot(4, 8, 4*8)\n    handles = [Rectangle((0,0),1,1, color=label_colors[i][:3]) for i in range(1, num_classes)]\n    labels = list(label_dict.values())\n    plt.legend(handles,labels, loc=\"upper right\", fontsize=20)\n    plt.axis('off')\n\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:05:00.320228Z","iopub.execute_input":"2024-07-10T07:05:00.320515Z","iopub.status.idle":"2024-07-10T07:05:00.337222Z","shell.execute_reply.started":"2024-07-10T07:05:00.320491Z","shell.execute_reply":"2024-07-10T07:05:00.336276Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.eval()\nmodel.to(device)\n\nimages, masks = inference(model, val_loader, device, num_samples=15)\nvisualize_predictions(images, masks, num_samples=15)","metadata":{"execution":{"iopub.status.busy":"2024-07-10T07:09:30.032605Z","iopub.execute_input":"2024-07-10T07:09:30.033477Z","iopub.status.idle":"2024-07-10T07:09:35.686484Z","shell.execute_reply.started":"2024-07-10T07:09:30.033428Z","shell.execute_reply":"2024-07-10T07:09:35.685484Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# References\nI took most of the inspiration from the following notebooks\n- https://www.kaggle.com/code/shubhamcodez/rsna-efficientnet-starter-notebook\n- https://www.kaggle.com/code/awsaf49/uwmgi-unet-train-pytorch/\n- https://www.kaggle.com/code/awsaf49/uwmgi-unet-infer-pytorch/\n- https://www.kaggle.com/code/anoukstein/2d-segmentation-of-sagittal-lumbar-spine-mri","metadata":{}}]}