{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport kagglehub\n\n# Download latest version\npath = kagglehub.competition_download('carvana-image-masking-challenge')\n\nprint(\"Path to competition files:\", path)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:09:53.847309Z","iopub.execute_input":"2026-06-30T05:09:53.848123Z","iopub.status.idle":"2026-06-30T05:09:55.4307Z","shell.execute_reply.started":"2026-06-30T05:09:53.84808Z","shell.execute_reply":"2026-06-30T05:09:55.429923Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 12: Setup for Carvana Dataset\n# NOTE: For Kaggle, add the Carvana dataset via:\n# \"Add Data\" -> Search \"carvana-image-masking-challenge\" -> Add\n\nimport os\nimport glob\nfrom sklearn.model_selection import train_test_split\nfrom tensorflow.keras.utils import Sequence\n\n# Check data paths\nimport kagglehub\nCARVANA_BASE = kagglehub.competition_download('carvana-image-masking-challenge')\n\n# List available directories\nfor root, dirs, files in os.walk(CARVANA_BASE):\n    level = root.replace(CARVANA_BASE, '').count(os.sep)\n    indent = ' ' * 2 * level\n    print(f'{indent}{os.path.basename(root)}/')\n    if level < 2:\n        subindent = ' ' * 2 * (level + 1)\n        for f in files[:5]:\n            print(f'{subindent}{f}')\n        if len(files) > 5:\n            print(f'{subindent}... and {len(files)-5} more files')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:12:54.562051Z","iopub.execute_input":"2026-06-30T05:12:54.56284Z","iopub.status.idle":"2026-06-30T05:12:56.109138Z","shell.execute_reply.started":"2026-06-30T05:12:54.562807Z","shell.execute_reply":"2026-06-30T05:12:56.108193Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 13: Carvana Data Loading\nTRAIN_IMG_DIR = os.path.join(CARVANA_BASE, 'train')\nTRAIN_MASK_DIR = os.path.join(CARVANA_BASE, 'train_masks')\n\n# If compressed, check for zip files\nif not os.path.exists(TRAIN_IMG_DIR):\n    # Try alternative paths\n    print(\"Checking for alternative directory structures...\")\n    for root, dirs, files in os.walk(CARVANA_BASE):\n        print(f\"  {root}: {len(files)} files, dirs: {dirs}\")\n    \n    # Try unzipping if needed\n    import zipfile\n    zip_files = glob.glob(os.path.join(CARVANA_BASE, '*.zip'))\n    for zf in zip_files:\n        print(f\"Found zip: {zf}\")\n        if 'train.zip' in zf:\n            with zipfile.ZipFile(zf, 'r') as z:\n                z.extractall('/kaggle/working/carvana')\n            TRAIN_IMG_DIR = '/kaggle/working/carvana/train'\n        if 'train_masks.zip' in zf:\n            with zipfile.ZipFile(zf, 'r') as z:\n                z.extractall('/kaggle/working/carvana')\n            TRAIN_MASK_DIR = '/kaggle/working/carvana/train_masks'\n\n# Get all image-mask pairs\nimage_paths = sorted(glob.glob(os.path.join(TRAIN_IMG_DIR, '*.jpg')))\nmask_paths = sorted(glob.glob(os.path.join(TRAIN_MASK_DIR, '*.gif')) + \n                    glob.glob(os.path.join(TRAIN_MASK_DIR, '*.png')) +\n                    glob.glob(os.path.join(TRAIN_MASK_DIR, '*.jpg')))\n\nprint(f\"Number of images: {len(image_paths)}\")\nprint(f\"Number of masks: {len(mask_paths)}\")\n\nif len(image_paths) > 0:\n    print(f\"Sample image path: {image_paths[0]}\")\n    print(f\"Sample mask path: {mask_paths[0]}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:13:00.10535Z","iopub.execute_input":"2026-06-30T05:13:00.106277Z","iopub.status.idle":"2026-06-30T05:13:10.798196Z","shell.execute_reply.started":"2026-06-30T05:13:00.106245Z","shell.execute_reply":"2026-06-30T05:13:10.797166Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 14: Carvana Data Generator\nIMG_SIZE_C = 128\nBATCH_SIZE_C = 16\nNUM_CLASSES_C = 1  # Binary segmentation (car vs background)\n\n# Limit dataset for faster training (use subset)\nMAX_SAMPLES = 2000  # Use 2000 samples for faster training\nimage_paths_sub = image_paths[:MAX_SAMPLES]\nmask_paths_sub = mask_paths[:MAX_SAMPLES]\n\n# Train-test split\ntrain_imgs, val_imgs, train_masks, val_masks = train_test_split(\n    image_paths_sub, mask_paths_sub, test_size=0.2, random_state=42\n)\n\nprint(f\"Training samples: {len(train_imgs)}\")\nprint(f\"Validation samples: {len(val_imgs)}\")\n\nclass CarvanaDataGenerator(Sequence):\n    def __init__(self, image_paths, mask_paths, batch_size=BATCH_SIZE_C, img_size=IMG_SIZE_C, augment=False):\n        self.image_paths = image_paths\n        self.mask_paths = mask_paths\n        self.batch_size = batch_size\n        self.img_size = img_size\n        self.augment = augment\n    \n    def __len__(self):\n        return len(self.image_paths) // self.batch_size\n    \n    def __getitem__(self, idx):\n        batch_imgs = self.image_paths[idx * self.batch_size:(idx + 1) * self.batch_size]\n        batch_masks = self.mask_paths[idx * self.batch_size:(idx + 1) * self.batch_size]\n        \n        images = np.zeros((self.batch_size, self.img_size, self.img_size, 3), dtype=np.float32)\n        masks = np.zeros((self.batch_size, self.img_size, self.img_size, 1), dtype=np.float32)\n        \n        for i, (img_path, mask_path) in enumerate(zip(batch_imgs, batch_masks)):\n            # Load image\n            img = tf.io.read_file(img_path)\n            img = tf.image.decode_jpeg(img, channels=3)\n            img = tf.image.resize(img, [self.img_size, self.img_size])\n            img = tf.cast(img, tf.float32) / 255.0\n            \n          # Load mask\n            mask = tf.io.read_file(mask_path)\n            try:\n                # Decode as PNG if it's PNG\n                mask = tf.image.decode_png(mask, channels=1)\n            except:\n                # If it's a GIF, decode as 3 channels (RGB) and convert to grayscale\n                mask = tf.image.decode_image(mask, channels=3)\n                mask = tf.image.rgb_to_grayscale(mask)\n            \n            # --- ADD THIS LINE TO RESIZE THE MASK ---\n            mask = tf.image.resize(mask, [self.img_size, self.img_size], method='nearest')\n            \n            mask = tf.cast(mask, tf.float32) / 255.0\n            mask = tf.where(mask > 0.5, 1.0, 0.0)\n            if self.augment and np.random.random() > 0.5:\n                img = tf.image.flip_left_right(img)\n                mask = tf.image.flip_left_right(mask)\n            \n            images[i] = img.numpy()\n            masks[i] = mask.numpy()\n        \n        return images, masks\n\ntrain_gen = CarvanaDataGenerator(train_imgs, train_masks, augment=True)\nval_gen = CarvanaDataGenerator(val_imgs, val_masks, augment=False)\n\n# Verify data\nsample_imgs, sample_masks = train_gen[0]\nprint(f\"Image batch shape: {sample_imgs.shape}\")\nprint(f\"Mask batch shape: {sample_masks.shape}\")\nprint(f\"Image range: [{sample_imgs.min():.2f}, {sample_imgs.max():.2f}]\")\nprint(f\"Mask unique values: {np.unique(sample_masks)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:15:51.760078Z","iopub.execute_input":"2026-06-30T05:15:51.760846Z","iopub.status.idle":"2026-06-30T05:15:52.502593Z","shell.execute_reply.started":"2026-06-30T05:15:51.760817Z","shell.execute_reply":"2026-06-30T05:15:52.501708Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 15: Visualize Carvana Samples\nfig, axes = plt.subplots(3, 2, figsize=(10, 12))\nfig.suptitle('Carvana - Sample Image-Mask Pairs', fontsize=16, fontweight='bold')\n\nfor i in range(3):\n    axes[i, 0].imshow(sample_imgs[i])\n    axes[i, 0].set_title(f'Input Image {i+1}', fontsize=12)\n    axes[i, 0].axis('off')\n    \n    axes[i, 1].imshow(sample_masks[i].squeeze(), cmap='gray')\n    axes[i, 1].set_title(f'Ground Truth Mask {i+1}', fontsize=12)\n    axes[i, 1].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:16:06.564979Z","iopub.execute_input":"2026-06-30T05:16:06.5656Z","iopub.status.idle":"2026-06-30T05:16:07.189457Z","shell.execute_reply.started":"2026-06-30T05:16:06.565567Z","shell.execute_reply":"2026-06-30T05:16:07.18849Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 16: Build U-Net for Carvana (Binary Segmentation)\ndef build_unet_binary(img_size=IMG_SIZE_C):\n    inputs = tf.keras.layers.Input(shape=(img_size, img_size, 3))\n    \n    # Encoder\n    # Block 1\n    c1 = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', kernel_initializer='he_normal')(inputs)\n    c1 = tf.keras.layers.BatchNormalization()(c1)\n    c1 = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c1)\n    c1 = tf.keras.layers.BatchNormalization()(c1)\n    p1 = tf.keras.layers.MaxPool2D(2)(c1)\n    p1 = tf.keras.layers.Dropout(0.25)(p1)\n    \n    # Block 2\n    c2 = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', kernel_initializer='he_normal')(p1)\n    c2 = tf.keras.layers.BatchNormalization()(c2)\n    c2 = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c2)\n    c2 = tf.keras.layers.BatchNormalization()(c2)\n    p2 = tf.keras.layers.MaxPool2D(2)(c2)\n    p2 = tf.keras.layers.Dropout(0.25)(p2)\n    \n    # Block 3\n    c3 = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', kernel_initializer='he_normal')(p2)\n    c3 = tf.keras.layers.BatchNormalization()(c3)\n    c3 = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c3)\n    c3 = tf.keras.layers.BatchNormalization()(c3)\n    p3 = tf.keras.layers.MaxPool2D(2)(c3)\n    p3 = tf.keras.layers.Dropout(0.25)(p3)\n    \n    # Block 4\n    c4 = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', kernel_initializer='he_normal')(p3)\n    c4 = tf.keras.layers.BatchNormalization()(c4)\n    c4 = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c4)\n    c4 = tf.keras.layers.BatchNormalization()(c4)\n    p4 = tf.keras.layers.MaxPool2D(2)(c4)\n    p4 = tf.keras.layers.Dropout(0.25)(p4)\n    \n    # Bottleneck\n    c5 = tf.keras.layers.Conv2D(1024, 3, padding='same', activation='relu', kernel_initializer='he_normal')(p4)\n    c5 = tf.keras.layers.BatchNormalization()(c5)\n    c5 = tf.keras.layers.Conv2D(1024, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c5)\n    c5 = tf.keras.layers.BatchNormalization()(c5)\n    \n    # Decoder\n    # Block 6\n    u6 = tf.keras.layers.Conv2DTranspose(512, 3, strides=2, padding='same')(c5)\n    u6 = tf.keras.layers.concatenate([u6, c4])\n    u6 = tf.keras.layers.Dropout(0.25)(u6)\n    c6 = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', kernel_initializer='he_normal')(u6)\n    c6 = tf.keras.layers.BatchNormalization()(c6)\n    c6 = tf.keras.layers.Conv2D(512, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c6)\n    c6 = tf.keras.layers.BatchNormalization()(c6)\n    \n    # Block 7\n    u7 = tf.keras.layers.Conv2DTranspose(256, 3, strides=2, padding='same')(c6)\n    u7 = tf.keras.layers.concatenate([u7, c3])\n    u7 = tf.keras.layers.Dropout(0.25)(u7)\n    c7 = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', kernel_initializer='he_normal')(u7)\n    c7 = tf.keras.layers.BatchNormalization()(c7)\n    c7 = tf.keras.layers.Conv2D(256, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c7)\n    c7 = tf.keras.layers.BatchNormalization()(c7)\n    \n    # Block 8\n    u8 = tf.keras.layers.Conv2DTranspose(128, 3, strides=2, padding='same')(c7)\n    u8 = tf.keras.layers.concatenate([u8, c2])\n    u8 = tf.keras.layers.Dropout(0.25)(u8)\n    c8 = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', kernel_initializer='he_normal')(u8)\n    c8 = tf.keras.layers.BatchNormalization()(c8)\n    c8 = tf.keras.layers.Conv2D(128, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c8)\n    c8 = tf.keras.layers.BatchNormalization()(c8)\n    \n    # Block 9\n    u9 = tf.keras.layers.Conv2DTranspose(64, 3, strides=2, padding='same')(c8)\n    u9 = tf.keras.layers.concatenate([u9, c1])\n    u9 = tf.keras.layers.Dropout(0.25)(u9)\n    c9 = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', kernel_initializer='he_normal')(u9)\n    c9 = tf.keras.layers.BatchNormalization()(c9)\n    c9 = tf.keras.layers.Conv2D(64, 3, padding='same', activation='relu', kernel_initializer='he_normal')(c9)\n    c9 = tf.keras.layers.BatchNormalization()(c9)\n    \n    # Output\n    outputs = tf.keras.layers.Conv2D(1, 1, activation='sigmoid')(c9)\n    \n    model = tf.keras.Model(inputs, outputs, name='U-Net-Binary')\n    return model\n\nmodel_carvana = build_unet_binary()\nmodel_carvana.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:16:18.410212Z","iopub.execute_input":"2026-06-30T05:16:18.410549Z","iopub.status.idle":"2026-06-30T05:16:19.719654Z","shell.execute_reply.started":"2026-06-30T05:16:18.410525Z","shell.execute_reply":"2026-06-30T05:16:19.718482Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 17: Compile Carvana Model with Dice metrics\n\ndef dice_coeff_binary(y_true, y_pred, smooth=1.0):\n    y_true_f = tf.cast(tf.reshape(y_true, [-1]), tf.float32)\n    y_pred_f = tf.cast(tf.reshape(y_pred, [-1]), tf.float32)\n    intersection = tf.reduce_sum(y_true_f * y_pred_f)\n    return (2. * intersection + smooth) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + smooth)\n\ndef dice_loss_binary(y_true, y_pred):\n    return 1 - dice_coeff_binary(y_true, y_pred)\n\ndef iou_metric_binary(y_true, y_pred):\n    y_pred_bin = tf.cast(y_pred > 0.5, tf.float32)\n    y_true_f = tf.cast(y_true, tf.float32)\n    intersection = tf.reduce_sum(y_true_f * y_pred_bin)\n    union = tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_bin) - intersection\n    return (intersection + 1e-7) / (union + 1e-7)\n\ndef bce_dice_loss(y_true, y_pred):\n    bce = tf.keras.losses.binary_crossentropy(y_true, y_pred)\n    dice = dice_loss_binary(y_true, y_pred)\n    return bce + dice\n\nmodel_carvana.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),\n    loss=bce_dice_loss,\n    metrics=['accuracy', dice_coeff_binary, iou_metric_binary]\n)\n\nprint(\"Carvana model compiled successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:16:35.976853Z","iopub.execute_input":"2026-06-30T05:16:35.977559Z","iopub.status.idle":"2026-06-30T05:16:35.995048Z","shell.execute_reply.started":"2026-06-30T05:16:35.977526Z","shell.execute_reply":"2026-06-30T05:16:35.993899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 18: Train Carvana Model\nEPOCHS_C = 20\n\ncallbacks_c = [\n    tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True, monitor='val_loss'),\n    tf.keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=3, monitor='val_loss', verbose=1)\n]\n\nhistory_c = model_carvana.fit(\n    train_gen,\n    epochs=EPOCHS_C,\n    validation_data=val_gen,\n    callbacks=callbacks_c\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:16:51.140068Z","iopub.execute_input":"2026-06-30T05:16:51.140806Z","iopub.status.idle":"2026-06-30T05:55:54.691903Z","shell.execute_reply.started":"2026-06-30T05:16:51.140774Z","shell.execute_reply":"2026-06-30T05:55:54.691137Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 19: Carvana Results & Metrics Table\nresults_df_c = pd.DataFrame({\n    'Epoch': range(1, len(history_c.history['loss']) + 1),\n    'Dice Score': [f\"{v:.4f}\" for v in history_c.history['dice_coeff_binary']],\n    'IoU': [f\"{v:.4f}\" for v in history_c.history['iou_metric_binary']],\n    'Loss': [f\"{v:.4f}\" for v in history_c.history['loss']],\n    'Val Dice Score': [f\"{v:.4f}\" for v in history_c.history['val_dice_coeff_binary']],\n    'Val IoU': [f\"{v:.4f}\" for v in history_c.history['val_iou_metric_binary']],\n    'Val Loss': [f\"{v:.4f}\" for v in history_c.history['val_loss']]\n})\n\nprint(\"=\" * 80)\nprint(\"RESULTS & METRICS - Carvana Dataset (U-Net)\")\nprint(\"=\" * 80)\ndisplay(results_df_c)\n\nprint(f\"\\n{'='*50}\")\nprint(f\"Final Training   - Dice: {history_c.history['dice_coeff_binary'][-1]:.4f}, IoU: {history_c.history['iou_metric_binary'][-1]:.4f}, Loss: {history_c.history['loss'][-1]:.4f}\")\nprint(f\"Final Validation - Dice: {history_c.history['val_dice_coeff_binary'][-1]:.4f}, IoU: {history_c.history['val_iou_metric_binary'][-1]:.4f}, Loss: {history_c.history['val_loss'][-1]:.4f}\")\nprint(f\"{'='*50}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:55:54.694306Z","iopub.execute_input":"2026-06-30T05:55:54.69463Z","iopub.status.idle":"2026-06-30T05:55:54.757066Z","shell.execute_reply.started":"2026-06-30T05:55:54.694605Z","shell.execute_reply":"2026-06-30T05:55:54.756375Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 20: Carvana - Input / Mask / Prediction Panel\nnum_viz = 5\nfig, axes = plt.subplots(num_viz, 3, figsize=(15, 5 * num_viz))\nfig.suptitle('Carvana - Input / Ground Truth Mask / Predicted Mask', fontsize=18, fontweight='bold')\n\nval_images, val_masks_gt = val_gen[0]\n\nfor i in range(num_viz):\n    pred = model_carvana.predict(val_images[i:i+1], verbose=0)\n    pred_binary = (pred[0] > 0.5).astype(np.float32)\n    \n    axes[i, 0].imshow(val_images[i])\n    axes[i, 0].set_title('Input Image', fontsize=12)\n    axes[i, 0].axis('off')\n    \n    axes[i, 1].imshow(val_masks_gt[i].squeeze(), cmap='gray')\n    axes[i, 1].set_title('Ground Truth Mask', fontsize=12)\n    axes[i, 1].axis('off')\n    \n    axes[i, 2].imshow(pred_binary.squeeze(), cmap='gray')\n    axes[i, 2].set_title('Predicted Mask', fontsize=12)\n    axes[i, 2].axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:55:54.758056Z","iopub.execute_input":"2026-06-30T05:55:54.758517Z","iopub.status.idle":"2026-06-30T05:56:03.710161Z","shell.execute_reply.started":"2026-06-30T05:55:54.758493Z","shell.execute_reply":"2026-06-30T05:56:03.709465Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 21: Carvana - Dice Score Curve\nplt.figure(figsize=(14, 5))\n\nplt.subplot(1, 2, 1)\nplt.plot(history_c.history['dice_coeff_binary'], 'b-o', label='Train Dice', markersize=4)\nplt.plot(history_c.history['val_dice_coeff_binary'], 'r-o', label='Val Dice', markersize=4)\nplt.title('Carvana - Dice Score Curve', fontsize=14, fontweight='bold')\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Dice Score', fontsize=12)\nplt.legend(fontsize=11)\nplt.grid(True, alpha=0.3)\n\nplt.subplot(1, 2, 2)\nplt.plot(history_c.history['loss'], 'b-o', label='Train Loss', markersize=4)\nplt.plot(history_c.history['val_loss'], 'r-o', label='Val Loss', markersize=4)\nplt.title('Carvana - Loss Curve', fontsize=14, fontweight='bold')\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Loss', fontsize=12)\nplt.legend(fontsize=11)\nplt.grid(True, alpha=0.3)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:56:03.711731Z","iopub.execute_input":"2026-06-30T05:56:03.712064Z","iopub.status.idle":"2026-06-30T05:56:04.078827Z","shell.execute_reply.started":"2026-06-30T05:56:03.712038Z","shell.execute_reply":"2026-06-30T05:56:04.07808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 22: Carvana - IoU Boxplot\nper_sample_iou_c = []\n\nfor batch_idx in range(len(val_gen)):\n    batch_imgs, batch_masks = val_gen[batch_idx]\n    preds = model_carvana.predict(batch_imgs, verbose=0)\n    preds_binary = (preds > 0.5).astype(np.float32)\n    \n    for i in range(batch_imgs.shape[0]):\n        pred_flat = preds_binary[i].flatten()\n        true_flat = batch_masks[i].flatten()\n        intersection = np.sum(pred_flat * true_flat)\n        union = np.sum(pred_flat) + np.sum(true_flat) - intersection\n        iou = (intersection + 1e-7) / (union + 1e-7)\n        per_sample_iou_c.append(iou)\n\nplt.figure(figsize=(8, 6))\nbp = plt.boxplot(per_sample_iou_c, patch_artist=True,\n                  boxprops=dict(facecolor='lightcoral', color='darkred'),\n                  medianprops=dict(color='blue', linewidth=2),\n                  whiskerprops=dict(color='darkred'),\n                  capprops=dict(color='darkred'))\nplt.title('Carvana - IoU Distribution (Validation Set)', fontsize=14, fontweight='bold')\nplt.ylabel('IoU Score', fontsize=12)\nplt.xticks([1], ['U-Net'], fontsize=12)\nplt.grid(True, alpha=0.3, axis='y')\n\nmean_iou_c = np.mean(per_sample_iou_c)\nmedian_iou_c = np.median(per_sample_iou_c)\nplt.text(1.3, mean_iou_c, f'Mean: {mean_iou_c:.4f}', fontsize=11, color='blue')\nplt.text(1.3, median_iou_c, f'Median: {median_iou_c:.4f}', fontsize=11, color='red')\n\nplt.tight_layout()\nplt.show()\n\nprint(f\"Mean IoU: {mean_iou_c:.4f}\")\nprint(f\"Median IoU: {median_iou_c:.4f}\")\nprint(f\"Std IoU: {np.std(per_sample_iou_c):.4f}\")\nprint(f\"Min IoU: {np.min(per_sample_iou_c):.4f}\")\nprint(f\"Max IoU: {np.max(per_sample_iou_c):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:56:04.079868Z","iopub.execute_input":"2026-06-30T05:56:04.080226Z","iopub.status.idle":"2026-06-30T05:56:27.221635Z","shell.execute_reply.started":"2026-06-30T05:56:04.0802Z","shell.execute_reply":"2026-06-30T05:56:27.220955Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 1: Install and Import Libraries\n!pip install tensorflow-datasets -q\n\nimport tensorflow as tf\nimport tensorflow_datasets as tfds\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport pandas as pd\nfrom IPython.display import display\n\nprint(f\"TensorFlow version: {tf.__version__}\")\nprint(f\"GPU Available: {tf.config.list_physical_devices('GPU')}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T05:57:02.76386Z","iopub.execute_input":"2026-06-30T05:57:02.76467Z","iopub.status.idle":"2026-06-30T05:57:06.567951Z","shell.execute_reply.started":"2026-06-30T05:57:02.764622Z","shell.execute_reply":"2026-06-30T05:57:06.567204Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset, info = tfds.load('oxford_iiit_pet', with_info=True)\nprint(info)\nprint(f\"\\nDataset keys: {list(dataset.keys())}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:08:03.856208Z","iopub.execute_input":"2026-06-30T06:08:03.856591Z","iopub.status.idle":"2026-06-30T06:09:05.386559Z","shell.execute_reply.started":"2026-06-30T06:08:03.856558Z","shell.execute_reply":"2026-06-30T06:09:05.385647Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 3: Preprocessing Functions\nIMG_SIZE = 128\nBATCH_SIZE = 16\n\ndef normalize(input_image, input_mask):\n    \"\"\"Normalize image to [0,1] and mask to {0, 1, 2} -> {0, 1, 2}\"\"\"\n    input_image = tf.cast(input_image, tf.float32) / 255.0\n    input_mask -= 1  # Labels are 1, 2, 3 -> convert to 0, 1, 2\n    return input_image, input_mask\n\ndef load_image_train(datapoint):\n    input_image = tf.image.resize(datapoint['image'], (IMG_SIZE, IMG_SIZE))\n    input_mask = tf.image.resize(\n        datapoint['segmentation_mask'], (IMG_SIZE, IMG_SIZE),\n        method=tf.image.ResizeMethod.NEAREST_NEIGHBOR\n    )\n    \n    # Random horizontal flip for augmentation\n    if tf.random.uniform(()) > 0.5:\n        input_image = tf.image.flip_left_right(input_image)\n        input_mask = tf.image.flip_left_right(input_mask)\n    \n    input_image, input_mask = normalize(input_image, input_mask)\n    return input_image, input_mask\n\ndef load_image_test(datapoint):\n    input_image = tf.image.resize(datapoint['image'], (IMG_SIZE, IMG_SIZE))\n    input_mask = tf.image.resize(\n        datapoint['segmentation_mask'], (IMG_SIZE, IMG_SIZE),\n        method=tf.image.ResizeMethod.NEAREST_NEIGHBOR\n    )\n    input_image, input_mask = normalize(input_image, input_mask)\n    return input_image, input_mask\n\n# Prepare datasets\nTRAIN_LENGTH = info.splits['train'].num_examples\nTEST_LENGTH = info.splits['test'].num_examples\nBUFFER_SIZE = 1000\n\ntrain_dataset = dataset['train'].map(load_image_train, num_parallel_calls=tf.data.AUTOTUNE)\ntrain_dataset = train_dataset.cache().shuffle(BUFFER_SIZE).batch(BATCH_SIZE).repeat().prefetch(tf.data.AUTOTUNE)\n\ntest_dataset = dataset['test'].map(load_image_test, num_parallel_calls=tf.data.AUTOTUNE)\ntest_dataset = test_dataset.batch(BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n\nprint(f\"Training samples: {TRAIN_LENGTH}\")\nprint(f\"Test samples: {TEST_LENGTH}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:09:05.388104Z","iopub.execute_input":"2026-06-30T06:09:05.388795Z","iopub.status.idle":"2026-06-30T06:09:05.574038Z","shell.execute_reply.started":"2026-06-30T06:09:05.388771Z","shell.execute_reply":"2026-06-30T06:09:05.573151Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 4: Visualize Sample Data\ndef display_sample(display_list, titles=None):\n    plt.figure(figsize=(15, 5))\n    if titles is None:\n        titles = ['Input Image', 'True Mask', 'Predicted Mask']\n    for i in range(len(display_list)):\n        plt.subplot(1, len(display_list), i + 1)\n        plt.title(titles[i], fontsize=14)\n        if len(display_list[i].shape) == 2 or display_list[i].shape[-1] == 1:\n            plt.imshow(tf.keras.utils.array_to_img(\n                tf.expand_dims(display_list[i], -1) if len(display_list[i].shape) == 2 else display_list[i]\n            ), cmap='jet')\n        else:\n            plt.imshow(tf.keras.utils.array_to_img(display_list[i]))\n        plt.axis('off')\n    plt.tight_layout()\n    plt.show()\n\n# Show samples\nfor images, masks in test_dataset.take(1):\n    for i in range(3):\n        display_sample([images[i], masks[i]])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:09:45.655841Z","iopub.execute_input":"2026-06-30T06:09:45.656621Z","iopub.status.idle":"2026-06-30T06:09:46.272424Z","shell.execute_reply.started":"2026-06-30T06:09:45.656588Z","shell.execute_reply":"2026-06-30T06:09:46.271363Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 5: Build U-Net Model\nNUM_CLASSES = 3  # Pet, Background, Border\n\ndef double_conv_block(x, n_filters):\n    x = tf.keras.layers.Conv2D(n_filters, 3, padding='same', activation='relu',\n                                kernel_initializer='he_normal')(x)\n    x = tf.keras.layers.BatchNormalization()(x)\n    x = tf.keras.layers.Conv2D(n_filters, 3, padding='same', activation='relu',\n                                kernel_initializer='he_normal')(x)\n    x = tf.keras.layers.BatchNormalization()(x)\n    return x\n\ndef downsample_block(x, n_filters):\n    f = double_conv_block(x, n_filters)\n    p = tf.keras.layers.MaxPool2D(2)(f)\n    p = tf.keras.layers.Dropout(0.3)(p)\n    return f, p\n\ndef upsample_block(x, conv_features, n_filters):\n    x = tf.keras.layers.Conv2DTranspose(n_filters, 3, 2, padding='same')(x)\n    x = tf.keras.layers.concatenate([x, conv_features])\n    x = tf.keras.layers.Dropout(0.3)(x)\n    x = double_conv_block(x, n_filters)\n    return x\n\ndef build_unet(img_size=IMG_SIZE, num_classes=NUM_CLASSES):\n    inputs = tf.keras.layers.Input(shape=(img_size, img_size, 3))\n    \n    # Encoder (Downsampling)\n    f1, p1 = downsample_block(inputs, 64)\n    f2, p2 = downsample_block(p1, 128)\n    f3, p3 = downsample_block(p2, 256)\n    f4, p4 = downsample_block(p3, 512)\n    \n    # Bottleneck\n    bottleneck = double_conv_block(p4, 1024)\n    \n    # Decoder (Upsampling)\n    u6 = upsample_block(bottleneck, f4, 512)\n    u7 = upsample_block(u6, f3, 256)\n    u8 = upsample_block(u7, f2, 128)\n    u9 = upsample_block(u8, f1, 64)\n    \n    # Output\n    outputs = tf.keras.layers.Conv2D(num_classes, 1, padding='same', activation='softmax')(u9)\n    \n    model = tf.keras.Model(inputs, outputs, name='U-Net')\n    return model\n\nmodel = build_unet()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:09:56.465075Z","iopub.execute_input":"2026-06-30T06:09:56.465986Z","iopub.status.idle":"2026-06-30T06:09:56.904182Z","shell.execute_reply.started":"2026-06-30T06:09:56.465942Z","shell.execute_reply":"2026-06-30T06:09:56.903298Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 6: Compile Model with Custom Metrics\n\ndef dice_coeff(y_true, y_pred, smooth=1.0):\n    y_true_f = tf.cast(tf.one_hot(tf.cast(tf.squeeze(y_true, axis=-1), tf.int32), NUM_CLASSES), tf.float32)\n    y_pred_f = tf.cast(y_pred, tf.float32)\n    intersection = tf.reduce_sum(y_true_f * y_pred_f, axis=[1, 2])\n    union = tf.reduce_sum(y_true_f, axis=[1, 2]) + tf.reduce_sum(y_pred_f, axis=[1, 2])\n    dice = tf.reduce_mean((2. * intersection + smooth) / (union + smooth))\n    return dice\n\ndef dice_loss(y_true, y_pred):\n    return 1 - dice_coeff(y_true, y_pred)\n\ndef iou_metric(y_true, y_pred):\n    y_true_f = tf.cast(tf.one_hot(tf.cast(tf.squeeze(y_true, axis=-1), tf.int32), NUM_CLASSES), tf.float32)\n    y_pred_f = tf.cast(y_pred, tf.float32)\n    intersection = tf.reduce_sum(y_true_f * y_pred_f, axis=[1, 2])\n    union = tf.reduce_sum(y_true_f, axis=[1, 2]) + tf.reduce_sum(y_pred_f, axis=[1, 2]) - intersection\n    iou = tf.reduce_mean((intersection + 1e-7) / (union + 1e-7))\n    return iou\n\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),\n    loss=tf.keras.losses.SparseCategoricalCrossentropy(),\n    metrics=['accuracy', dice_coeff, iou_metric]\n)\n\nprint(\"Model compiled successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:10:12.255904Z","iopub.execute_input":"2026-06-30T06:10:12.256675Z","iopub.status.idle":"2026-06-30T06:10:12.270757Z","shell.execute_reply.started":"2026-06-30T06:10:12.25664Z","shell.execute_reply":"2026-06-30T06:10:12.27003Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 7: Train Model\nEPOCHS = 20\nSTEPS_PER_EPOCH = TRAIN_LENGTH // BATCH_SIZE\nVALIDATION_STEPS = TEST_LENGTH // BATCH_SIZE\n\ncallbacks = [\n    tf.keras.callbacks.EarlyStopping(patience=5, restore_best_weights=True, monitor='val_loss'),\n    tf.keras.callbacks.ReduceLROnPlateau(factor=0.5, patience=3, monitor='val_loss', verbose=1)\n]\n\nhistory = model.fit(\n    train_dataset,\n    epochs=EPOCHS,\n    steps_per_epoch=STEPS_PER_EPOCH,\n    validation_data=test_dataset,\n    validation_steps=VALIDATION_STEPS,\n    callbacks=callbacks\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:10:22.855232Z","iopub.execute_input":"2026-06-30T06:10:22.856275Z","iopub.status.idle":"2026-06-30T06:37:41.76176Z","shell.execute_reply.started":"2026-06-30T06:10:22.856233Z","shell.execute_reply":"2026-06-30T06:37:41.760984Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 8: Results & Metrics Table\nresults_df = pd.DataFrame({\n    'Epoch': range(1, len(history.history['loss']) + 1),\n    'Dice Score': [f\"{v:.4f}\" for v in history.history['dice_coeff']],\n    'IoU': [f\"{v:.4f}\" for v in history.history['iou_metric']],\n    'Loss': [f\"{v:.4f}\" for v in history.history['loss']],\n    'Val Dice Score': [f\"{v:.4f}\" for v in history.history['val_dice_coeff']],\n    'Val IoU': [f\"{v:.4f}\" for v in history.history['val_iou_metric']],\n    'Val Loss': [f\"{v:.4f}\" for v in history.history['val_loss']]\n})\n\nprint(\"=\" * 80)\nprint(\"RESULTS & METRICS - Oxford Pet Dataset (U-Net)\")\nprint(\"=\" * 80)\ndisplay(results_df)\n\n# Final metrics\nprint(f\"\\n{'='*50}\")\nprint(f\"Final Training   - Dice: {history.history['dice_coeff'][-1]:.4f}, IoU: {history.history['iou_metric'][-1]:.4f}, Loss: {history.history['loss'][-1]:.4f}\")\nprint(f\"Final Validation - Dice: {history.history['val_dice_coeff'][-1]:.4f}, IoU: {history.history['val_iou_metric'][-1]:.4f}, Loss: {history.history['val_loss'][-1]:.4f}\")\nprint(f\"{'='*50}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:37:41.763706Z","iopub.execute_input":"2026-06-30T06:37:41.764284Z","iopub.status.idle":"2026-06-30T06:37:41.781715Z","shell.execute_reply.started":"2026-06-30T06:37:41.764256Z","shell.execute_reply":"2026-06-30T06:37:41.780969Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 9: Visualization 1 - Input / Mask / Prediction Panel\ndef create_mask(pred_mask):\n    pred_mask = tf.argmax(pred_mask, axis=-1)\n    pred_mask = pred_mask[..., tf.newaxis]\n    return pred_mask\n\ndef show_predictions(dataset, num=5):\n    fig, axes = plt.subplots(num, 3, figsize=(15, 5 * num))\n    fig.suptitle('Oxford Pet - Input / Ground Truth Mask / Predicted Mask', fontsize=18, fontweight='bold')\n    \n    for idx, (image, mask) in enumerate(dataset.unbatch().take(num)):\n        pred = model.predict(image[tf.newaxis, ...], verbose=0)\n        pred_mask = create_mask(pred[0])\n        \n        axes[idx, 0].imshow(image)\n        axes[idx, 0].set_title('Input Image', fontsize=12)\n        axes[idx, 0].axis('off')\n        \n        axes[idx, 1].imshow(tf.squeeze(mask), cmap='jet')\n        axes[idx, 1].set_title('Ground Truth Mask', fontsize=12)\n        axes[idx, 1].axis('off')\n        \n        axes[idx, 2].imshow(tf.squeeze(pred_mask), cmap='jet')\n        axes[idx, 2].set_title('Predicted Mask', fontsize=12)\n        axes[idx, 2].axis('off')\n    \n    plt.tight_layout()\n    plt.show()\n\nshow_predictions(test_dataset, num=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:37:41.782703Z","iopub.execute_input":"2026-06-30T06:37:41.783154Z","iopub.status.idle":"2026-06-30T06:37:44.983364Z","shell.execute_reply.started":"2026-06-30T06:37:41.783121Z","shell.execute_reply":"2026-06-30T06:37:44.982485Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 10: Visualization 2 - Dice Score Curve\nplt.figure(figsize=(12, 5))\n\nplt.subplot(1, 2, 1)\nplt.plot(history.history['dice_coeff'], 'b-o', label='Train Dice', markersize=4)\nplt.plot(history.history['val_dice_coeff'], 'r-o', label='Val Dice', markersize=4)\nplt.title('Oxford Pet - Dice Score Curve', fontsize=14, fontweight='bold')\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Dice Score', fontsize=12)\nplt.legend(fontsize=11)\nplt.grid(True, alpha=0.3)\n\nplt.subplot(1, 2, 2)\nplt.plot(history.history['loss'], 'b-o', label='Train Loss', markersize=4)\nplt.plot(history.history['val_loss'], 'r-o', label='Val Loss', markersize=4)\nplt.title('Oxford Pet - Loss Curve', fontsize=14, fontweight='bold')\nplt.xlabel('Epoch', fontsize=12)\nplt.ylabel('Loss', fontsize=12)\nplt.legend(fontsize=11)\nplt.grid(True, alpha=0.3)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:37:44.985076Z","iopub.execute_input":"2026-06-30T06:37:44.985364Z","iopub.status.idle":"2026-06-30T06:37:45.313988Z","shell.execute_reply.started":"2026-06-30T06:37:44.985329Z","shell.execute_reply":"2026-06-30T06:37:45.313193Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 11: Visualization 3 - IoU Boxplot (per-sample IoU on test set)\n\n# Compute per-sample IoU on test set\nper_sample_iou = []\n\nfor images, masks in test_dataset:\n    preds = model.predict(images, verbose=0)\n    pred_masks = tf.argmax(preds, axis=-1)  # (B, H, W)\n    true_masks = tf.squeeze(masks, axis=-1)  # (B, H, W)\n    true_masks = tf.cast(true_masks, tf.int64)\n    \n    for i in range(pred_masks.shape[0]):\n        pred_oh = tf.one_hot(pred_masks[i], NUM_CLASSES)\n        true_oh = tf.one_hot(true_masks[i], NUM_CLASSES)\n        intersection = tf.reduce_sum(pred_oh * true_oh, axis=[0, 1])\n        union = tf.reduce_sum(pred_oh, axis=[0, 1]) + tf.reduce_sum(true_oh, axis=[0, 1]) - intersection\n        sample_iou = tf.reduce_mean((intersection + 1e-7) / (union + 1e-7)).numpy()\n        per_sample_iou.append(sample_iou)\n\nplt.figure(figsize=(8, 6))\nbp = plt.boxplot(per_sample_iou, patch_artist=True, \n                  boxprops=dict(facecolor='skyblue', color='navy'),\n                  medianprops=dict(color='red', linewidth=2),\n                  whiskerprops=dict(color='navy'),\n                  capprops=dict(color='navy'))\nplt.title('Oxford Pet - IoU Distribution (Test Set)', fontsize=14, fontweight='bold')\nplt.ylabel('IoU Score', fontsize=12)\nplt.xticks([1], ['U-Net'], fontsize=12)\nplt.grid(True, alpha=0.3, axis='y')\n\n# Add stats text\nmean_iou = np.mean(per_sample_iou)\nmedian_iou = np.median(per_sample_iou)\nplt.text(1.3, mean_iou, f'Mean: {mean_iou:.4f}', fontsize=11, color='blue')\nplt.text(1.3, median_iou, f'Median: {median_iou:.4f}', fontsize=11, color='red')\n\nplt.tight_layout()\nplt.show()\n\nprint(f\"Mean IoU: {mean_iou:.4f}\")\nprint(f\"Median IoU: {median_iou:.4f}\")\nprint(f\"Std IoU: {np.std(per_sample_iou):.4f}\")\nprint(f\"Min IoU: {np.min(per_sample_iou):.4f}\")\nprint(f\"Max IoU: {np.max(per_sample_iou):.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:37:45.314842Z","iopub.execute_input":"2026-06-30T06:37:45.31518Z","iopub.status.idle":"2026-06-30T06:38:46.553995Z","shell.execute_reply.started":"2026-06-30T06:37:45.315127Z","shell.execute_reply":"2026-06-30T06:38:46.55327Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 23: Combined Summary of Both Datasets\nprint(\"=\" * 80)\nprint(\"LAB ASSIGNMENT 8 - SEMANTIC SEGMENTATION USING U-NET - SUMMARY\")\nprint(\"=\" * 80)\n\nprint(\"\\n📊 DATASET 1: Oxford Pet (Multi-class: 3 classes)\")\nprint(\"-\" * 50)\nprint(f\"  Final Val Dice:  {history.history['val_dice_coeff'][-1]:.4f}\")\nprint(f\"  Final Val IoU:   {history.history['val_iou_metric'][-1]:.4f}\")\nprint(f\"  Final Val Loss:  {history.history['val_loss'][-1]:.4f}\")\nprint(f\"  Test Mean IoU:   {mean_iou:.4f}\")\n\nprint(f\"\\n📊 DATASET 2: Carvana (Binary: car vs background)\")\nprint(\"-\" * 50)\nprint(f\"  Final Val Dice:  {history_c.history['val_dice_coeff_binary'][-1]:.4f}\")\nprint(f\"  Final Val IoU:   {history_c.history['val_iou_metric_binary'][-1]:.4f}\")\nprint(f\"  Final Val Loss:  {history_c.history['val_loss'][-1]:.4f}\")\nprint(f\"  Test Mean IoU:   {mean_iou_c:.4f}\")\n\nprint(\"\\n\" + \"=\" * 80)\nprint(\"🎯 OUTCOME: Successfully implemented semantic segmentation using U-Net\")\nprint(\"   architecture with encoder-decoder structure and skip connections.\")\nprint(\"   Evaluated using Dice Score and IoU metrics on both datasets.\")\nprint(\"=\" * 80)\n\n# Combined comparison plot\nfig, axes = plt.subplots(1, 2, figsize=(14, 5))\nfig.suptitle('U-Net Performance Comparison', fontsize=16, fontweight='bold')\n\n# Dice comparison\ndatasets = ['Oxford Pet', 'Carvana']\ndice_vals = [history.history['val_dice_coeff'][-1], history_c.history['val_dice_coeff_binary'][-1]]\niou_vals = [mean_iou, mean_iou_c]\n\nbars1 = axes[0].bar(datasets, dice_vals, color=['skyblue', 'lightcoral'], edgecolor='black')\naxes[0].set_title('Final Validation Dice Score', fontsize=13)\naxes[0].set_ylabel('Dice Score')\naxes[0].set_ylim(0, 1)\nfor bar, val in zip(bars1, dice_vals):\n    axes[0].text(bar.get_x() + bar.get_width()/2., bar.get_height() + 0.02, \n                 f'{val:.4f}', ha='center', fontsize=12, fontweight='bold')\n\nbars2 = axes[1].bar(datasets, iou_vals, color=['skyblue', 'lightcoral'], edgecolor='black')\naxes[1].set_title('Mean IoU Score', fontsize=13)\naxes[1].set_ylabel('IoU Score')\naxes[1].set_ylim(0, 1)\nfor bar, val in zip(bars2, iou_vals):\n    axes[1].text(bar.get_x() + bar.get_width()/2., bar.get_height() + 0.02, \n                 f'{val:.4f}', ha='center', fontsize=12, fontweight='bold')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-06-30T06:38:46.554888Z","iopub.execute_input":"2026-06-30T06:38:46.555097Z","iopub.status.idle":"2026-06-30T06:38:46.780048Z","shell.execute_reply.started":"2026-06-30T06:38:46.555076Z","shell.execute_reply":"2026-06-30T06:38:46.779164Z"}},"outputs":[],"execution_count":null}]}