{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":52254,"databundleVersionId":6863140,"sourceType":"competition"},{"sourceId":6211844,"sourceType":"datasetVersion","datasetId":3567114},{"sourceId":7184233,"sourceType":"datasetVersion","datasetId":4152977}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"<center><img src=\"https://keras.io/img/logo-small.png\" alt=\"Keras logo\" width=\"100\"><br/>\nThis starter notebook is provided by the Keras team.</center>","metadata":{}},{"cell_type":"markdown","source":"# Setup and Imports\n","metadata":{}},{"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":"2023-12-12T18:25:55.384714Z","iopub.execute_input":"2023-12-12T18:25:55.385089Z","iopub.status.idle":"2023-12-12T18:26:26.930416Z","shell.execute_reply.started":"2023-12-12T18:25:55.385061Z","shell.execute_reply":"2023-12-12T18:26:26.929316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:26.932255Z","iopub.execute_input":"2023-12-12T18:26:26.932566Z","iopub.status.idle":"2023-12-12T18:26:44.95516Z","shell.execute_reply.started":"2023-12-12T18:26:26.932537Z","shell.execute_reply":"2023-12-12T18:26:44.954222Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Configuration\n\nA particularly good practise is to have a configuration class for your notebooks. This not only keeps your configurations all at a single place but also becomes handy to map the configs to the performance of the model.\n\nPlease play around with the configurations and see how the performance of the model changes.","metadata":{}},{"cell_type":"markdown","source":"## Note on some observations\n\n\n1. Class Dependencies: Refers to inherent relationships between classes in the analysis.\n2. Complementarity: `bowel_injury` and `bowel_healthy`, as well as `extravasation_injury` and `extravasation_healthy`, are perfectly complementary, with their sum always equal to 1.0.\n3. Simplification: For the model, only `{bowel/extravasation}_injury` will be included, and the corresponding healthy status can be calculated using a sigmoid function.\n4. Softmax: `{kidney/liver/spleen}_{healthy/low/high}` classifications are softmaxed, ensuring their combined probabilities sum up to 1.0 for each organ, simplifying the model while preserving essential information.","metadata":{}},{"cell_type":"code","source":"class Config:\n    SEED = 42\n    IMAGE_SIZE = [256, 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":"2023-12-12T18:26:44.956506Z","iopub.execute_input":"2023-12-12T18:26:44.957294Z","iopub.status.idle":"2023-12-12T18:26:44.96693Z","shell.execute_reply.started":"2023-12-12T18:26:44.95725Z","shell.execute_reply":"2023-12-12T18:26:44.96603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Reproducibility\n\nWe would want this notebook to have reproducible results. Here we set the seed for all the random algorithms so that we can reproduce the experiments each time exactly the same way.","metadata":{}},{"cell_type":"code","source":"keras.utils.set_random_seed(seed=config.SEED)","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:44.969611Z","iopub.execute_input":"2023-12-12T18:26:44.970349Z","iopub.status.idle":"2023-12-12T18:26:44.991883Z","shell.execute_reply.started":"2023-12-12T18:26:44.970314Z","shell.execute_reply":"2023-12-12T18:26:44.990918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset\n\nThe dataset provided in the competition consists of DICOM images. We will not be training on the DICOM images, rather would work on PNG image which are extracted from the DICOM format.\n\n[A helpful resource on the conversion of DICOM to PNG](https://www.kaggle.com/code/radek1/how-to-process-dicom-images-to-pngs)","metadata":{}},{"cell_type":"code","source":"BASE_PATH = f\"/kaggle/input/rsna-atd-512x512-png-v2-dataset\"","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2023-12-12T18:26:44.992924Z","iopub.execute_input":"2023-12-12T18:26:44.993231Z","iopub.status.idle":"2023-12-12T18:26:45.003688Z","shell.execute_reply.started":"2023-12-12T18:26:44.993181Z","shell.execute_reply":"2023-12-12T18:26:45.002862Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Meta Data\n\nThe `train.csv` file contains the following meta information:\n\n- `patient_id`: A unique ID code for each patient.\n- `series_id`: A unique ID code for each scan.\n- `instance_number`: The image number within the scan. The lowest instance number for many series is above zero as the original scans were cropped to the abdomen.\n- `[bowel/extravasation]_[healthy/injury]`: The two injury types with binary targets.\n- `[kidney/liver/spleen]_[healthy/low/high]`: The three injury types with three target levels.\n- `any_injury`: Whether the patient had any injury at all.\n","metadata":{}},{"cell_type":"code","source":"# train\ndataframe = pd.read_csv(f\"{BASE_PATH}/train.csv\")\ndataframe[\"image_path\"] = f\"{BASE_PATH}/train_images\"\\\n                    + \"/\" + dataframe.patient_id.astype(str)\\\n                    + \"/\" + dataframe.series_id.astype(str)\\\n                    + \"/\" + dataframe.instance_number.astype(str) +\".png\"\ndataframe = dataframe.drop_duplicates()\n\ndataframe.head(2)","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:45.004796Z","iopub.execute_input":"2023-12-12T18:26:45.005049Z","iopub.status.idle":"2023-12-12T18:26:45.185332Z","shell.execute_reply.started":"2023-12-12T18:26:45.005026Z","shell.execute_reply":"2023-12-12T18:26:45.184466Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We split the training dataset into train and validation. This is a common practise in the Machine Learning pipelines. We not only want to train our model, but also want to validate it's training.\n\nA small catch here is that the training and validation data should have an aligned data distribution. Here we handle that by grouping the lables and then splitting the dataset. This ensures an aligned data distribution between the training and the validation splits.","metadata":{}},{"cell_type":"code","source":"# Function to handle the split for each group\ndef split_group(group, test_size=0.2):\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\ntrain_data = pd.DataFrame()\nval_data = pd.DataFrame()\n\n# Iterate through the groups and split them, handling single-sample groups\nfor _, group in dataframe.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)","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:45.187011Z","iopub.execute_input":"2023-12-12T18:26:45.187878Z","iopub.status.idle":"2023-12-12T18:26:45.264828Z","shell.execute_reply.started":"2023-12-12T18:26:45.187839Z","shell.execute_reply":"2023-12-12T18:26:45.264012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data.shape, val_data.shape","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:45.265983Z","iopub.execute_input":"2023-12-12T18:26:45.266347Z","iopub.status.idle":"2023-12-12T18:26:45.273162Z","shell.execute_reply.started":"2023-12-12T18:26:45.266314Z","shell.execute_reply":"2023-12-12T18:26:45.272318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Pipeline /w tf.data\n\nHere we build the data pipeline using `tf.data`. Using `tf.data` we can map out data to an augmentation pipeline simple by using the ` map` API.\n\nAdding augmentations to the data pipeline is as simple as adding a layer into the list of layers that the `Augmenter` processes.\n\nReference: https://keras.io/api/keras_cv/layers/augmentation/","metadata":{}},{"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\ndef apply_augmentation(images, labels):\n    augmenter = keras_cv.layers.Augmenter(\n        [\n            keras_cv.layers.RandomFlip(mode=\"horizontal_and_vertical\"),\n            keras_cv.layers.RandomCutout(height_factor=0.2, width_factor=0.2),\n            \n        ]\n    )\n    return (augmenter(images), labels)\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","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:26:45.274377Z","iopub.execute_input":"2023-12-12T18:26:45.274645Z","iopub.status.idle":"2023-12-12T18:26:45.283984Z","shell.execute_reply.started":"2023-12-12T18:26:45.274621Z","shell.execute_reply":"2023-12-12T18:26:45.283124Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"paths  = 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":"2023-12-12T18:26:45.287327Z","iopub.execute_input":"2023-12-12T18:26:45.287602Z","iopub.status.idle":"2023-12-12T18:27:00.416915Z","shell.execute_reply.started":"2023-12-12T18:26:45.287578Z","shell.execute_reply":"2023-12-12T18:27:00.415841Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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":"2023-12-12T18:27:00.418278Z","iopub.execute_input":"2023-12-12T18:27:00.419109Z","iopub.status.idle":"2023-12-12T18:27:01.055183Z","shell.execute_reply.started":"2023-12-12T18:27:00.419071Z","shell.execute_reply":"2023-12-12T18:27:01.05427Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Build Model\n\n","metadata":{}},{"cell_type":"markdown","source":"### Imports y librerias keras","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.layers import Input, Conv2D, BatchNormalization, ReLU, Add, AveragePooling2D, Flatten, Dense, GlobalAveragePooling2D, MaxPooling2D, UpSampling2D, concatenate\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:27:01.056479Z","iopub.execute_input":"2023-12-12T18:27:01.056849Z","iopub.status.idle":"2023-12-12T18:27:01.062855Z","shell.execute_reply.started":"2023-12-12T18:27:01.056812Z","shell.execute_reply":"2023-12-12T18:27:01.062004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Lenet Model","metadata":{}},{"cell_type":"code","source":"# LENET model\ndef build_lenet_model(warmup_steps, decay_steps):\n    # Define Input\n    inputs = keras.Input(shape=config.IMAGE_SIZE + [3], batch_size=config.BATCH_SIZE)\n\n    # LeNet Architecture\n    x = Conv2D(6, (5, 5), activation='relu', padding='same')(inputs)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Conv2D(16, (5, 5), activation='relu')(x)\n    x = MaxPooling2D(pool_size=(2, 2))(x)\n    x = Flatten()(x)\n    x = Dense(120, activation='relu')(x)\n    x = Dense(84, activation='relu')(x)\n\n    # Define 'necks' for each head\n    x_bowel = Dense(32, activation='silu')(x)\n    x_extra = Dense(32, activation='silu')(x)\n    x_liver = Dense(32, activation='silu')(x)\n    x_kidney = Dense(32, activation='silu')(x)\n    x_spleen = Dense(32, activation='silu')(x)\n\n    # Define heads\n    out_bowel = Dense(1, name='bowel', activation='sigmoid')(x_bowel)\n    out_extra = Dense(1, name='extra', activation='sigmoid')(x_extra)\n    out_liver = Dense(3, name='liver', activation='softmax')(x_liver)\n    out_kidney = Dense(3, name='kidney', activation='softmax')(x_kidney)\n    out_spleen = Dense(3, name='spleen', activation='softmax')(x_spleen)\n\n    # Concatenate the outputs\n    outputs = [out_bowel, out_extra, out_liver, out_kidney, out_spleen]\n\n    # Create model\n    print(\"[INFO] Building the model...\")\n    model = keras.Model(inputs=inputs, outputs=outputs)\n\n    # Cosine Decay for learning rate\n    cosine_decay = keras.optimizers.schedules.CosineDecay(\n        initial_learning_rate=1e-4,\n        decay_steps=decay_steps,\n        alpha=0.0,\n        warmup_target=1e-3,\n        warmup_steps=warmup_steps,\n    )\n\n    # Compile the model\n    optimizer = keras.optimizers.Adam(learning_rate=cosine_decay)\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    metrics = {\n        \"bowel\": [\"accuracy\"],\n        \"extra\": [\"accuracy\"],\n        \"liver\": [\"accuracy\"],\n        \"kidney\": [\"accuracy\"],\n        \"spleen\": [\"accuracy\"],\n    }\n    print(\"[INFO] Compiling the model...\")\n    model.compile(\n        optimizer=optimizer,\n        loss=loss,\n        metrics=metrics\n    )\n\n    return model\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:27:01.064463Z","iopub.execute_input":"2023-12-12T18:27:01.064882Z","iopub.status.idle":"2023-12-12T18:27:01.080137Z","shell.execute_reply.started":"2023-12-12T18:27:01.064849Z","shell.execute_reply":"2023-12-12T18:27:01.07917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Unet Model","metadata":{}},{"cell_type":"code","source":"# Unet model\ndef build_unet_model(warmup_steps, decay_steps):\n    # Define Input\n    inputs = keras.Input(shape=config.IMAGE_SIZE + [3,], batch_size=config.BATCH_SIZE)\n\n    # U-Net Architecture\n    # Contraction path\n    c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(inputs)\n    c1 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c1)\n    p1 = MaxPooling2D((2, 2))(c1)\n\n    c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p1)\n    c2 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c2)\n    p2 = MaxPooling2D((2, 2))(c2)\n\n    c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p2)\n    c3 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c3)\n    p3 = MaxPooling2D((2, 2))(c3)\n\n    c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p3)\n    c4 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c4)\n    p4 = MaxPooling2D(pool_size=(2, 2))(c4)\n\n    # Middle\n    c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(p4)\n    c5 = Conv2D(256, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c5)\n\n    # Expansive path\n    u6 = UpSampling2D((2, 2))(c5)\n    u6 = concatenate([u6, c4])\n    c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u6)\n    c6 = Conv2D(128, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c6)\n\n    u7 = UpSampling2D((2, 2))(c6)\n    u7 = concatenate([u7, c3])\n    c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u7)\n    c7 = Conv2D(64, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c7)\n\n    u8 = UpSampling2D((2, 2))(c7)\n    u8 = concatenate([u8, c2])\n    c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u8)\n    c8 = Conv2D(32, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c8)\n\n    u9 = UpSampling2D((2, 2))(c8)\n    u9 = concatenate([u9, c1], axis=3)\n    c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(u9)\n    c9 = Conv2D(16, (3, 3), activation='relu', kernel_initializer='he_normal', padding='same')(c9)\n\n    # Output layer\n    #x = Conv2D(1, (1, 1), activation='sigmoid')(c9)\n\n    # Global Average Pooling\n    x = GlobalAveragePooling2D()(c9)\n\n    # Define 'necks' for each head\n    x_bowel = Dense(32, activation='silu')(x)\n    x_extra = Dense(32, activation='silu')(x)\n    x_liver = Dense(32, activation='silu')(x)\n    x_kidney = Dense(32, activation='silu')(x)\n    x_spleen = Dense(32, activation='silu')(x)\n\n    # Define heads\n    out_bowel = Dense(1, name='bowel', activation='sigmoid')(x_bowel)\n    out_extra = Dense(1, name='extra', activation='sigmoid')(x_extra)\n    out_liver = Dense(3, name='liver', activation='softmax')(x_liver)\n    out_kidney = Dense(3, name='kidney', activation='softmax')(x_kidney)\n    out_spleen = Dense(3, name='spleen', activation='softmax')(x_spleen)\n\n    # Concatenate the outputs\n    outputs = [out_bowel, out_extra, out_liver, out_kidney, out_spleen]\n\n    # Create model\n    print(\"[INFO] Building the model...\")\n    model = keras.Model(inputs=inputs, outputs=outputs)\n\n    # Cosine Decay\n    cosine_decay = keras.optimizers.schedules.CosineDecay(\n        initial_learning_rate=1e-4,\n        decay_steps=decay_steps,\n        alpha=0.0,\n        warmup_target=1e-3,\n        warmup_steps=warmup_steps,\n    )\n\n    # Compile the model\n    optimizer = keras.optimizers.Adam(learning_rate=cosine_decay)\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    metrics = {\n        \"bowel\": [\"accuracy\"],\n        \"extra\": [\"accuracy\"],\n        \"liver\": [\"accuracy\"],\n        \"kidney\": [\"accuracy\"],\n        \"spleen\": [\"accuracy\"],\n    }\n    print(\"[INFO] Compiling the model...\")\n    model.compile(\n        optimizer=optimizer,\n        loss=loss,\n        metrics=metrics\n    )\n\n    return model","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:27:01.081368Z","iopub.execute_input":"2023-12-12T18:27:01.081782Z","iopub.status.idle":"2023-12-12T18:27:01.1066Z","shell.execute_reply.started":"2023-12-12T18:27:01.081756Z","shell.execute_reply":"2023-12-12T18:27:01.105634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Resnet modificado para ser mas liviano","metadata":{}},{"cell_type":"markdown","source":"In this version:\n- The number of filters in each convolutional layer is reduced.\n- The number of residual blocks is reduced to 2 per stage.\n- The number of units in the 'necks' of each head is reduced to 16.","metadata":{}},{"cell_type":"markdown","source":"To make the ResNet model lighter compared to the original version, several key changes were made. These modifications aimed to reduce the model's complexity and memory footprint, making it more suitable for environments with limited computational resources. Here's a summary of the changes:\n\n- Reduced Number of Filters in Convolutional Layers:\n\n    - In the original ResNet architecture, the number of filters in convolutional layers typically starts at 64 and increases in later stages (128, 256, 512).\n    - In the lighter version, the number of filters has been reduced. It starts at 32 and then progresses through 64, 128, and 256.\n    ``This reduction in filters decreases the number of trainable parameters and, consequently, the memory required for training and inference.``\n- Fewer Residual Blocks:\n\n    - Standard ResNet models like ResNet50 have a larger number of residual blocks (e.g., [3, 4, 6, 3] for ResNet50).\n    - The lighter model uses fewer blocks in each stage ([2, 2, 2, 2]).\n    ``Fewer blocks mean fewer layers and operations, further reducing the computational load and memory usage. ``\n- Reduction in Dense Layer Units:\n\n    - The 'necks' for each head in the original model might have had more units (e.g., 32).\n    - In the lighter version, these are reduced to 16 units. This reduction decreases the model's complexity while still allowing for feature transformation before making predictions.\n    ``These changes are aimed at striking a balance between model complexity and resource constraints. While a lighter model is more computationally efficient, it's important to remember that reducing the model's size and capacity can also impact its performance, especially for complex tasks or datasets with high variability. The ideal configuration often depends on the specific requirements of the task and the computational resources available.``","metadata":{}},{"cell_type":"markdown","source":"## Resnet","metadata":{}},{"cell_type":"code","source":"# Resnet version modificada para ser mas liviano\ndef residual_block(x, filters, adjust_shortcut=False, kernel_size=3, stride=1):\n    \"\"\"Residual block with identity shortcut.\"\"\"\n    shortcut = x\n\n    # First convolution\n    x = Conv2D(filters, kernel_size, strides=stride, padding=\"same\")(x)\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n\n    # Second convolution\n    x = Conv2D(filters, kernel_size, strides=1, padding=\"same\")(x)\n    x = BatchNormalization()(x)\n\n    # Adjust shortcut if the number of filters change\n    if adjust_shortcut:\n        shortcut = Conv2D(filters, (1, 1), strides=stride, padding=\"same\")(shortcut)\n        shortcut = BatchNormalization()(shortcut)\n\n    # Add shortcut\n    x = Add()([x, shortcut])\n    x = ReLU()(x)\n\n    return x\n\ndef build_lighter_resnet_model(warmup_steps, decay_steps):\n    # Define Input\n    inputs = keras.Input(shape=config.IMAGE_SIZE + [3], batch_size=config.BATCH_SIZE)\n\n    # Initial Convolution\n    x = Conv2D(32, (7, 7), strides=2, padding=\"same\")(inputs)\n    x = BatchNormalization()(x)\n    x = ReLU()(x)\n    x = AveragePooling2D(pool_size=(3, 3), strides=2, padding=\"same\")(x)\n\n    # Residual Blocks with fewer filters\n    num_blocks_list = [2, 2, 2, 2]  # Fewer blocks\n    for filters in [32, 64, 128, 256]:  # Reduced number of filters\n        for _ in range(num_blocks_list.pop(0)):\n            adjust_shortcut = filters != 32\n            x = residual_block(x, filters, adjust_shortcut=adjust_shortcut)\n\n    # Global Average Pooling\n    x = GlobalAveragePooling2D()(x)\n\n    # Define 'necks' for each head\n    x_bowel = Dense(16, activation='silu')(x)  # Reduced units\n    x_extra = Dense(16, activation='silu')(x)\n    x_liver = Dense(16, activation='silu')(x)\n    x_kidney = Dense(16, activation='silu')(x)\n    x_spleen = Dense(16, activation='silu')(x)\n\n    # Define heads\n    out_bowel = Dense(1, name='bowel', activation='sigmoid')(x_bowel)\n    out_extra = Dense(1, name='extra', activation='sigmoid')(x_extra)\n    out_liver = Dense(3, name='liver', activation='softmax')(x_liver)\n    out_kidney = Dense(3, name='kidney', activation='softmax')(x_kidney)\n    out_spleen = Dense(3, name='spleen', activation='softmax')(x_spleen)\n\n    # Concatenate the outputs\n    outputs = [out_bowel, out_extra, out_liver, out_kidney, out_spleen]\n\n    # Create model\n    print(\"[INFO] Building the model...\")\n    model = keras.Model(inputs=inputs, outputs=outputs)\n\n    # Cosine Decay for learning rate\n    cosine_decay = keras.optimizers.schedules.CosineDecay(\n        initial_learning_rate=1e-4,\n        decay_steps=decay_steps,\n        alpha=0.0,\n        warmup_target=1e-3,\n        warmup_steps=warmup_steps,\n    )\n\n    # Compile the model\n    optimizer = keras.optimizers.Adam(learning_rate=cosine_decay)\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    metrics = {\n        \"bowel\": [\"accuracy\"],\n        \"extra\": [\"accuracy\"],\n        \"liver\": [\"accuracy\"],\n        \"kidney\": [\"accuracy\"],\n        \"spleen\": [\"accuracy\"],\n    }\n    print(\"[INFO] Compiling the model...\")\n    model.compile(\n        optimizer=optimizer,\n        loss=loss,\n        metrics=metrics\n    )\n\n    return model\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:27:01.107849Z","iopub.execute_input":"2023-12-12T18:27:01.108127Z","iopub.status.idle":"2023-12-12T18:27:01.129375Z","shell.execute_reply.started":"2023-12-12T18:27:01.108103Z","shell.execute_reply":"2023-12-12T18:27:01.128377Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Assuming you have already defined the necessary functions like build_dataset\n\n# Build the dataset\nprint(\"[INFO] Building the dataset...\")\ntrain_paths = train_data.image_path.values\ntrain_labels = train_data[config.TARGET_COLS].values.astype(np.float32)\nvalid_paths = val_data.image_path.values\nvalid_labels = val_data[config.TARGET_COLS].values.astype(np.float32)\n\n# Train and valid datasets\ntrain_ds = build_dataset(image_paths=train_paths, labels=train_labels)\nval_ds = build_dataset(image_paths=valid_paths, labels=valid_labels)\n\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":"2023-12-12T18:27:01.130584Z","iopub.execute_input":"2023-12-12T18:27:01.130955Z","iopub.status.idle":"2023-12-12T18:27:01.840162Z","shell.execute_reply.started":"2023-12-12T18:27:01.130922Z","shell.execute_reply":"2023-12-12T18:27:01.839257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Definicion del modelo","metadata":{}},{"cell_type":"code","source":"# Build the model\nprint(\"[INFO] Building the model...\")\nmodel_unet = build_unet_model(warmup_steps, decay_steps)\nmodel_lenet = build_lenet_model(warmup_steps, decay_steps)\nmodel_resnet = build_lighter_resnet_model(warmup_steps, decay_steps)\n\n# Train\n# Train the U-Net model\nprint(\"[INFO] Training U-Net model...\")\nhistory_unet = model_unet.fit(\n    train_ds,\n    epochs=config.EPOCHS,\n    validation_data=val_ds,\n)\n\n# Train the LeNet model\nprint(\"[INFO] Training LeNet model...\")\nhistory_lenet = model_lenet.fit(\n    train_ds,\n    epochs=config.EPOCHS,\n    validation_data=val_ds,\n)\n\n# Train the lighter ResNet model\nprint(\"[INFO] Training lighter ResNet model...\")\nhistory_resnet = model_resnet.fit(\n    train_ds,\n    epochs=config.EPOCHS,\n    validation_data=val_ds,\n)","metadata":{"execution":{"iopub.status.busy":"2023-12-12T18:27:01.84132Z","iopub.execute_input":"2023-12-12T18:27:01.84159Z","iopub.status.idle":"2023-12-12T19:10:41.855114Z","shell.execute_reply.started":"2023-12-12T18:27:01.841567Z","shell.execute_reply":"2023-12-12T19:10:41.854226Z"},"trusted":true},"execution_count":null,"outputs":[]},{"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, 3, figsize=(15, 25))  # Adjusted for three models\n\n# Iterate through the metrics and plot them\nfor i, name in enumerate([\"bowel\", \"extra\", \"kidney\", \"liver\", \"spleen\"]):\n    # Plotting for U-Net\n    axes[i, 0].plot(history_unet.history[name + '_accuracy'], label='Training ' + name)\n    axes[i, 0].plot(history_unet.history['val_' + name + '_accuracy'], label='Validation ' + name)\n    axes[i, 0].set_title('U-Net - ' + name)\n    axes[i, 0].set_xlabel('Epoch')\n    axes[i, 0].set_ylabel('Accuracy')\n    axes[i, 0].legend()\n\n    # Plotting for LeNet\n    axes[i, 1].plot(history_lenet.history[name + '_accuracy'], label='Training ' + name)\n    axes[i, 1].plot(history_lenet.history['val_' + name + '_accuracy'], label='Validation ' + name)\n    axes[i, 1].set_title('LeNet - ' + name)\n    axes[i, 1].set_xlabel('Epoch')\n    axes[i, 1].set_ylabel('Accuracy')\n    axes[i, 1].legend()\n\n    # Plotting for lighter ResNet\n    axes[i, 2].plot(history_resnet.history[name + '_accuracy'], label='Training ' + name)\n    axes[i, 2].plot(history_resnet.history['val_' + name + '_accuracy'], label='Validation ' + name)\n    axes[i, 2].set_title('Lighter ResNet - ' + name)\n    axes[i, 2].set_xlabel('Epoch')\n    axes[i, 2].set_ylabel('Accuracy')\n    axes[i, 2].legend()\n\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T19:10:41.857357Z","iopub.execute_input":"2023-12-12T19:10:41.857663Z","iopub.status.idle":"2023-12-12T19:10:45.963706Z","shell.execute_reply.started":"2023-12-12T19:10:41.857636Z","shell.execute_reply":"2023-12-12T19:10:45.962705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Plot training and validation loss for each model\nplt.figure(figsize=(10, 6))\n\n# Plotting for U-Net model\nplt.plot(history_unet.history[\"loss\"], label=\"U-Net Training Loss\")\nplt.plot(history_unet.history[\"val_loss\"], label=\"U-Net Validation Loss\")\n\n# Plotting for LeNet model\nplt.plot(history_lenet.history[\"loss\"], label=\"LeNet Training Loss\")\nplt.plot(history_lenet.history[\"val_loss\"], label=\"LeNet Validation Loss\")\n\n# Plotting for lighter ResNet model\nplt.plot(history_resnet.history[\"loss\"], label=\"Lighter ResNet Training Loss\")\nplt.plot(history_resnet.history[\"val_loss\"], label=\"Lighter ResNet Validation Loss\")\n\n# Adding labels and legend\nplt.title(\"Training and Validation Loss\")\nplt.xlabel(\"Epochs\")\nplt.ylabel(\"Loss\")\nplt.legend()\n\n# Display the plot\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-12T19:10:45.964899Z","iopub.execute_input":"2023-12-12T19:10:45.9652Z","iopub.status.idle":"2023-12-12T19:10:46.25174Z","shell.execute_reply.started":"2023-12-12T19:10:45.965174Z","shell.execute_reply":"2023-12-12T19:10:46.250858Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_best_results(history):\n    best_epoch = np.argmin(history.history['val_loss'])\n    best_loss = history.history['val_loss'][best_epoch]\n    best_acc_bowel = history.history['val_bowel_accuracy'][best_epoch]\n    best_acc_extra = history.history['val_extra_accuracy'][best_epoch]\n    best_acc_liver = history.history['val_liver_accuracy'][best_epoch]\n    best_acc_kidney = history.history['val_kidney_accuracy'][best_epoch]\n    best_acc_spleen = history.history['val_spleen_accuracy'][best_epoch]\n\n    # Find mean accuracy\n    best_acc = np.mean(\n        [best_acc_bowel, best_acc_extra, best_acc_liver, best_acc_kidney, best_acc_spleen]\n    )\n\n    return best_epoch, best_loss, best_acc, [best_acc_bowel, best_acc_extra, best_acc_liver, best_acc_kidney, best_acc_spleen]\n\n# Get best results for each model\nbest_epoch_unet, best_loss_unet, best_acc_unet, organ_acc_unet = get_best_results(history_unet)\nbest_epoch_lenet, best_loss_lenet, best_acc_lenet, organ_acc_lenet = get_best_results(history_lenet)\nbest_epoch_resnet, best_loss_resnet, best_acc_resnet, organ_acc_resnet = get_best_results(history_resnet)\n\n# Function to print results\ndef print_results(model_name, best_epoch, best_loss, best_acc, organ_acc):\n    print(f\"{model_name} - BEST Loss: {best_loss:.3f}, BEST Acc: {best_acc:.3f}, BEST Epoch: {best_epoch}\")\n    print('ORGAN Acc:')\n    for organ, acc in zip([\"Bowel\", \"Extravasation\", \"Liver\", \"Kidney\", \"Spleen\"], organ_acc):\n        print(f'  >>>> {organ.ljust(15)} : {acc:.3f}')\n    print('\\n')\n\n# Print results for each model\nprint_results(\"U-Net\", best_epoch_unet, best_loss_unet, best_acc_unet, organ_acc_unet)\nprint_results(\"LeNet\", best_epoch_lenet, best_loss_lenet, best_acc_lenet, organ_acc_lenet)\nprint_results(\"Lighter ResNet\", best_epoch_resnet, best_loss_resnet, best_acc_resnet, organ_acc_resnet)\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T19:10:46.253405Z","iopub.execute_input":"2023-12-12T19:10:46.253771Z","iopub.status.idle":"2023-12-12T19:10:46.266153Z","shell.execute_reply.started":"2023-12-12T19:10:46.253736Z","shell.execute_reply":"2023-12-12T19:10:46.265183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Store the model for inference","metadata":{}},{"cell_type":"code","source":"# Save the model\n\n#model.save(\"rsna-atd.keras\")\nmodel_resnet.save(\"resnet-rsna-atd.keras\")\nmodel_unet.save(\"unet-rsna-atd.keras\")\nmodel_lenet.save(\"lenet-rsna-atd.keras\")","metadata":{"execution":{"iopub.status.busy":"2023-12-12T19:10:46.267513Z","iopub.execute_input":"2023-12-12T19:10:46.268287Z","iopub.status.idle":"2023-12-12T19:10:47.432283Z","shell.execute_reply.started":"2023-12-12T19:10:46.268252Z","shell.execute_reply":"2023-12-12T19:10:47.431267Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport cv2\n\n# Ruta de la imagen a visualizar\nimage_path_1 = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/48843/62825/30.png' # 1\nimage_path_2 = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/50046/24574/30.png' # 2\nimage_path_3 = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/63706/39279/30.png' # 3\n\n\n# Cargar las imágenes\nimg1 = cv2.cvtColor(cv2.imread(image_path_1), cv2.COLOR_BGR2RGB)\nimg2 = cv2.cvtColor(cv2.imread(image_path_2), cv2.COLOR_BGR2RGB)\nimg3 = cv2.cvtColor(cv2.imread(image_path_3), cv2.COLOR_BGR2RGB)\n\n# Crear un conjunto de subplots\nfig, axs = plt.subplots(1, 3, figsize=(15, 5))  # 1 fila, 3 columnas\n\n# Mostrar cada imagen en su respectivo subplot\naxs[0].imshow(img1)\naxs[0].axis('off')  # Ocultar los ejes para la primera imagen\naxs[0].set_title('Imagen 1')\n\naxs[1].imshow(img2)\naxs[1].axis('off')  # Ocultar los ejes para la segunda imagen\naxs[1].set_title('Imagen 2')\n\naxs[2].imshow(img3)\naxs[2].axis('off')  # Ocultar los ejes para la tercera imagen\naxs[2].set_title('Imagen 3')\n\n# Mostrar el gráfico\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-12-12T20:12:52.13944Z","iopub.execute_input":"2023-12-12T20:12:52.140348Z","iopub.status.idle":"2023-12-12T20:12:52.654938Z","shell.execute_reply.started":"2023-12-12T20:12:52.140314Z","shell.execute_reply":"2023-12-12T20:12:52.654008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the saved model\nmodel = keras.models.load_model('lenet-rsna-atd.keras')\n\n# Preprocess the test images\nimport cv2\nimport numpy as np\n\n# image_path = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/48843/62825/30.png'\nimage_path = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/50046/24574/30.png' # 2\n#image_path = '/kaggle/input/rsna-atd-512x512-png-v2-dataset/test_images/63706/39279/30.png' # 3\nimage_size = [256, 256]  # Asegúrate de que esto coincida con el tamaño de entrada de tu modelo\n\n# Cargar y preprocesar la imagen\nimg = cv2.imread(image_path)\nimg = cv2.resize(img, tuple(image_size))\nimg = img / 255.0  # Normalizar al rango [0, 1]\nimg = np.expand_dims(img, axis=0)  # Añadir una dimensión de batch\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T20:12:57.304871Z","iopub.execute_input":"2023-12-12T20:12:57.305338Z","iopub.status.idle":"2023-12-12T20:12:59.494042Z","shell.execute_reply.started":"2023-12-12T20:12:57.305303Z","shell.execute_reply":"2023-12-12T20:12:59.49326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Realizar la prediccion","metadata":{}},{"cell_type":"code","source":"\nprediction = model.predict(img)","metadata":{"execution":{"iopub.status.busy":"2023-12-12T20:14:06.187142Z","iopub.execute_input":"2023-12-12T20:14:06.188097Z","iopub.status.idle":"2023-12-12T20:14:06.260805Z","shell.execute_reply.started":"2023-12-12T20:14:06.18806Z","shell.execute_reply":"2023-12-12T20:14:06.260037Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Predicciones binarias\nprint(\"Probabilidad de Bowel Injury:\", prediction[0][0, 0])\nprint(\"Probabilidad de Extravasation Injury:\", prediction[1][0, 0])\n\n# Predicciones multiclase\norganos = ['kidney', 'liver', 'spleen']\nestados = ['healthy', 'low', 'high']\n\nfor i, organo in enumerate(organos, 2):\n    print(f\"\\nProbabilidades para {organo}:\")\n    for estado, prob in zip(estados, prediction[i][0]):\n        print(f\"  {estado}: {prob:.2f}\")\n","metadata":{"execution":{"iopub.status.busy":"2023-12-12T20:14:08.673424Z","iopub.execute_input":"2023-12-12T20:14:08.674322Z","iopub.status.idle":"2023-12-12T20:14:08.680908Z","shell.execute_reply.started":"2023-12-12T20:14:08.674283Z","shell.execute_reply":"2023-12-12T20:14:08.679999Z"},"trusted":true},"execution_count":null,"outputs":[]}]}