{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"competition","sourceId":120401,"databundleVersionId":14399764}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:39.465676Z","iopub.execute_input":"2026-05-01T06:57:39.466473Z","iopub.status.idle":"2026-05-01T06:57:50.673426Z","shell.execute_reply.started":"2026-05-01T06:57:39.466438Z","shell.execute_reply":"2026-05-01T06:57:50.672578Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport warnings\n\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'\nwarnings.filterwarnings(\"ignore\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:50.674863Z","iopub.execute_input":"2026-05-01T06:57:50.675603Z","iopub.status.idle":"2026-05-01T06:57:50.679754Z","shell.execute_reply.started":"2026-05-01T06:57:50.675576Z","shell.execute_reply":"2026-05-01T06:57:50.678916Z"}},"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# Correct paths\nbase = '/kaggle/input/competitions/flood-image-segmentation-ml-4-im-2025-2026'\ntrain_img_dir  = base + '/Training/Images'\ntrain_mask_dir = base + '/Training/Masks'\ntest_img_dir   = base + '/Testing/Images'\n\n# Count files\nprint(\"Train images:\", len(os.listdir(train_img_dir)))\nprint(\"Train masks :\", len(os.listdir(train_mask_dir)))\nprint(\"Test images :\", len(os.listdir(test_img_dir)))\n\n# Check one image and its mask\nimg_name = os.listdir(train_img_dir)[0]\nimg  = np.array(Image.open(os.path.join(train_img_dir,  img_name)))\nmask = np.array(Image.open(os.path.join(train_mask_dir, img_name)))\n\nprint(\"\\nImage shape :\", img.shape)\nprint(\"Mask shape  :\", mask.shape)\nprint(\"Mask unique values:\", np.unique(mask))\n\n# Visualize\nfig, axes = plt.subplots(1, 2, figsize=(12, 5))\naxes[0].imshow(img)\naxes[0].set_title(\"Image\")\naxes[1].imshow(mask, cmap='gray')\naxes[1].set_title(\"Mask\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:50.681247Z","iopub.execute_input":"2026-05-01T06:57:50.681642Z","iopub.status.idle":"2026-05-01T06:57:51.189422Z","shell.execute_reply.started":"2026-05-01T06:57:50.681619Z","shell.execute_reply":"2026-05-01T06:57:51.188615Z"}},"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# Correct paths\nbase = '/kaggle/input/competitions/flood-image-segmentation-ml-4-im-2025-2026'\ntrain_img_dir  = base + '/Training/Images'\ntrain_mask_dir = base + '/Training/Masks'\ntest_img_dir   = base + '/Testing/Images'\n\n# Count files\nprint(\"Train images:\", len(os.listdir(train_img_dir)))\nprint(\"Train masks :\", len(os.listdir(train_mask_dir)))\nprint(\"Test images :\", len(os.listdir(test_img_dir)))\n\n# Check one image and its mask\nimg_name = os.listdir(train_img_dir)[0]\nimg  = np.array(Image.open(os.path.join(train_img_dir,  img_name)))\nmask = np.array(Image.open(os.path.join(train_mask_dir, img_name)))\n\nprint(\"\\nImage shape :\", img.shape)\nprint(\"Mask shape  :\", mask.shape)\nprint(\"Mask unique values:\", np.unique(mask))\n\n# Visualize\nfig, axes = plt.subplots(1, 2, figsize=(12, 5))\naxes[0].imshow(img)\naxes[0].set_title(\"Image\")\naxes[1].imshow(mask, cmap='gray')\naxes[1].set_title(\"Mask\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:51.192131Z","iopub.execute_input":"2026-05-01T06:57:51.192516Z","iopub.status.idle":"2026-05-01T06:57:51.640903Z","shell.execute_reply.started":"2026-05-01T06:57:51.192490Z","shell.execute_reply":"2026-05-01T06:57:51.640074Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Load mask as Grayscale (not RGB)\nmask = np.array(Image.open(os.path.join(train_mask_dir, img_name)).convert('L'))\n\n# Fix: white = flood = 255, so > 127 is correct\nmask_binary = (mask > 127).astype(np.uint8)\n\nprint(\"Mask shape:\", mask.shape)\nprint(\"After fix:\", np.unique(mask_binary))\nprint(\"Flood pixels %:\", round(mask_binary.mean() * 100, 2))\n\nfig, axes = plt.subplots(1, 3, figsize=(15, 5))\naxes[0].imshow(img)\naxes[0].set_title(\"Original Image\")\naxes[1].imshow(mask, cmap='gray')\naxes[1].set_title(\"Mask Before Fix\")\naxes[2].imshow(mask_binary, cmap='gray')\naxes[2].set_title(\"Mask After Fix (Binary)\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:51.642137Z","iopub.execute_input":"2026-05-01T06:57:51.642487Z","iopub.status.idle":"2026-05-01T06:57:52.191811Z","shell.execute_reply.started":"2026-05-01T06:57:51.642461Z","shell.execute_reply":"2026-05-01T06:57:52.190925Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom PIL import Image\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom sklearn.model_selection import train_test_split\n\nbase = '/kaggle/input/competitions/flood-image-segmentation-ml-4-im-2025-2026'\ntrain_img_dir  = base + '/Training/Images'\ntrain_mask_dir = base + '/Training/Masks'\ntest_img_dir   = base + '/Testing/Images'\n\nIMG_SIZE = 256\n\ndef load_image(path):\n    img = Image.open(path).convert('RGB')\n    img = img.resize((IMG_SIZE, IMG_SIZE))\n    return np.array(img, dtype=np.float32) / 255.0\n\ndef load_mask(path):\n    mask = Image.open(path).convert('L')\n    mask = mask.resize((IMG_SIZE, IMG_SIZE), resample=Image.NEAREST)\n    mask = np.array(mask)\n    mask = (mask > 127).astype(np.float32)\n    return mask\n\nimg_names = sorted(os.listdir(train_img_dir))\n\nnp.random.seed(42)\nnp.random.shuffle(img_names)\n\nprint(\"Loading data...\")\n\nX = np.array([load_image(os.path.join(train_img_dir, n)) for n in img_names])\ny = np.array([load_mask(os.path.join(train_mask_dir, n)) for n in img_names])\n\ny = np.expand_dims(y, axis=-1)\n\nprint(\"X shape:\", X.shape)\nprint(\"y shape:\", y.shape)\n\nX_train, X_val, y_train, y_val = train_test_split(\n    X, y, test_size=0.15, random_state=42\n)\n\nprint(\"Train size:\", len(X_train))\nprint(\"Val size  :\", len(X_val))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T06:57:52.192990Z","iopub.execute_input":"2026-05-01T06:57:52.193378Z","iopub.status.idle":"2026-05-01T07:00:26.562059Z","shell.execute_reply.started":"2026-05-01T06:57:52.193338Z","shell.execute_reply":"2026-05-01T07:00:26.561016Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers, Model\nfrom tensorflow.keras.applications import EfficientNetB4\n\ndef build_unet_efficientnet(input_shape=(256, 256, 3)):\n    \n    base_model = EfficientNetB4(\n        include_top=False,\n        weights='imagenet',\n        input_shape=input_shape\n    )\n    \n    base_model.trainable = False\n\n    s1 = base_model.get_layer('block1a_activation').output\n    s2 = base_model.get_layer('block2b_activation').output\n    s3 = base_model.get_layer('block3b_activation').output\n    s4 = base_model.get_layer('block5e_activation').output\n    \n    bridge = base_model.get_layer('block7b_activation').output\n    \n    def decoder_block(x, skip, filters):\n        x = layers.UpSampling2D((2, 2))(x)\n        x = layers.Concatenate()([x, skip])\n        x = layers.Conv2D(filters, 3, padding='same', use_bias=False)(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.Activation('relu')(x)\n        x = layers.Conv2D(filters, 3, padding='same', use_bias=False)(x)\n        x = layers.BatchNormalization()(x)\n        x = layers.Activation('relu')(x)\n        return x\n    \n    d1 = decoder_block(bridge, s4, 256)\n    d2 = decoder_block(d1, s3, 128)\n    d3 = decoder_block(d2, s2, 64)\n    d4 = decoder_block(d3, s1, 32)\n    \n    x = layers.UpSampling2D((2, 2))(d4)\n    x = layers.Conv2D(16, 3, padding='same', use_bias=False)(x)\n    x = layers.BatchNormalization()(x)\n    x = layers.Activation('relu')(x)\n    \n    output = layers.Conv2D(1, 1, activation='sigmoid')(x)\n    \n    model = Model(inputs=base_model.input, outputs=output)\n    return model\n\nmodel = build_unet_efficientnet()\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:00:26.563324Z","iopub.execute_input":"2026-05-01T07:00:26.563937Z","iopub.status.idle":"2026-05-01T07:00:35.480020Z","shell.execute_reply.started":"2026-05-01T07:00:26.563909Z","shell.execute_reply":"2026-05-01T07:00:35.479082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\n\ndef dice_coef(y_true, y_pred, smooth=1e-6):\n    y_true = tf.cast(tf.reshape(y_true, [-1]), tf.float32)\n    y_pred = tf.cast(tf.reshape(y_pred, [-1]), tf.float32)\n    intersection = tf.reduce_sum(y_true * y_pred)\n    return (2. * intersection + smooth) / (tf.reduce_sum(y_true) + tf.reduce_sum(y_pred) + smooth)\n\ndef iou_metric(y_true, y_pred, smooth=1e-6):\n    y_true = tf.cast(tf.reshape(y_true, [-1]), tf.float32)\n    y_pred = tf.cast(tf.reshape(y_pred, [-1]), tf.float32)\n    intersection = tf.reduce_sum(y_true * y_pred)\n    union = tf.reduce_sum(y_true) + tf.reduce_sum(y_pred) - intersection\n    return (intersection + smooth) / (union + smooth)\n\ndef dice_bce_loss(y_true, y_pred):\n    y_true = tf.cast(y_true, tf.float32)\n    y_pred = tf.cast(y_pred, tf.float32)\n    # BCE\n    bce = tf.reduce_mean(tf.keras.losses.binary_crossentropy(y_true, y_pred))\n    # Dice\n    y_true_f = tf.reshape(y_true, [-1])\n    y_pred_f = tf.reshape(y_pred, [-1])\n    intersection = tf.reduce_sum(y_true_f * y_pred_f)\n    dice = 1 - (2. * intersection + 1e-6) / (tf.reduce_sum(y_true_f) + tf.reduce_sum(y_pred_f) + 1e-6)\n    return 0.5 * bce + 0.5 * dice\n\n# Compile\nmodel.compile(\n    optimizer=tf.keras.optimizers.Adam(learning_rate=1e-4),\n    loss=dice_bce_loss,\n    metrics=[iou_metric, dice_coef]\n)\n\nprint(\"Compiled successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:00:35.481216Z","iopub.execute_input":"2026-05-01T07:00:35.481569Z","iopub.status.idle":"2026-05-01T07:00:35.502032Z","shell.execute_reply.started":"2026-05-01T07:00:35.481545Z","shell.execute_reply":"2026-05-01T07:00:35.501336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(model.output_shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:00:35.503166Z","iopub.execute_input":"2026-05-01T07:00:35.503554Z","iopub.status.idle":"2026-05-01T07:00:35.508187Z","shell.execute_reply.started":"2026-05-01T07:00:35.503527Z","shell.execute_reply":"2026-05-01T07:00:35.507419Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau\n\n\ncallbacks = [\n    ModelCheckpoint(\n        'best_model.h5',\n        monitor='val_iou_metric',\n        mode='max',\n        save_best_only=True,\n        verbose=1\n    ),\n    EarlyStopping(\n        monitor='val_iou_metric',\n        mode='max',\n        patience=12,\n        verbose=1,\n        restore_best_weights=True\n    ),\n    ReduceLROnPlateau(\n        monitor='val_iou_metric',\n        mode='max',\n        factor=0.5,\n        patience=3,\n        min_lr=1e-7,\n        verbose=1\n    )\n]\n\nhistory = model.fit(\n    X_train, y_train,\n    validation_data=(X_val, y_val),\n    epochs=50,\n    batch_size=16,\n    callbacks=callbacks\n)\n\nprint(\"Training complete!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:00:35.510036Z","iopub.execute_input":"2026-05-01T07:00:35.510341Z","iopub.status.idle":"2026-05-01T07:31:21.431237Z","shell.execute_reply.started":"2026-05-01T07:00:35.510317Z","shell.execute_reply":"2026-05-01T07:31:21.430274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\n\ndef visualize_predictions(model, X_val, y_val, num=5):\n    preds = model.predict(X_val[:num])\n\n    plt.figure(figsize=(15, num * 3))\n\n    for i in range(num):\n        img = X_val[i]\n        true_mask = y_val[i]\n        pred_mask = preds[i]\n\n        pred_binary = (pred_mask > 0.5).astype(np.float32)\n\n        # Image\n        plt.subplot(num, 3, i*3 + 1)\n        plt.imshow(img)\n        plt.title(\"Image\")\n        plt.axis(\"off\")\n\n        # Ground truth\n        plt.subplot(num, 3, i*3 + 2)\n        plt.imshow(true_mask.squeeze(), cmap='gray')\n        plt.title(\"True Mask\")\n        plt.axis(\"off\")\n\n        # Prediction\n        plt.subplot(num, 3, i*3 + 3)\n        plt.imshow(pred_binary.squeeze(), cmap='gray')\n        plt.title(\"Predicted Mask\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\nvisualize_predictions(model, X_val, y_val)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:31:21.432946Z","iopub.execute_input":"2026-05-01T07:31:21.433397Z","iopub.status.idle":"2026-05-01T07:31:37.500377Z","shell.execute_reply.started":"2026-05-01T07:31:21.433368Z","shell.execute_reply":"2026-05-01T07:31:37.499134Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import numpy as np\n\ndef compute_iou(y_true, y_pred, smooth=1e-6):\n    y_true = y_true.reshape(-1)\n    y_pred = y_pred.reshape(-1)\n\n    intersection = np.sum(y_true * y_pred)\n    union = np.sum(y_true) + np.sum(y_pred) - intersection\n\n    return (intersection + smooth) / (union + smooth)\n\n\nthresholds = np.arange(0.1, 0.9, 0.05)\n\nbest_t = 0\nbest_iou = 0\n\ny_val_pred = model.predict(X_val)\n\nfor t in thresholds:\n    preds = (y_val_pred > t).astype(np.float32)\n\n    iou_scores = []\n\n    for i in range(len(y_val)):\n        iou = compute_iou(y_val[i], preds[i])\n        iou_scores.append(iou)\n\n    mean_iou = np.mean(iou_scores)\n\n    print(f\"Threshold {t:.2f} → IoU: {mean_iou:.4f}\")\n\n    if mean_iou > best_iou:\n        best_iou = mean_iou\n        best_t = t\n\nprint(\"\\nBest Threshold:\", best_t)\nprint(\"Best IoU:\", best_iou)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:31:37.501564Z","iopub.execute_input":"2026-05-01T07:31:37.501947Z","iopub.status.idle":"2026-05-01T07:32:45.381208Z","shell.execute_reply.started":"2026-05-01T07:31:37.501915Z","shell.execute_reply":"2026-05-01T07:32:45.380234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def rle_encode(image):\n    pixels = image.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n    return ' '.join(str(x) for x in runs)\n\ntest_names = sorted(os.listdir(test_img_dir))\nimage_ids = []\nrle_encoded = []\n\nprint(\"Generating predictions...\")\nfor name in test_names:\n    img = load_image(os.path.join(test_img_dir, name))\n    img_input = np.expand_dims(img, axis=0)\n    pred = model.predict(img_input, verbose=0)\n    \n    pred_mask = pred[0, :, :, 0]\n    \n    # Use NEAREST interpolation for binary mask\n    pred_pil = Image.fromarray((pred_mask * 255).astype(np.uint8))\n    pred_resized = np.array(pred_pil.resize((512, 512), Image.NEAREST))\n    pred_binary = (pred_resized > int(0.55 * 255)).astype(np.uint8)\n    # = (pred_resized > 140).astype(np.uint8)\n    image_id = int(name.split('.')[0])\n    image_ids.append(image_id)\n    rle_encoded.append(rle_encode(pred_binary))\n\nresult = pd.DataFrame({'id': image_ids, 'rle': rle_encoded})\nresult = result.sort_values('id').reset_index(drop=True)\nresult.to_csv('submission.csv', index=False)\n\nprint(\"Done!\")\nprint(result.head())\n\n# Verify RLE is not empty\nprint(\"\\nSample RLE:\", result['rle'][0][:100])\nprint(\"Empty RLEs:\", (result['rle'] == '').sum())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:38:19.565969Z","iopub.execute_input":"2026-05-01T07:38:19.566302Z","iopub.status.idle":"2026-05-01T07:38:56.945109Z","shell.execute_reply.started":"2026-05-01T07:38:19.566275Z","shell.execute_reply":"2026-05-01T07:38:56.944354Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for i in range(5):\n    rle = result.loc[i, 'rle']\n    print(f\"Image {i} RLE preview:\", rle[:100])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-01T07:43:20.959522Z","iopub.execute_input":"2026-05-01T07:43:20.959962Z","iopub.status.idle":"2026-05-01T07:43:20.965039Z","shell.execute_reply.started":"2026-05-01T07:43:20.959931Z","shell.execute_reply":"2026-05-01T07:43:20.964299Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}