{"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":52254,"databundleVersionId":9674523,"sourceType":"competition"},{"sourceId":6211844,"sourceType":"datasetVersion","datasetId":3567114},{"sourceId":6091,"sourceType":"modelInstanceVersion","modelInstanceId":4623,"modelId":2800}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"! pip install -q git+https://github.com/keras-team/keras-cv","metadata":{"_kg_hide-output":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2024-12-15T19:03:25.999862Z","iopub.execute_input":"2024-12-15T19:03:26.000744Z","iopub.status.idle":"2024-12-15T19:03:48.437361Z","shell.execute_reply.started":"2024-12-15T19:03:26.000704Z","shell.execute_reply":"2024-12-15T19:03:48.435769Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n# You can use `tensorflow`, `pytorch`, `jax` here\n# KerasCore makes the notebook backend agnostic :)\nos.environ[\"KERAS_BACKEND\"] = \"tensorflow\"\n\nimport keras_cv\nimport keras_core as keras\nfrom keras_core import layers\n\nimport numpy as np\nimport pandas as pd\nimport tensorflow as tf\nfrom matplotlib import pyplot as plt\nfrom sklearn.model_selection import train_test_split\n\nimport cv2\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_modality_lut\nimport gc\nfrom tqdm.notebook import tqdm\nfrom glob import glob\nfrom joblib import Parallel, delayed","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:48.439943Z","iopub.execute_input":"2024-12-15T19:03:48.440347Z","iopub.status.idle":"2024-12-15T19:03:48.447747Z","shell.execute_reply.started":"2024-12-15T19:03:48.44031Z","shell.execute_reply":"2024-12-15T19:03:48.446684Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class Config:\n    SEED = 42\n    IMAGE_SIZE = [256, 256]\n    RESIZE_DIM = 256\n    BATCH_SIZE = 64\n    EPOCHS = 10\n    TARGET_COLS  = [\n        \"bowel_injury\", \"extravasation_injury\",\n        \"kidney_healthy\", \"kidney_low\", \"kidney_high\",\n        \"liver_healthy\", \"liver_low\", \"liver_high\",\n        \"spleen_healthy\", \"spleen_low\", \"spleen_high\",\n    ]\n    AUTOTUNE = tf.data.AUTOTUNE\n\nconfig = Config()","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:48.449909Z","iopub.execute_input":"2024-12-15T19:03:48.450318Z","iopub.status.idle":"2024-12-15T19:03:48.472205Z","shell.execute_reply.started":"2024-12-15T19:03:48.450269Z","shell.execute_reply":"2024-12-15T19:03:48.471072Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"keras.utils.set_random_seed(seed=config.SEED)","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:48.474402Z","iopub.execute_input":"2024-12-15T19:03:48.474741Z","iopub.status.idle":"2024-12-15T19:03:48.485663Z","shell.execute_reply.started":"2024-12-15T19:03:48.474709Z","shell.execute_reply":"2024-12-15T19:03:48.484627Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"BASE_PATH = f\"/kaggle/input/rsna-atd-512x512-png-v2-dataset\"\nRSNA_BASE_PATH = f\"/kaggle/input/rsna-2023-abdominal-trauma-detection\"\nIMAGE_DIR = \"/tmp/dataset/rsna-atd\"\nTEST_IMAGE_DIR = \"/tmp/dataset/test\"\nSTRIDE = 10","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2024-12-15T19:03:48.486892Z","iopub.execute_input":"2024-12-15T19:03:48.487265Z","iopub.status.idle":"2024-12-15T19:03:48.498306Z","shell.execute_reply.started":"2024-12-15T19:03:48.487232Z","shell.execute_reply":"2024-12-15T19:03:48.497264Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Data Pipeline**\n\nconvert DICOM images to PNG (for train dataset)","metadata":{}},{"cell_type":"code","source":"meta_df_1 = pd.read_csv(f\"{RSNA_BASE_PATH}/train_2024.csv\")\nmeta_df_2 = pd.read_csv(f\"{RSNA_BASE_PATH}/train_series_meta.csv\")\n\n# Perform cross product (Cartesian product) on 'patient_id'\n# Renaming columns to avoid column name conflicts\nmeta_df_1 = meta_df_1.rename(columns=lambda x: f\"{x}\" if x != 'patient_id' else x)\nmeta_df_2 = meta_df_2.rename(columns=lambda x: f\"{x}\" if x != 'patient_id' else x)\n\n# Cartesian product using merge without specifying the 'on' argument but using all patient_ids\nmeta_df = pd.merge(meta_df_1, meta_df_2, on=\"patient_id\", how=\"outer\")\n\n# Checking if patients are repeated by finding the number of unique patient IDs\nnum_rows = meta_df.shape[0]\nunique_patients = meta_df[\"patient_id\"].nunique()\n\n# Display the results\nprint(f\"Total number of rows after cross product: {num_rows}\")\nprint(f\"Number of unique patients: {unique_patients}\")\n\n# Display the first few rows of the cross product dataframe to verify\nmeta_df.head()","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:48.499611Z","iopub.execute_input":"2024-12-15T19:03:48.499924Z","iopub.status.idle":"2024-12-15T19:03:48.542526Z","shell.execute_reply.started":"2024-12-15T19:03:48.499893Z","shell.execute_reply":"2024-12-15T19:03:48.541505Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Limit to only 1000 unique patients\n# limited_patient_ids = meta_df[\"patient_id\"].drop_duplicates().sample(n=100, random_state=42)\n# meta_df_limited = meta_df[meta_df[\"patient_id\"].isin(limited_patient_ids)]\n\n# # Checking the number of unique patients in the limited DataFrame\n# limited_num_rows = meta_df_limited.shape[0]\n# limited_unique_patients = meta_df_limited[\"patient_id\"].nunique()\n\n# # Display the results for verification\n# print(f\"Total number of rows after limiting to 1000 patients: {limited_num_rows}\")\n# print(f\"Number of unique patients in the limited DataFrame: {limited_unique_patients}\")\n\n# # Display the first few rows of the limited DataFrame\n# meta_df_limited.head()\n\n# meta_df = meta_df_limited","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:03:48.544086Z","iopub.execute_input":"2024-12-15T19:03:48.544551Z","iopub.status.idle":"2024-12-15T19:03:48.555973Z","shell.execute_reply.started":"2024-12-15T19:03:48.544504Z","shell.execute_reply":"2024-12-15T19:03:48.554908Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%capture\nfrom tqdm import tqdm\nfrom glob import glob\n\nmeta_df[\"dicom_folder\"] = RSNA_BASE_PATH + \"/\" + \"train_images\" \\\n                          + \"/\" + meta_df.patient_id.astype(str) \\\n                          + \"/\" + meta_df.series_id.astype(str)\n\ntrain_folders = meta_df.dicom_folder.tolist()\ntrain_paths = []\nfor folder in tqdm(train_folders):\n    train_paths += sorted(glob(os.path.join(folder, \"*dcm\")))[::STRIDE]","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:48.557763Z","iopub.execute_input":"2024-12-15T19:03:48.558091Z","iopub.status.idle":"2024-12-15T19:03:52.320211Z","shell.execute_reply.started":"2024-12-15T19:03:48.558056Z","shell.execute_reply":"2024-12-15T19:03:52.319326Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.DataFrame(train_paths, columns=[\"dicom_path\"])\ndf[\"patient_id\"] = df.dicom_path.map(lambda x: x.split(\"/\")[-3]).astype(int)\ndf[\"series_id\"] = df.dicom_path.map(lambda x: x.split(\"/\")[-2]).astype(int)\ndf[\"instance_number\"] = df.dicom_path.map(lambda x: x.split(\"/\")[-1].replace(\".dcm\",\"\")).astype(int)\n\ndf[\"image_path\"] = f\"{IMAGE_DIR}/train_images\"\\\n                    + \"/\" + df.patient_id.astype(str)\\\n                    + \"/\" + df.series_id.astype(str)\\\n                    + \"/\" + df.instance_number.astype(str) +\".png\"\n\n# Perform the merge on both 'patient_id' and 'series_id', adding suffixes to handle duplicate columns\ndf_merged = pd.merge(meta_df, df, on=[\"patient_id\", \"series_id\"], how=\"outer\", suffixes=('_meta', '_df'))\n\n# Iterate through columns and drop duplicates (keep the column from 'df' and drop '_meta')\nfor col in df_merged.columns:\n    if col.endswith('_meta') and col.replace('_meta', '') in df_merged.columns:\n        df_merged.drop(columns=[col], inplace=True)\n\n# Rename columns back to remove the '_df' suffix\ndf_merged.columns = df_merged.columns.str.replace('_df', '')\n\ndf_merged = df_merged.iloc[:, :-6].join(df_merged.iloc[:, -3:])\n\n# Display the first few rows to verify the merge result\ndf_merged.head()","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:52.321739Z","iopub.execute_input":"2024-12-15T19:03:52.32219Z","iopub.status.idle":"2024-12-15T19:03:52.397993Z","shell.execute_reply.started":"2024-12-15T19:03:52.322143Z","shell.execute_reply":"2024-12-15T19:03:52.396992Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Checking if patients are repeated by finding the number of unique patient IDs\nnum_rows = df_merged.shape[0]\nunique_patients = df_merged[\"patient_id\"].nunique()\n\nprint(f\"{num_rows=}\")\nprint(f\"{unique_patients=}\")","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:52.404145Z","iopub.execute_input":"2024-12-15T19:03:52.404619Z","iopub.status.idle":"2024-12-15T19:03:52.412203Z","shell.execute_reply.started":"2024-12-15T19:03:52.404585Z","shell.execute_reply":"2024-12-15T19:03:52.411076Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!rm -r {IMAGE_DIR}\nos.makedirs(f\"{IMAGE_DIR}/train_images\", exist_ok=True)\nos.makedirs(f\"{IMAGE_DIR}/test_images\", exist_ok=True)","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:52.413424Z","iopub.execute_input":"2024-12-15T19:03:52.41374Z","iopub.status.idle":"2024-12-15T19:03:53.62882Z","shell.execute_reply.started":"2024-12-15T19:03:52.413711Z","shell.execute_reply":"2024-12-15T19:03:53.627425Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def standardize_pixel_array(dcm):\n    # Correct DICOM pixel_array if PixelRepresentation == 1.\n    pixel_array = dcm.pixel_array\n    if dcm.PixelRepresentation == 1:\n        bit_shift = dcm.BitsAllocated - dcm.BitsStored\n        dtype = pixel_array.dtype \n        new_array = (pixel_array << bit_shift).astype(dtype) >>  bit_shift\n        pixel_array = pydicom.pixel_data_handlers.util.apply_modality_lut(new_array, dcm)\n    return pixel_array\n\ndef read_xray(path, fix_monochrome=True):\n    dicom = pydicom.dcmread(path)\n    data = standardize_pixel_array(dicom)\n    data = data - np.min(data)\n    data = data / (np.max(data) + 1e-5)\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = 1.0 - data\n    return data\n\ndef resize_and_save(file_path):\n    img = read_xray(file_path)\n    h, w = img.shape[:2]  # orig hw\n    img = cv2.resize(img, (config.RESIZE_DIM, config.RESIZE_DIM), cv2.INTER_LINEAR)\n    img = (img * 255).astype(np.uint8)\n    \n    sub_path = file_path.split(\"/\",4)[-1].split(\".dcm\")[0] + \".png\"\n    infos = sub_path.split(\"/\")\n    sub_path = file_path.split(\"/\",4)[-1].split(\".dcm\")[0] + \".png\"\n    infos = sub_path.split(\"/\")\n    pid = infos[-3]\n    sid = infos[-2]\n    iid = infos[-1]; iid = iid.replace(\".png\",\"\")\n    new_path = os.path.join(IMAGE_DIR, sub_path)\n    os.makedirs(new_path.rsplit(\"/\",1)[0], exist_ok=True)\n    cv2.imwrite(new_path, img)\n    return","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:53.630659Z","iopub.execute_input":"2024-12-15T19:03:53.631019Z","iopub.status.idle":"2024-12-15T19:03:53.642422Z","shell.execute_reply.started":"2024-12-15T19:03:53.630985Z","shell.execute_reply":"2024-12-15T19:03:53.641208Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%%time\n\nfile_paths = df_merged.dicom_path.tolist()\n_ = Parallel(n_jobs=2, backend=\"threading\")(\n    delayed(resize_and_save)(file_path) for file_path in tqdm(file_paths, leave=True, position=0)\n)\n\ndel _; gc.collect()","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:03:53.644045Z","iopub.execute_input":"2024-12-15T19:03:53.644449Z","iopub.status.idle":"2024-12-15T19:05:18.291654Z","shell.execute_reply.started":"2024-12-15T19:03:53.644416Z","shell.execute_reply":"2024-12-15T19:05:18.290745Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Split the training set into train and validation","metadata":{}},{"cell_type":"code","source":"# # Function to handle the split for each group\n# def split_group(group, test_size=0.3):\n#     if len(group) == 1:\n#         return (group, pd.DataFrame()) if np.random.rand() < test_size else (pd.DataFrame(), group)\n#     else:\n#         return train_test_split(group, test_size=test_size, random_state=42)\n\n# # Initialize the train and validation datasets\n# train_data = pd.DataFrame()\n# val_data = pd.DataFrame()\n\n# # Iterate through the groups and split them, handling single-sample groups\n# for _, group in df_merged.groupby(config.TARGET_COLS):\n#     train_group, val_group = split_group(group)\n#     train_data = pd.concat([train_data, train_group], ignore_index=True)\n#     val_data = pd.concat([val_data, val_group], ignore_index=True)\n    \n# train_data.shape, val_data.shape\n\n","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:05:18.293034Z","iopub.execute_input":"2024-12-15T19:05:18.293402Z","iopub.status.idle":"2024-12-15T19:05:18.298039Z","shell.execute_reply.started":"2024-12-15T19:05:18.293371Z","shell.execute_reply":"2024-12-15T19:05:18.297055Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import pandas as pd\n\ndef count_organ_health_status(data):\n    \"\"\"\n    Counts the number of rows for healthy and injury organs for each category.\n    \n    Parameters:\n        data (pd.DataFrame): Input DataFrame containing columns for each organ's health status.\n\n    Returns:\n        pd.DataFrame: Summary DataFrame with counts for healthy and injury organs per category.\n    \"\"\"\n    categories = ['bowel', 'extravasation', 'kidney', 'liver', 'spleen']\n    results = []\n\n    for category in categories:\n        if category in ['bowel', 'extravasation']:\n            # Use specific healthy and injury columns for bowel and extravasation\n            healthy_count = data[f'{category}_healthy'].sum()\n            injury_count = data[f'{category}_injury'].sum()\n        else:\n            # For kidney, liver, spleen, infer injury from `healthy == 0`\n            healthy_count = data[f'{category}_healthy'].sum()\n            injury_count = len(data) - healthy_count  # Rows where healthy == 0 are injuries\n\n        results.append({\n            'Organ': category,\n            'Healthy Count': healthy_count,\n            'Injury Count': injury_count\n        })\n\n    # Convert to DataFrame for better visualization\n    summary_df = pd.DataFrame(results)\n    return summary_df\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:18.299496Z","iopub.execute_input":"2024-12-15T19:05:18.299922Z","iopub.status.idle":"2024-12-15T19:05:18.327065Z","shell.execute_reply.started":"2024-12-15T19:05:18.299872Z","shell.execute_reply":"2024-12-15T19:05:18.326066Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def duplicate_all_injured(data):\n    \"\"\"\n    Identifies rows where kidney, liver, and spleen are all injured and duplicates them \n    to match the average number of healthy rows for these organs.\n\n    Parameters:\n        data (pd.DataFrame): Input DataFrame containing `kidney_healthy`, `liver_healthy`, and `spleen_healthy` columns.\n\n    Returns:\n        pd.DataFrame: A new DataFrame with the duplicated rows added.\n    \"\"\"\n    # Identify rows where all three organs are injured\n    all_injured_rows = data[\n        (data['kidney_healthy'] == 0) & \n        (data['liver_healthy'] == 0) & \n        (data['spleen_healthy'] == 0)\n    ]\n\n    # Calculate the average number of healthy rows for these organs\n    healthy_counts = [\n        data['kidney_healthy'].sum(),\n        data['liver_healthy'].sum(),\n        data['spleen_healthy'].sum()\n    ]\n    avg_healthy_count = int(sum(healthy_counts) / len(healthy_counts))\n\n    # Calculate how many rows to duplicate\n    num_injured_rows = len(all_injured_rows)\n    rows_needed = avg_healthy_count - num_injured_rows\n\n    if rows_needed > 0:\n        # Duplicate the rows to balance\n        duplicated_rows = all_injured_rows.sample(n=rows_needed, replace=True, random_state=42)\n        balanced_data = pd.concat([data, duplicated_rows], ignore_index=True)\n    else:\n        # If already balanced or no need to duplicate, return original data\n        balanced_data = data\n\n    return balanced_data\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:18.32832Z","iopub.execute_input":"2024-12-15T19:05:18.328714Z","iopub.status.idle":"2024-12-15T19:05:18.344778Z","shell.execute_reply.started":"2024-12-15T19:05:18.328671Z","shell.execute_reply":"2024-12-15T19:05:18.343818Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"organs_to_balance = ['kidney', 'liver', 'spleen']\nbalanced_df = duplicate_all_injured(df_merged)\nprint(count_organ_health_status(df_merged))\nprint(count_organ_health_status(balanced_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:18.345961Z","iopub.execute_input":"2024-12-15T19:05:18.346275Z","iopub.status.idle":"2024-12-15T19:05:18.373251Z","shell.execute_reply.started":"2024-12-15T19:05:18.346245Z","shell.execute_reply":"2024-12-15T19:05:18.372206Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\nimport pandas as pd\nimport numpy as np\n\n# Function to handle stratified sampling for each group\ndef stratified_split_group(group, test_size=0.3):\n    if len(group) == 1:\n        # Handle single-sample groups\n        return (group, pd.DataFrame()) if np.random.rand() < test_size else (pd.DataFrame(), group)\n    else:\n        # Perform stratified split\n        return train_test_split(group, test_size=test_size, random_state=42, stratify=group[config.TARGET_COLS])\n\n# Initialize the train and validation datasets\ntrain_data = pd.DataFrame()\nval_data = pd.DataFrame()\n\n# Iterate through the groups and split them, handling single-sample groups\nfor _, group in balanced_df.groupby(config.TARGET_COLS):\n    train_group, val_group = stratified_split_group(group)\n    train_data = pd.concat([train_data, train_group], ignore_index=True)\n    val_data = pd.concat([val_data, val_group], ignore_index=True)\n\nprint(f\"Training data shape: {train_data.shape}\")\nprint(f\"Validation data shape: {val_data.shape}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:18.374806Z","iopub.execute_input":"2024-12-15T19:05:18.375546Z","iopub.status.idle":"2024-12-15T19:05:18.533267Z","shell.execute_reply.started":"2024-12-15T19:05:18.375501Z","shell.execute_reply":"2024-12-15T19:05:18.532428Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(count_organ_health_status(val_data))\nprint(count_organ_health_status(train_data))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:18.534401Z","iopub.execute_input":"2024-12-15T19:05:18.534675Z","iopub.status.idle":"2024-12-15T19:05:18.545294Z","shell.execute_reply.started":"2024-12-15T19:05:18.534648Z","shell.execute_reply":"2024-12-15T19:05:18.544085Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def decode_image_and_label(image_path, label):\n    file_bytes = tf.io.read_file(image_path)\n    image = tf.io.decode_png(file_bytes, channels=3, dtype=tf.uint8)\n    image = tf.image.resize(image, config.IMAGE_SIZE, method=\"bilinear\")\n    image = tf.cast(image, tf.float32) / 255.0\n    \n    label = tf.cast(label, tf.float32)\n    #         bowel       fluid       kidney      liver       spleen\n    labels = (label[0:1], label[1:2], label[2:5], label[5:8], label[8:11])\n    \n    return (image, labels)\n\n\naugmenter = keras.Sequential([\n    layers.RandomFlip(mode='horizontal_and_vertical'),\n    layers.RandomRotation(factor=0.2),\n    layers.RandomZoom(height_factor=0.2, width_factor=0.2),\n    layers.RandomContrast(0.2)\n])\n\ndef apply_augmentation(images, labels):\n    # Use the already created augmenter here\n    augmented_images = augmenter(images)\n    return augmented_images, labels\n\n\n\n\ndef build_dataset(image_paths, labels):\n    ds = (\n        tf.data.Dataset.from_tensor_slices((image_paths, labels))\n        .map(decode_image_and_label, num_parallel_calls=config.AUTOTUNE)\n        .shuffle(config.BATCH_SIZE * 10)\n        .batch(config.BATCH_SIZE)\n        .map(apply_augmentation, num_parallel_calls=config.AUTOTUNE)\n        .prefetch(config.AUTOTUNE)\n    )\n    return ds\n","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:05:18.546751Z","iopub.execute_input":"2024-12-15T19:05:18.547103Z","iopub.status.idle":"2024-12-15T19:05:18.604221Z","shell.execute_reply.started":"2024-12-15T19:05:18.547055Z","shell.execute_reply":"2024-12-15T19:05:18.603252Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Example origin_paths and origin_labels\npaths  = train_data.image_path.tolist()\nlabels = train_data[config.TARGET_COLS].values\n\nds = build_dataset(image_paths=paths, labels=labels)\nimages, labels = next(iter(ds))\nimages.shape, [label.shape for label in labels]","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:05:18.605725Z","iopub.execute_input":"2024-12-15T19:05:18.606036Z","iopub.status.idle":"2024-12-15T19:05:32.019487Z","shell.execute_reply.started":"2024-12-15T19:05:18.606006Z","shell.execute_reply":"2024-12-15T19:05:32.018435Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# No more customizing your plots by hand, KerasCV has your back ;)\nkeras_cv.visualization.plot_image_gallery(\n    images=images,\n    value_range=(0, 1),\n    rows=2,\n    cols=2,\n)","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:05:32.021197Z","iopub.execute_input":"2024-12-15T19:05:32.02164Z","iopub.status.idle":"2024-12-15T19:05:32.552167Z","shell.execute_reply.started":"2024-12-15T19:05:32.021594Z","shell.execute_reply":"2024-12-15T19:05:32.551069Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\ndef build_model(warmup_steps, decay_steps):\n    # Define Input\n    inputs = keras.Input(shape=(256, 256, 3), batch_size=config.BATCH_SIZE)\n\n    # Preprocessing Layer for EfficientNetV2\n    preprocess = tf.keras.applications.efficientnet_v2.preprocess_input\n    x = preprocess(inputs)\n    \n    # Define Backbone using EfficientNetV2S\n    base_model = tf.keras.applications.EfficientNetV2S(\n        weights='imagenet',  # Load pretrained weights from ImageNet\n        include_top=False,   # No classification head\n        input_shape=(256, 256, 3)\n    )\n    base_model.trainable = True  # Set to False if freezing is needed\n    x = base_model(x)\n\n    # Global Average Pooling\n    gap = layers.GlobalAveragePooling2D()(x)\n    \n    # Adding complexity to each \"neck\"\n    def complex_neck(inputs):\n        x = layers.Dense(64, activation='silu')(inputs)\n        x = layers.BatchNormalization()(x)\n        x = layers.Dropout(0.3)(x)\n        x = layers.Dense(32, activation='silu')(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.Dropout(0.2)(x)\n        return x\n\n    # Define 'necks' for each head\n    x_bowel = complex_neck(gap)\n    x_extra = complex_neck(gap)\n    x_liver = complex_neck(gap)\n    x_kidney = complex_neck(gap)\n    x_spleen = complex_neck(gap)\n    \n    # Define heads for each target output\n    out_bowel = layers.Dense(1, name='bowel', activation='sigmoid')(x_bowel)\n    out_extra = layers.Dense(1, name='extra', activation='sigmoid')(x_extra)\n    out_liver = layers.Dense(3, name='liver', activation='softmax')(x_liver)\n    out_kidney = layers.Dense(3, name='kidney', activation='softmax')(x_kidney)\n    out_spleen = layers.Dense(3, name='spleen', activation='softmax')(x_spleen)\n    \n    # Combine all outputs\n    outputs = [out_bowel, out_extra, out_liver, out_kidney, out_spleen]\n    \n    # Create the Model\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    \n    # Custom learning rate schedule class (unchanged)\n    @tf.keras.utils.register_keras_serializable()\n    class WarmUpCosineDecaySchedule(tf.keras.optimizers.schedules.LearningRateSchedule):\n        def __init__(self, initial_lr, warmup_steps, decay_steps):\n            self.initial_lr = initial_lr\n            self.warmup_steps = warmup_steps\n            self.decay_steps = decay_steps\n\n        def __call__(self, step):\n            lr = tf.cond(\n                step < self.warmup_steps,\n                lambda: self.initial_lr * (tf.cast(step, tf.float32) / tf.cast(self.warmup_steps, tf.float32)),\n                lambda: self.initial_lr * 0.5 * (1 + tf.cos(tf.constant(np.pi, dtype=tf.float32) * \n                       (tf.cast(step, tf.float32) - tf.cast(self.warmup_steps, tf.float32)) / \n                       tf.cast((self.decay_steps - self.warmup_steps), tf.float32)))\n            )\n            return lr\n\n        def get_config(self):\n            return {\n                \"initial_lr\": self.initial_lr,\n                \"warmup_steps\": self.warmup_steps,\n                \"decay_steps\": self.decay_steps,\n            }\n\n    # Set initial learning rate and schedule\n    initial_learning_rate = 1e-4\n    lr_schedule = WarmUpCosineDecaySchedule(\n        initial_lr=initial_learning_rate,\n        warmup_steps=warmup_steps,\n        decay_steps=decay_steps\n    )\n    \n    # Define Optimizer\n    optimizer = keras.optimizers.Adam(learning_rate=lr_schedule)\n    \n    # Define Losses\n    loss = {\n        \"bowel\": keras.losses.BinaryCrossentropy(),\n        \"extra\": keras.losses.BinaryCrossentropy(),\n        \"liver\": keras.losses.CategoricalCrossentropy(),\n        \"kidney\": keras.losses.CategoricalCrossentropy(),\n        \"spleen\": keras.losses.CategoricalCrossentropy(),\n    }\n    \n    # Define Metrics\n    metrics = {\n        \"bowel\": [\"accuracy\"],\n        \"extra\": [\"accuracy\"],\n        \"liver\": [\"accuracy\"],\n        \"kidney\": [\"accuracy\"],\n        \"spleen\": [\"accuracy\"],\n    }\n\n    # Compile the Model\n    model.compile(\n        optimizer=optimizer,\n        loss=loss,\n        metrics=metrics\n    )\n    \n    return model\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:32.554077Z","iopub.execute_input":"2024-12-15T19:05:32.554563Z","iopub.status.idle":"2024-12-15T19:05:32.573924Z","shell.execute_reply.started":"2024-12-15T19:05:32.554502Z","shell.execute_reply":"2024-12-15T19:05:32.572686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# get image_paths and labels\nprint(\"[INFO] Building the dataset...\")\ntrain_paths = train_data.image_path.values; train_labels = train_data[config.TARGET_COLS].values.astype(np.float32)\nvalid_paths = val_data.image_path.values; valid_labels = val_data[config.TARGET_COLS].values.astype(np.float32)\n\n# train and valid dataset\ntrain_ds = build_dataset(image_paths=train_paths, labels=train_labels)\nval_ds = build_dataset(image_paths=valid_paths, labels=valid_labels)\n\n# Calculate total steps, warmup, and decay steps\ntotal_train_steps = train_ds.cardinality().numpy() * config.BATCH_SIZE * config.EPOCHS\nwarmup_steps = int(total_train_steps * 0.10)\ndecay_steps = total_train_steps - warmup_steps\n\nprint(f\"{total_train_steps=}\")\nprint(f\"{warmup_steps=}\")\nprint(f\"{decay_steps=}\")","metadata":{"execution":{"iopub.status.busy":"2024-12-15T19:05:32.575523Z","iopub.execute_input":"2024-12-15T19:05:32.576505Z","iopub.status.idle":"2024-12-15T19:05:34.092302Z","shell.execute_reply.started":"2024-12-15T19:05:32.576454Z","shell.execute_reply":"2024-12-15T19:05:34.091107Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def pred_decode_image(image_path):\n    file_bytes = tf.io.read_file(image_path)\n    image = tf.io.decode_png(file_bytes, channels=3, dtype=tf.uint8)\n    image = tf.image.resize(image, config.IMAGE_SIZE, method=\"bilinear\")\n    image = tf.cast(image, tf.float32) / 255.0\n    return image\n\ndef pred_build_dataset(image_paths):\n    ds = (\n        tf.data.Dataset.from_tensor_slices(image_paths)\n        .map(pred_decode_image, num_parallel_calls=config.AUTOTUNE)\n        .shuffle(config.BATCH_SIZE * 10)\n        .batch(config.BATCH_SIZE)\n        .prefetch(config.AUTOTUNE)\n    )\n    return ds","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.093497Z","iopub.execute_input":"2024-12-15T19:05:34.093816Z","iopub.status.idle":"2024-12-15T19:05:34.100311Z","shell.execute_reply.started":"2024-12-15T19:05:34.093785Z","shell.execute_reply":"2024-12-15T19:05:34.099191Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def post_proc(pred):\n    \"\"\"\n    Maps 11 model outputs to 13 target columns.\n    \"\"\"\n    proc_pred = np.empty((pred.shape[0], 13), dtype=\"float32\")\n\n    # bowel (binary: injury, healthy)\n    proc_pred[:, 0] = pred[:, 0]  # bowel_injury\n    proc_pred[:, 1] = 1 - proc_pred[:, 0]  # bowel_healthy\n\n    # extravasation (binary: injury, healthy)\n    proc_pred[:, 2] = pred[:, 1]  # extravasation_injury\n    proc_pred[:, 3] = 1 - proc_pred[:, 2]  # extravasation_healthy\n\n    # kidney (multi-class: healthy, low, high)\n    proc_pred[:, 4:7] = pred[:, 2:5]\n\n    # liver (multi-class: healthy, low, high)\n    proc_pred[:, 7:10] = pred[:, 5:8]\n\n    # spleen (multi-class: healthy, low, high)\n    proc_pred[:, 10:13] = pred[:, 8:11]\n\n    return proc_pred","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.101663Z","iopub.execute_input":"2024-12-15T19:05:34.102036Z","iopub.status.idle":"2024-12-15T19:05:34.114039Z","shell.execute_reply.started":"2024-12-15T19:05:34.101973Z","shell.execute_reply":"2024-12-15T19:05:34.113076Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(valid_labels[0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.115457Z","iopub.execute_input":"2024-12-15T19:05:34.115764Z","iopub.status.idle":"2024-12-15T19:05:34.130657Z","shell.execute_reply.started":"2024-12-15T19:05:34.115735Z","shell.execute_reply":"2024-12-15T19:05:34.129699Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay, precision_score, recall_score, f1_score\n\nclass MetricsCallback(tf.keras.callbacks.Callback):\n    def __init__(self, valid_paths, valid_labels, pred_build_dataset, target_cols, threshold=0.5, output_dir=\"metrics_output\"):\n        \"\"\"\n        Args:\n            valid_paths (list): List of image paths for validation.\n            valid_labels (numpy array): Corresponding labels for the validation paths.\n            pred_build_dataset (function): Function to build the dataset for prediction.\n            target_cols (list): List of target column names.\n            threshold (float): Threshold for binary classification.\n            output_dir (str): Directory to save metrics outputs.\n        \"\"\"\n        super().__init__()\n        self.valid_paths = valid_paths\n        self.valid_labels = valid_labels\n        self.pred_build_dataset = pred_build_dataset\n        self.target_cols = target_cols\n        self.threshold = threshold\n        self.output_dir = output_dir\n\n        # Create output directory if it doesn't exist\n        os.makedirs(output_dir, exist_ok=True)\n\n    def on_epoch_end(self, epoch, logs=None):\n        # Build dataset from valid_paths\n        dval = self.pred_build_dataset(self.valid_paths)\n\n        # Predict with the model\n        preds = self.model.predict(dval)\n\n        # Ensure predictions are concatenated correctly for multi-output models\n        if isinstance(preds, list):\n            preds = np.concatenate(preds, axis=-1)\n\n        # Post-process predictions to align with target columns\n        preds = post_proc(preds)\n\n        # Check shape consistency\n        if preds.shape[0] != len(self.valid_labels):\n            raise ValueError(\n                f\"Mismatch between number of predictions ({preds.shape[0]}) and labels ({len(self.valid_labels)}).\"\n            )\n\n        # Initialize binary predictions\n        binary_preds = preds.copy()\n\n        # Set binary predictions for kidney, liver, spleen\n        for organ, indices in zip(\n            [\"kidney\", \"liver\", \"spleen\"], \n            [(4, 5, 6), (7, 8, 9), (10, 11, 12)]  # Multi-class indices for each organ\n        ):\n            organ_preds = preds[:, indices]  # Extract predictions for the organ\n            max_indices = np.argmax(organ_preds, axis=1)  # Get the index of the largest value\n            binary_preds[:, indices] = 0  # Set all values to 0\n            binary_preds[np.arange(len(preds)), indices[0] + max_indices] = 1  # Set max value to 1\n\n        # Threshold predictions for binary targets (e.g., bowel, extravasation)\n        binary_preds[:, :4] = (preds[:, :4] > self.threshold).astype(int)\n\n        # Open a file to save predictions for this epoch\n        epoch_output_dir = os.path.join(self.output_dir, f\"epoch_{epoch+1}\")\n        os.makedirs(epoch_output_dir, exist_ok=True)\n        predictions_file = os.path.join(epoch_output_dir, f\"predictions_epoch_{epoch+1}.txt\")\n\n        with open(predictions_file, \"w\") as f:\n            # Compute confusion matrix and metrics for each target column\n            for i, target in enumerate(self.target_cols):\n                y_true = self.valid_labels[:, i]\n                y_pred = binary_preds[:, i]\n\n                # Save predictions and ground truth\n                f.write(f\"Target: {target}\\n\")\n                f.write(f\"Raw Predictions: {preds[:, i].tolist()}\\n\")\n                f.write(f\"Binary Predictions: {y_pred.tolist()}\\n\")\n                f.write(f\"Ground Truth: {y_true.tolist()}\\n\\n\")\n\n                # Compute confusion matrix\n                cm_labels = [0, 1]\n                cm = confusion_matrix(y_true, y_pred, labels=cm_labels)\n\n                # Save confusion matrix plot\n                disp = ConfusionMatrixDisplay(confusion_matrix=cm, display_labels=cm_labels)\n                disp.plot(cmap=plt.cm.Blues)\n                plt.title(f'Confusion Matrix for {target} (Epoch {epoch + 1})')\n\n                cm_plot_file = os.path.join(epoch_output_dir, f\"confusion_matrix_{target}.png\")\n                plt.savefig(cm_plot_file)\n                plt.close()\n\n                # Compute precision, recall, and F1-score\n                precision = precision_score(y_true, y_pred, average=\"binary\")\n                recall = recall_score(y_true, y_pred, average=\"binary\")\n                f1 = f1_score(y_true, y_pred, average=\"binary\")\n\n                # Save metrics to the file\n                f.write(f\"{target} - Precision: {precision:.4f}, Recall: {recall:.4f}, F1-Score: {f1:.4f}\\n\\n\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.136686Z","iopub.execute_input":"2024-12-15T19:05:34.13705Z","iopub.status.idle":"2024-12-15T19:05:34.153983Z","shell.execute_reply.started":"2024-12-15T19:05:34.137019Z","shell.execute_reply":"2024-12-15T19:05:34.15291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def update_valid_labels(valid_labels):\n    \"\"\"\n    Update the valid_labels to include both healthy and injury labels for bowel and extravasation.\n    \"\"\"\n    updated_labels = np.zeros((valid_labels.shape[0], 13), dtype=\"float32\")\n    \n    # bowel (binary: injury, healthy)\n    updated_labels[:, 0] = valid_labels[:, 0]  # bowel_injury\n    updated_labels[:, 1] = 1 - updated_labels[:, 0]  # bowel_healthy\n\n    # extravasation (binary: injury, healthy)\n    updated_labels[:, 2] = valid_labels[:, 1]  # extravasation_injury\n    updated_labels[:, 3] = 1 - updated_labels[:, 2]  # extravasation_healthy\n\n    # kidney (multi-class: healthy, low, high)\n    updated_labels[:, 4:7] = valid_labels[:, 2:5]\n\n    # liver (multi-class: healthy, low, high)\n    updated_labels[:, 7:10] = valid_labels[:, 5:8]\n\n    # spleen (multi-class: healthy, low, high)\n    updated_labels[:, 10:13] = valid_labels[:, 8:11]\n\n    return updated_labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.155462Z","iopub.execute_input":"2024-12-15T19:05:34.156214Z","iopub.status.idle":"2024-12-15T19:05:34.170653Z","shell.execute_reply.started":"2024-12-15T19:05:34.156166Z","shell.execute_reply":"2024-12-15T19:05:34.169703Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define the target columns (both healthy and injury for bowel and extravasation)\nTARGET_COLS = [\n    \"bowel_healthy\", \"bowel_injury\",  # Healthy and injury for bowel\n    \"extravasation_healthy\", \"extravasation_injury\",  # Healthy and injury for extravasation\n    \"kidney_healthy\", \"kidney_low\", \"kidney_high\",\n    \"liver_healthy\", \"liver_low\", \"liver_high\",\n    \"spleen_healthy\", \"spleen_low\", \"spleen_high\",\n]\n\n# Assuming valid_labels has 11 columns, we update it to match the 13 target columns\nvalid_labels_updated = update_valid_labels(valid_labels)\n\n# Initialize the metrics callback\nmetrics_callback = MetricsCallback(\n    valid_paths=valid_paths,\n    valid_labels=valid_labels_updated,\n    pred_build_dataset=pred_build_dataset,  # Replace with your function\n    target_cols=TARGET_COLS,\n    threshold=0.5\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.172237Z","iopub.execute_input":"2024-12-15T19:05:34.17258Z","iopub.status.idle":"2024-12-15T19:05:34.187204Z","shell.execute_reply.started":"2024-12-15T19:05:34.172547Z","shell.execute_reply":"2024-12-15T19:05:34.186186Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(valid_labels_updated[0])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.188535Z","iopub.execute_input":"2024-12-15T19:05:34.188872Z","iopub.status.idle":"2024-12-15T19:05:34.198536Z","shell.execute_reply.started":"2024-12-15T19:05:34.188841Z","shell.execute_reply":"2024-12-15T19:05:34.197384Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Build the model\nprint(\"[INFO] Building the model...\")\nmodel = build_model(warmup_steps, decay_steps)\n\n\n# Model checkpointing to save the best model\ncheckpoint_cb = keras.callbacks.ModelCheckpoint(\n    filepath='best_model.keras',\n    save_best_only=True,  # Only save the model with the best validation loss\n    monitor='val_loss',   # Monitor validation loss\n    mode='min',           # Minimize the validation loss\n    verbose=1             # Print a message when saving the model\n)\n\n# Early stopping to prevent overfitting\nearly_stopping = keras.callbacks.EarlyStopping(\n    monitor='val_loss', \n    patience=5,  # Stop training if validation loss doesn't improve for 5 epochs\n    restore_best_weights=True\n)\n\n# Train the model without class_weight\nhistory = model.fit(\n    train_ds,\n    epochs=config.EPOCHS,\n    validation_data=val_ds,\n    callbacks=[checkpoint_cb]  # Use early stopping and checkpoint\n)","metadata":{"_kg_hide-input":true,"_kg_hide-output":false,"execution":{"iopub.status.busy":"2024-12-15T19:05:34.199934Z","iopub.execute_input":"2024-12-15T19:05:34.200887Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Visualize the training plots","metadata":{}},{"cell_type":"code","source":"# Create a 3x2 grid for the subplots\nfig, axes = plt.subplots(5, 1, figsize=(5, 15))\n\n# Flatten axes to iterate through them\naxes = axes.flatten()\n\n# Iterate through the metrics and plot them\nfor i, name in enumerate([\"bowel\", \"extra\", \"kidney\", \"liver\", \"spleen\"]):\n    # Plot training accuracy\n    axes[i].plot(history.history[name + '_accuracy'], label='Training ' + name)\n    # Plot validation accuracy\n    axes[i].plot(history.history['val_' + name + '_accuracy'], label='Validation ' + name)\n    axes[i].set_title(name)\n    axes[i].set_xlabel('Epoch')\n    axes[i].set_ylabel('Accuracy')\n    axes[i].legend()\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# store best results\nbest_epoch = np.argmin(history.history['val_loss'])\nbest_loss = history.history['val_loss'][best_epoch]\nbest_acc_bowel = history.history['val_bowel_accuracy'][best_epoch]\nbest_acc_extra = history.history['val_extra_accuracy'][best_epoch]\nbest_acc_liver = history.history['val_liver_accuracy'][best_epoch]\nbest_acc_kidney = history.history['val_kidney_accuracy'][best_epoch]\nbest_acc_spleen = history.history['val_spleen_accuracy'][best_epoch]\n\n# Find mean accuracy\nbest_acc = np.mean(\n    [best_acc_bowel,\n     best_acc_extra,\n     best_acc_liver,\n     best_acc_kidney,\n     best_acc_spleen\n])\n\n\nprint(f'>>>> BEST Loss  : {best_loss:.3f}\\n>>>> BEST Acc   : {best_acc:.3f}\\n>>>> BEST Epoch : {best_epoch}\\n')\nprint('ORGAN Acc:')\nprint(f'  >>>> {\"Bowel\".ljust(15)} : {best_acc_bowel:.3f}')\nprint(f'  >>>> {\"Extravasation\".ljust(15)} : {best_acc_extra:.3f}')\nprint(f'  >>>> {\"Liver\".ljust(15)} : {best_acc_liver:.3f}')\nprint(f'  >>>> {\"Kidney\".ljust(15)} : {best_acc_kidney:.3f}')\nprint(f'  >>>> {\"Spleen\".ljust(15)} : {best_acc_spleen:.3f}')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Store the model for inference","metadata":{}},{"cell_type":"code","source":"# Define output paths\noutput_dir = '/kaggle/working/output'\nos.makedirs(output_dir, exist_ok=True)\n\n# Save performance metrics to a CSV file\nresults_file = os.path.join(output_dir, 'performance_metrics.csv')\nresults_df = pd.DataFrame({\n    \"Epoch\": [best_epoch],\n    \"Best_Loss\": [best_loss],\n    \"Best_Acc\": [best_acc],\n    \"Bowel_Accuracy\": [best_acc_bowel],\n    \"Extravasation_Accuracy\": [best_acc_extra],\n    \"Liver_Accuracy\": [best_acc_liver],\n    \"Kidney_Accuracy\": [best_acc_kidney],\n    \"Spleen_Accuracy\": [best_acc_spleen],\n})\nresults_df.to_csv(results_file, index=False)\n\n# Save loss and accuracy plot\nplt.figure(figsize=(10, 6))\nplt.plot(history.history[\"loss\"], label=\"Training Loss\")\nplt.plot(history.history[\"val_loss\"], label=\"Validation Loss\")\nplt.title(\"Loss Over Epochs\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.grid(True)\nplt.savefig(os.path.join(output_dir, 'loss_plot.png'))\n\nplt.figure(figsize=(10, 6))\nplt.plot(history.history['bowel_accuracy'], label='Bowel Accuracy')\nplt.plot(history.history['extra_accuracy'], label='Extravasation Accuracy')\nplt.plot(history.history['liver_accuracy'], label='Liver Accuracy')\nplt.plot(history.history['kidney_accuracy'], label='Kidney Accuracy')\nplt.plot(history.history['spleen_accuracy'], label='Spleen Accuracy')\nplt.title(f\"Organ Accuracy Over Epochs (Train)\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid(True)\nplt.savefig(os.path.join(output_dir, 'organ_accuracy_plot_train.png'))\n\nplt.figure(figsize=(10, 6))\nplt.plot(history.history['val_bowel_accuracy'], label='Bowel Accuracy')\nplt.plot(history.history['val_extra_accuracy'], label='Extravasation Accuracy')\nplt.plot(history.history['val_liver_accuracy'], label='Liver Accuracy')\nplt.plot(history.history['val_kidney_accuracy'], label='Kidney Accuracy')\nplt.plot(history.history['val_spleen_accuracy'], label='Spleen Accuracy')\nplt.title(f\"Organ Accuracy Over Epochs (Validation)\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid(True)\nplt.savefig(os.path.join(output_dir, 'organ_accuracy_plot_val.png'))\n\nprint(f'All results saved to: {output_dir}')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save('best_model.keras')\nmodel.summary()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_meta_df = pd.read_csv(f\"{RSNA_BASE_PATH}/test_series_meta.csv\")\n\n# # Checking if patients are repeated by finding the number of unique patient IDs\n# num_rows = test_meta_df.shape[0]\n# unique_patients = test_meta_df[\"patient_id\"].nunique()\n\n# print(f\"{num_rows=}\")\n# print(f\"{unique_patients=}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_meta_df[\"dicom_folder\"] = RSNA_BASE_PATH + \"/\" + \"test_images\"\\\n#                                     + \"/\" + test_meta_df.patient_id.astype(str)\\\n#                                     + \"/\" + test_meta_df.series_id.astype(str)\n\n# test_folders = test_meta_df.dicom_folder.tolist()\n# test_paths = []\n# for folder in tqdm(test_folders):\n#     test_paths += sorted(glob(os.path.join(folder, \"*dcm\")))[::STRIDE]","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# test_df = pd.DataFrame(test_paths, columns=[\"dicom_path\"])\n# test_df[\"patient_id\"] = test_df.dicom_path.map(lambda x: x.split(\"/\")[-3]).astype(int)\n# test_df[\"series_id\"] = test_df.dicom_path.map(lambda x: x.split(\"/\")[-2]).astype(int)\n# test_df[\"instance_number\"] = test_df.dicom_path.map(lambda x: x.split(\"/\")[-1].replace(\".dcm\",\"\")).astype(int)\n\n# test_df[\"image_path\"] = f\"{IMAGE_DIR}/test_images\"\\\n#                     + \"/\" + test_df.patient_id.astype(str)\\\n#                     + \"/\" + test_df.series_id.astype(str)\\\n#                     + \"/\" + test_df.instance_number.astype(str) +\".png\"\n\n# test_df.head(2)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Checking if patients are repeated by finding the number of unique patient IDs\n# num_rows = test_df.shape[0]\n# unique_patients = test_df[\"patient_id\"].nunique()\n\n# print(f\"{num_rows=}\")\n# print(f\"{unique_patients=}\")","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# !rm -r {IMAGE_DIR}\n# os.makedirs(f\"{TEST_IMAGE_DIR}/train_images\", exist_ok=True)\n# os.makedirs(f\"{TEST_IMAGE_DIR}/test_images\", exist_ok=True)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# %%time\n\n# file_paths = test_df.dicom_path.tolist()\n# _ = Parallel(n_jobs=2, backend=\"threading\")(\n#     delayed(resize_and_save)(file_path) for file_path in tqdm(file_paths, leave=True, position=0)\n# )\n\n# del _; gc.collect()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# def decode_image(image_path):\n#     file_bytes = tf.io.read_file(image_path)\n#     image = tf.io.decode_png(file_bytes, channels=3, dtype=tf.uint8)\n#     image = tf.image.resize(image, config.IMAGE_SIZE, method=\"bilinear\")\n#     image = tf.cast(image, tf.float32) / 255.0\n#     return image\n\n# def build_dataset(image_paths):\n#     ds = (\n#         tf.data.Dataset.from_tensor_slices(image_paths)\n#         .map(decode_image, num_parallel_calls=config.AUTOTUNE)\n#         .shuffle(config.BATCH_SIZE * 10)\n#         .batch(config.BATCH_SIZE)\n#         .prefetch(config.AUTOTUNE)\n#     )\n#     return ds","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# paths  = test_df.image_path.tolist()\n\n# ds = build_dataset(paths)\n# images = next(iter(ds))\n\n# images.shape","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# keras_cv.visualization.plot_image_gallery(\n#     images=images,\n#     value_range=(0, 1),\n#     rows=1,\n#     cols=3,\n# )","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"INFERENCE","metadata":{}},{"cell_type":"code","source":"# def post_proc(pred):\n#     proc_pred = np.empty((pred.shape[0], 2*2 + 3*3), dtype=\"float32\")\n\n#     # bowel, extravasation\n#     proc_pred[:, 0] = pred[:, 0]\n#     proc_pred[:, 1] = 1 - proc_pred[:, 0]\n#     proc_pred[:, 2] = pred[:, 1]\n#     proc_pred[:, 3] = 1 - proc_pred[:, 2]\n    \n#     # liver, kidney, sneel\n#     proc_pred[:, 4:7] = pred[:, 2:5]\n#     proc_pred[:, 7:10] = pred[:, 5:8]\n#     proc_pred[:, 10:13] = pred[:, 8:11]\n\n#     return proc_pred","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Getting unique patient IDs from test dataset\n# patient_ids = test_df[\"patient_id\"].unique()\n\n# # Initializing array to store predictions\n# patient_preds = np.zeros(\n#     shape=(len(patient_ids), 2*2 + 3*3),\n#     dtype=\"float32\"\n# )\n\n# # Iterating over each patient\n# for pidx, patient_id in tqdm(enumerate(patient_ids), total=len(patient_ids), desc=\"Patients \"):\n#     print(f\"Patient ID: {patient_id}\")\n    \n#     # Query the dataframe for a particular patient\n#     patient_df = test_df.query(\"patient_id == @patient_id\")\n    \n#     # Getting image paths for a patient\n#     patient_paths = patient_df.image_path.tolist()\n\n#     # Building dataset for prediction\n#     dtest = build_dataset(patient_paths)\n    \n#     # Predicting with the model\n#     pred = model.predict(dtest)\n#     pred = np.concatenate(pred, axis=-1).astype(\"float32\")\n#     pred = pred[:len(patient_paths), :]\n#     pred = np.mean(pred.reshape(1, len(patient_paths), 11), axis=0)\n#     pred = np.max(pred, axis=0, keepdims=True)\n    \n#     patient_preds[pidx, :] += post_proc(pred)[0]\n    \n\n#     # Deleting variables to free up memory \n#     del patient_df, patient_paths, dtest, pred; gc.collect()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# TARGET_COLS  = [\n#         \"bowel_healthy\", \"bowel_injury\",  \"extravasation_healthy\", \"extravasation_injury\",\n#         \"kidney_healthy\", \"kidney_low\", \"kidney_high\",\n#         \"liver_healthy\", \"liver_low\", \"liver_high\",\n#         \"spleen_healthy\", \"spleen_low\", \"spleen_high\",\n#     ]\n\n# # Create Submission\n# pred_df = pd.DataFrame({\"patient_id\":patient_ids,})\n# pred_df[TARGET_COLS] = patient_preds.astype(\"float32\")\n\n# # Align with sample submission\n# sub_df = pd.read_csv(f\"{RSNA_BASE_PATH}/sample_submission.csv\")\n# sub_df = sub_df[[\"patient_id\"]]\n# sub_df = sub_df.merge(pred_df, on=\"patient_id\", how=\"left\")\n\n# sub_df.head()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}