{"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":90316,"databundleVersionId":10477888,"sourceType":"competition"}],"dockerImageVersionId":30823,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\n\n\n# Updated dataset paths for Kaggle\ntrain_csv_path = \"/kaggle/input/ai-dl-multiclass-segmentation/train.csv\"\ntest_class_csv_path = \"/kaggle/input/ai-dl-multiclass-segmentation/test_class.csv\"\ntrain_images_path = \"/kaggle/input/ai-dl-multiclass-segmentation/TrainImages\"\ntest_images_path = \"/kaggle/input/ai-dl-multiclass-segmentation/TestImages\"\n\n# Load the CSV files\ntrain_df = pd.read_csv(train_csv_path)\ntest_class_df = pd.read_csv(test_class_csv_path)\n\n# RLE Decoding Function\ndef rle_decode(mask_rle, shape):\n    height, width = shape\n    mask = np.zeros(height * width, dtype=np.uint8)\n    if not mask_rle or mask_rle == \"nan\":\n        return mask.reshape(height, width)\n    rle_pairs = np.array(mask_rle.split(), dtype=int).reshape(-1, 2)\n    for start, length in rle_pairs:\n        start -= 1  # Convert to zero indexing\n        mask[start:start + length] = 1\n    return mask.reshape(height, width)\n\n# Testing the decoding function\nsample_rle = train_df.iloc[0]['Encoding']\nsample_height = train_df.iloc[0]['ImageHeight']\nsample_width = train_df.iloc[0]['ImageWidth']\n\ndecoded_mask = rle_decode(sample_rle, (sample_height, sample_width))\n\n\n# Visualize the decoded mask to verify it\nplt.figure(figsize=(6,6))\nplt.title(f\"Decoded Mask for Image: {train_df.iloc[0]['ImageName']}\")\nplt.imshow(decoded_mask, cmap='gray')\nplt.axis('off')\nplt.show()\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:02:08.671819Z","iopub.execute_input":"2025-01-04T09:02:08.672187Z","iopub.status.idle":"2025-01-04T09:02:09.032578Z","shell.execute_reply.started":"2025-01-04T09:02:08.672145Z","shell.execute_reply":"2025-01-04T09:02:09.031919Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\n# Splitting the dataset into train and validation sets (80% train, 20% validation)\ntrain_df_split, val_df_split = train_test_split(train_df, test_size=0.2, random_state=42)\n\n# Displaying the number of samples in each split\nlen(train_df_split), len(val_df_split)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:02:45.106834Z","iopub.execute_input":"2025-01-04T09:02:45.107162Z","iopub.status.idle":"2025-01-04T09:02:45.568820Z","shell.execute_reply.started":"2025-01-04T09:02:45.107136Z","shell.execute_reply":"2025-01-04T09:02:45.568139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\n\n# Paths for Kaggle (update these as needed)\ntrain_images_path = \"/kaggle/input/ai-dl-multiclass-segmentation/TrainImages\"\ntrain_masks_path = \"/kaggle/working/TrainMasks\"\nval_masks_path = \"/kaggle/working/ValMasks\"\n\n# Create directories if they don't exist\nos.makedirs(train_masks_path, exist_ok=True)\nos.makedirs(val_masks_path, exist_ok=True)\n\n# Function to decode RLE\ndef rle_decode(mask_rle, shape):\n    height, width = shape\n    mask = np.zeros(height * width, dtype=np.uint8)\n    if not mask_rle or mask_rle == \"nan\":\n        return mask.reshape(height, width)\n    rle_pairs = np.array(mask_rle.split(), dtype=int).reshape(-1, 2)\n    for start, length in rle_pairs:\n        start -= 1  # Convert to zero indexing\n        mask[start:start + length] = 1\n    return mask.reshape(height, width)\n\n# Function to generate and save masks ensuring correct dimensions\ndef generate_and_save_masks_with_check(df, save_path, images_path):\n    \"\"\"\n    Generate binary masks from RLE and save them as .png files only if they match the image size.\n    \"\"\"\n    mismatched_masks = 0\n    for index, row in df.iterrows():\n        img_name = row['ImageName']\n        height, width = row['ImageHeight'], row['ImageWidth']\n        \n        # Load the corresponding image to check dimensions\n        img_path = os.path.join(images_path, f\"{img_name}.jpg\")\n        if not os.path.exists(img_path):\n            print(f\"Image {img_name} not found in {images_path}\")\n            continue\n            \n        image = Image.open(img_path)\n        image_width, image_height = image.size\n\n        # Decode the mask\n        mask = rle_decode(row['Encoding'], (height, width))\n\n        # Check if the image size matches the mask size\n        if (height, width) != (image_height, image_width):\n            print(f\"Size mismatch for {img_name}: Image ({image_height}, {image_width}) vs Mask ({height}, {width})\")\n            mismatched_masks += 1\n            continue\n\n        # Save the mask only if dimensions match\n        mask_file_path = os.path.join(save_path, f\"{img_name}_mask.png\")\n        plt.imsave(mask_file_path, mask, cmap='gray')\n\n    print(f\"Finished generating masks. {mismatched_masks} mismatched masks were found.\")\n\n# Generate and save masks for both training and validation sets with checks\ngenerate_and_save_masks_with_check(train_df_split, train_masks_path, train_images_path)\ngenerate_and_save_masks_with_check(val_df_split, val_masks_path, train_images_path)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:05:59.746165Z","iopub.execute_input":"2025-01-04T09:05:59.746478Z","iopub.status.idle":"2025-01-04T09:07:31.604271Z","shell.execute_reply.started":"2025-01-04T09:05:59.746454Z","shell.execute_reply":"2025-01-04T09:07:31.603564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\n\ndef unet_model(input_shape=(256, 256, 3), num_classes=4):\n    \"\"\"\n    Build a U-Net model for multiclass segmentation.\n    \n    Parameters:\n    - input_shape: Shape of the input image (height, width, channels)\n    - num_classes: Number of classes to predict (for multiclass segmentation)\n    \n    Returns:\n    - TensorFlow U-Net model\n    \"\"\"\n    inputs = layers.Input(shape=input_shape)\n\n    # Encoder\n    c1 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)\n    c1 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(c1)\n    p1 = layers.MaxPooling2D((2, 2))(c1)\n\n    c2 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(p1)\n    c2 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(c2)\n    p2 = layers.MaxPooling2D((2, 2))(c2)\n\n    c3 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(p2)\n    c3 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(c3)\n    p3 = layers.MaxPooling2D((2, 2))(c3)\n\n    # Bottleneck\n    c4 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(p3)\n    c4 = layers.Conv2D(512, (3, 3), activation='relu', padding='same')(c4)\n\n    # Decoder\n    u1 = layers.UpSampling2D((2, 2))(c4)\n    u1 = layers.Concatenate()([u1, c3])\n    c5 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(u1)\n    c5 = layers.Conv2D(256, (3, 3), activation='relu', padding='same')(c5)\n\n    u2 = layers.UpSampling2D((2, 2))(c5)\n    u2 = layers.Concatenate()([u2, c2])\n    c6 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(u2)\n    c6 = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(c6)\n\n    u3 = layers.UpSampling2D((2, 2))(c6)\n    u3 = layers.Concatenate()([u3, c1])\n    c7 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(u3)\n    c7 = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(c7)\n\n    # Output layer for multiclass segmentation\n    outputs = layers.Conv2D(num_classes, (1, 1), activation='softmax')(c7)\n\n    model = models.Model(inputs=inputs, outputs=outputs)\n    model.compile(optimizer='adam',\n                  loss='categorical_crossentropy',\n                  metrics=['accuracy'])\n    \n    return model\n\n# Initialize and compile the model\nunet = unet_model(input_shape=(256, 256, 3), num_classes=4)\n\n# Display model summary\nunet.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:08:41.339166Z","iopub.execute_input":"2025-01-04T09:08:41.339476Z","iopub.status.idle":"2025-01-04T09:08:49.019830Z","shell.execute_reply.started":"2025-01-04T09:08:41.339439Z","shell.execute_reply":"2025-01-04T09:08:49.019166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install tensorflow-addons","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:11:37.134333Z","iopub.execute_input":"2025-01-04T09:11:37.134617Z","iopub.status.idle":"2025-01-04T09:11:42.068612Z","shell.execute_reply.started":"2025-01-04T09:11:37.134593Z","shell.execute_reply":"2025-01-04T09:11:42.067728Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\nimport random\n\n# Custom NT-Xent Loss (Contrastive Loss) without TensorFlow Addons\ndef nt_xent_loss(z_i, z_j, temperature=0.5):\n    \"\"\"\n    Custom NT-Xent loss without TensorFlow Addons.\n    \"\"\"\n    # Normalize embeddings to unit length\n    z_i = tf.math.l2_normalize(z_i, axis=1)\n    z_j = tf.math.l2_normalize(z_j, axis=1)\n    \n    # Cosine similarity matrix\n    logits = tf.matmul(z_i, z_j, transpose_b=True) / temperature\n    batch_size = tf.shape(z_i)[0]\n\n    # Labels for positive pairs\n    labels = tf.range(batch_size)\n    labels = tf.concat([labels, labels], axis=0)\n\n    # Create positive pairs from z_i and z_j\n    logits = tf.concat([logits, tf.transpose(logits)], axis=0)\n    \n    # Compute the loss using sparse categorical crossentropy\n    loss = tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True)\n    return tf.reduce_mean(loss)\n\n# Testing the custom NT-Xent loss\nz_i = tf.random.normal([32, 128])  # Simulated embeddings for batch size 32\nz_j = tf.random.normal([32, 128])\nloss_value = nt_xent_loss(z_i, z_j)\nprint(f\"Sample NT-Xent Loss: {loss_value.numpy():.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:12:18.957288Z","iopub.execute_input":"2025-01-04T09:12:18.957616Z","iopub.status.idle":"2025-01-04T09:12:20.068339Z","shell.execute_reply.started":"2025-01-04T09:12:18.957589Z","shell.execute_reply":"2025-01-04T09:12:20.067529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\n\ndef get_simclr_model(input_shape=(256, 256, 3), projection_dim=128):\n    inputs = layers.Input(shape=input_shape)\n\n    # Simple CNN Backbone\n    x = layers.Conv2D(64, (3, 3), activation='relu', padding='same')(inputs)\n    x = layers.MaxPooling2D((2, 2))(x)\n    x = layers.Conv2D(128, (3, 3), activation='relu', padding='same')(x)\n    x = layers.GlobalAveragePooling2D()(x)\n\n    # Projection Head (2-layer MLP)\n    x = layers.Dense(512, activation=\"relu\")(x)\n    outputs = layers.Dense(projection_dim)(x)\n\n    return models.Model(inputs, outputs)\n\n# Initialize the model\nsimclr_model = get_simclr_model()\nsimclr_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:14:55.219046Z","iopub.execute_input":"2025-01-04T09:14:55.219355Z","iopub.status.idle":"2025-01-04T09:14:55.270124Z","shell.execute_reply.started":"2025-01-04T09:14:55.219334Z","shell.execute_reply":"2025-01-04T09:14:55.269448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Custom NT-Xent Loss (Contrastive Loss) without TensorFlow Addons\ndef nt_xent_loss(z_i, z_j, temperature=0.5):\n    z_i = tf.math.l2_normalize(z_i, axis=1)\n    z_j = tf.math.l2_normalize(z_j, axis=1)\n    logits = tf.matmul(z_i, z_j, transpose_b=True) / temperature\n    batch_size = tf.shape(z_i)[0]\n    labels = tf.range(batch_size)\n    labels = tf.concat([labels, labels], axis=0)\n    logits = tf.concat([logits, tf.transpose(logits)], axis=0)\n    loss = tf.keras.losses.sparse_categorical_crossentropy(labels, logits, from_logits=True)\n    return tf.reduce_mean(loss)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:15:05.684690Z","iopub.execute_input":"2025-01-04T09:15:05.685039Z","iopub.status.idle":"2025-01-04T09:15:05.690396Z","shell.execute_reply.started":"2025-01-04T09:15:05.685010Z","shell.execute_reply":"2025-01-04T09:15:05.689563Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training step using the custom NT-Xent loss\noptimizer = tf.keras.optimizers.Adam(learning_rate=0.001)\n\n@tf.function\ndef train_step(images):\n    with tf.GradientTape() as tape:\n        z_i = simclr_model(images[0], training=True)\n        z_j = simclr_model(images[1], training=True)\n        loss = nt_xent_loss(z_i, z_j)\n    gradients = tape.gradient(loss, simclr_model.trainable_variables)\n    optimizer.apply_gradients(zip(gradients, simclr_model.trainable_variables))\n    return loss","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:15:16.948288Z","iopub.execute_input":"2025-01-04T09:15:16.948687Z","iopub.status.idle":"2025-01-04T09:15:16.958059Z","shell.execute_reply.started":"2025-01-04T09:15:16.948653Z","shell.execute_reply":"2025-01-04T09:15:16.957133Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\n\n# Define SimCLR augmentations for your real dataset\ndef simclr_augmentations(image):\n    image = tf.image.random_crop(image, size=[256, 256, 3])  \n    image = tf.image.random_flip_left_right(image)         \n    image = tf.image.random_brightness(image, max_delta=0.5) \n    image = tf.image.random_contrast(image, lower=0.2, upper=0.8)  \n    image = tf.clip_by_value(image, 0.0, 1.0)                \n    return image\n\ndef load_and_preprocess_image(file_path):\n    image = tf.io.read_file(file_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [256, 256]) / 255.0\n    return image\n\ndef prepare_simclr_batch(file_path):\n    # Load image and apply two different augmentations for contrastive learning\n    image = load_and_preprocess_image(file_path)\n    return simclr_augmentations(image), simclr_augmentations(image)\n\n# Load the actual test dataset from Kaggle\ntest_image_files = tf.data.Dataset.list_files(\"/kaggle/input/ai-dl-multiclass-segmentation/TestImages/*.jpg\")\ntest_dataset = test_image_files.map(prepare_simclr_batch).batch(32).shuffle(buffer_size=100)\n\n# Confirm the dataset structure\nfor batch in test_dataset.take(1):\n    print(f\"Batch shape: {batch[0].shape}, Augmented Pair Shape: {batch[1].shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:16:32.516787Z","iopub.execute_input":"2025-01-04T09:16:32.517188Z","iopub.status.idle":"2025-01-04T09:16:45.742342Z","shell.execute_reply.started":"2025-01-04T09:16:32.517160Z","shell.execute_reply":"2025-01-04T09:16:45.741465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Optimizer for SimCLR pretraining\noptimizer = tf.keras.optimizers.Adam(learning_rate=0.001)\n\n# Custom SimCLR training step using NT-Xent loss\n@tf.function\ndef train_step(batch):\n    with tf.GradientTape() as tape:\n        z_i = simclr_model(batch[0], training=True)  # First augmented view\n        z_j = simclr_model(batch[1], training=True)  # Second augmented view\n        loss = nt_xent_loss(z_i, z_j)\n    \n    gradients = tape.gradient(loss, simclr_model.trainable_variables)\n    optimizer.apply_gradients(zip(gradients, simclr_model.trainable_variables))\n    return loss\n\n# SimCLR Training Loop (10 epochs for demonstration)\nEPOCHS = 10\nfor epoch in range(EPOCHS):\n    total_loss = 0.0\n    for step, batch in enumerate(test_dataset):\n        loss = train_step(batch)\n        total_loss += loss\n    avg_loss = total_loss / (step + 1)\n    print(f\"Epoch {epoch + 1}/{EPOCHS}, Loss: {avg_loss.numpy():.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:18:07.060089Z","iopub.execute_input":"2025-01-04T09:18:07.060447Z","iopub.status.idle":"2025-01-04T09:19:34.859467Z","shell.execute_reply.started":"2025-01-04T09:18:07.060422Z","shell.execute_reply":"2025-01-04T09:19:34.858647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Save the pretrained SimCLR model for future fine-tuning\nsimclr_model.save(\"/kaggle/working/simclr_pretrained_model.h5\")\nprint(\"SimCLR Pretraining Completed and Model Saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:20:38.629346Z","iopub.execute_input":"2025-01-04T09:20:38.629704Z","iopub.status.idle":"2025-01-04T09:20:38.659951Z","shell.execute_reply.started":"2025-01-04T09:20:38.629678Z","shell.execute_reply":"2025-01-04T09:20:38.659077Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, models\n\n# Load the pretrained SimCLR model\npretrained_simclr = tf.keras.models.load_model(\"/kaggle/working/simclr_pretrained_model.h5\")\n\n# Freeze the pretrained layers\nfor layer in pretrained_simclr.layers:\n    layer.trainable = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:21:05.012003Z","iopub.execute_input":"2025-01-04T09:21:05.012329Z","iopub.status.idle":"2025-01-04T09:21:05.059444Z","shell.execute_reply.started":"2025-01-04T09:21:05.012298Z","shell.execute_reply":"2025-01-04T09:21:05.058591Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_unet_with_simclr(pretrained_simclr, num_classes=4):\n    \"\"\"\n    Build a U-Net model with a frozen SimCLR backbone and dynamic feature map size.\n    \"\"\"\n    inputs = pretrained_simclr.input\n    x = pretrained_simclr(inputs, training=False)\n\n    # ✅ Ensure the output is a single tensor (not a list)\n    if isinstance(x, list):\n        x = x[0]  # Take the first tensor if multiple outputs exist\n\n    # ✅ Check the shape after ensuring it's a tensor\n    print(f\"Corrected SimCLR Output Shape: {x.shape}\")\n\n    # ✅ Ensure the output is flattened\n    x = layers.Flatten()(x) if len(x.shape) > 2 else x\n\n    # ✅ Expand the feature vector with a Dense layer before reshaping\n    x = layers.Dense(8 * 8 * 64, activation='relu')(x)\n    \n    # ✅ Reshape into a spatial feature map\n    x = layers.Reshape((8, 8, 64))(x)\n    \n    # ✅ U-Net Decoder with upsampling\n    x = layers.Conv2DTranspose(256, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)\n\n    x = layers.Conv2DTranspose(128, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)\n\n    x = layers.Conv2DTranspose(64, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)\n\n    # ✅ Output Layer (4 classes with softmax)\n    outputs = layers.Conv2D(num_classes, (1, 1), activation='softmax')(x)\n\n    model = models.Model(inputs=inputs, outputs=outputs)\n    return model\n\n# ✅ Initialize the corrected U-Net with the pretrained SimCLR backbone\nunet_model = build_unet_with_simclr(pretrained_simclr)\nunet_model.compile(optimizer='adam',\n                   loss='categorical_crossentropy',\n                   metrics=['accuracy'])\nunet_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:24:08.368046Z","iopub.execute_input":"2025-01-04T09:24:08.368415Z","iopub.status.idle":"2025-01-04T09:24:08.433362Z","shell.execute_reply.started":"2025-01-04T09:24:08.368387Z","shell.execute_reply":"2025-01-04T09:24:08.432529Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.utils import to_categorical\n\n# Function to load images and masks together for fine-tuning\ndef preprocess_image_mask(image_path, mask_path):\n    # Load the image\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [256, 256]) / 255.0\n\n    # Load the mask\n    mask = tf.io.read_file(mask_path)\n    mask = tf.image.decode_png(mask, channels=1)\n    mask = tf.image.resize(mask, [256, 256], method='nearest')\n    mask = tf.cast(mask, tf.int32)\n    mask = tf.squeeze(mask)\n    mask = to_categorical(mask, num_classes=4)  # Convert to categorical format\n\n    return image, mask\n\n# Prepare the training and validation datasets\ntrain_image_paths = tf.data.Dataset.list_files(\"/kaggle/input/ai-dl-multiclass-segmentation/TrainImages/*.jpg\")\ntrain_mask_paths = tf.data.Dataset.list_files(\"/kaggle/working/TrainMasks/*.png\")\n\ntrain_dataset = tf.data.Dataset.zip((train_image_paths, train_mask_paths))\ntrain_dataset = train_dataset.map(preprocess_image_mask).batch(32).shuffle(buffer_size=100)\n\nval_image_paths = tf.data.Dataset.list_files(\"/kaggle/input/ai-dl-multiclass-segmentation/TrainImages/*.jpg\")\nval_mask_paths = tf.data.Dataset.list_files(\"/kaggle/working/ValMasks/*.png\")\n\nval_dataset = tf.data.Dataset.zip((val_image_paths, val_mask_paths))\nval_dataset = val_dataset.map(preprocess_image_mask).batch(32)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:25:17.419149Z","iopub.execute_input":"2025-01-04T09:25:17.419494Z","iopub.status.idle":"2025-01-04T09:25:18.543102Z","shell.execute_reply.started":"2025-01-04T09:25:17.419466Z","shell.execute_reply":"2025-01-04T09:25:18.542295Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Custom Intersection over Union (IoU) metric\ndef mean_iou(y_true, y_pred):\n    y_pred = tf.argmax(y_pred, axis=-1)\n    y_true = tf.argmax(y_true, axis=-1)\n    \n    # Intersection and union calculation\n    intersection = tf.reduce_sum(tf.cast(y_pred * y_true, tf.float32))\n    union = tf.reduce_sum(tf.cast(y_pred + y_true, tf.float32)) - intersection\n    return intersection / (union + tf.keras.backend.epsilon())\n\n# Adding IoU to the model's compilation\nunet_model.compile(optimizer='adam',\n                   loss='categorical_crossentropy',\n                   metrics=['accuracy', mean_iou])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:25:52.028466Z","iopub.execute_input":"2025-01-04T09:25:52.028766Z","iopub.status.idle":"2025-01-04T09:25:52.038063Z","shell.execute_reply.started":"2025-01-04T09:25:52.028744Z","shell.execute_reply":"2025-01-04T09:25:52.037289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_unet_with_simclr(pretrained_simclr, num_classes=4):\n    \"\"\"\n    Build a U-Net model with a frozen SimCLR backbone and dynamic feature map size.\n    \"\"\"\n    inputs = pretrained_simclr.input\n    x = pretrained_simclr(inputs, training=False)\n\n    # Ensure output is a single tensor\n    if isinstance(x, list):\n        x = x[0]\n\n    # Expand feature vector\n    x = layers.Dense(8 * 8 * 64, activation='relu')(x)\n    x = layers.Reshape((8, 8, 64))(x)\n\n    # ✅ Additional Upsampling Layers to Match 256x256 Output Size\n    x = layers.Conv2DTranspose(256, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)  # 16x16\n\n    x = layers.Conv2DTranspose(128, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)  # 32x32\n\n    x = layers.Conv2DTranspose(64, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)  # 64x64\n\n    x = layers.Conv2DTranspose(32, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)  # 128x128\n\n    # ✅ Final Upsampling to Match 256x256\n    x = layers.Conv2DTranspose(16, (3, 3), activation='relu', padding='same')(x)\n    x = layers.UpSampling2D((2, 2))(x)  # 256x256\n\n    # ✅ Output Layer with Correct Size\n    outputs = layers.Conv2D(num_classes, (1, 1), activation='softmax')(x)\n\n    model = models.Model(inputs=inputs, outputs=outputs)\n    return model\n\n# ✅ Reinitialize and Compile the Corrected U-Net\nunet_model = build_unet_with_simclr(pretrained_simclr)\nunet_model.compile(optimizer='adam',\n                   loss='categorical_crossentropy',\n                   metrics=['accuracy'])\nunet_model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:27:24.863192Z","iopub.execute_input":"2025-01-04T09:27:24.863579Z","iopub.status.idle":"2025-01-04T09:27:24.951880Z","shell.execute_reply.started":"2025-01-04T09:27:24.863546Z","shell.execute_reply":"2025-01-04T09:27:24.951111Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fine-tune the U-Net model with the labeled dataset\nEPOCHS = 20\nhistory = unet_model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=EPOCHS,\n    verbose=1\n)\n\n# Save the fine-tuned model for future use\nunet_model.save(\"/kaggle/working/fine_tuned_unet_model.h5\")\nprint(\"✅ Fine-tuning completed and model saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:28:03.712520Z","iopub.execute_input":"2025-01-04T09:28:03.712885Z","iopub.status.idle":"2025-01-04T09:32:01.110861Z","shell.execute_reply.started":"2025-01-04T09:28:03.712838Z","shell.execute_reply":"2025-01-04T09:32:01.109935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# If using RLE encoding, ensure masks are generated correctly\ndef rle_decode(mask_rle, shape=(256, 256)):\n    '''\n    Decode RLE encoded mask into a 2D numpy array.\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0::2], s[1::2])]\n    starts -= 1\n    ends = starts + lengths\n    mask = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for start, end in zip(starts, ends):\n        mask[start:end] = 1\n    return mask.reshape(shape)\n\n# Apply the fix while loading the mask\ndef preprocess_image_mask_fixed(image_path, mask_rle):\n    image = tf.io.read_file(image_path)\n    image = tf.image.decode_jpeg(image, channels=3)\n    image = tf.image.resize(image, [256, 256]) / 255.0\n\n    # Decode the RLE mask\n    mask = rle_decode(mask_rle)\n    mask = tf.cast(mask, tf.int32)\n    return image, mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:33:36.395723Z","iopub.execute_input":"2025-01-04T09:33:36.396071Z","iopub.status.idle":"2025-01-04T09:33:36.402505Z","shell.execute_reply.started":"2025-01-04T09:33:36.396043Z","shell.execute_reply":"2025-01-04T09:33:36.401734Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Test again for unique values in the corrected mask\nsample_image, sample_mask = next(iter(train_dataset))\nunique_values = np.unique(sample_mask.numpy())\nprint(f\"✅ Fixed Unique Values in the Mask: {unique_values}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:33:45.547205Z","iopub.execute_input":"2025-01-04T09:33:45.547505Z","iopub.status.idle":"2025-01-04T09:33:51.371334Z","shell.execute_reply.started":"2025-01-04T09:33:45.547482Z","shell.execute_reply":"2025-01-04T09:33:51.370411Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Fine-tune the U-Net model with the corrected masks\nEPOCHS = 20\nhistory = unet_model.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=EPOCHS,\n    verbose=1\n)\n\n# Save the fine-tuned model for future use\nunet_model.save(\"/kaggle/working/fine_tuned_unet_model.h5\")\nprint(\"✅ Fine-tuning completed and model saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-01-04T09:34:18.798042Z","iopub.execute_input":"2025-01-04T09:34:18.798377Z","iopub.status.idle":"2025-01-04T09:34:34.549123Z","shell.execute_reply.started":"2025-01-04T09:34:18.798353Z","shell.execute_reply":"2025-01-04T09:34:34.547714Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}