{"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":[{"sourceId":117682,"databundleVersionId":15062069,"sourceType":"competition"},{"sourceId":734053,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":559462,"modelId":572036},{"sourceId":735673,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":560849,"modelId":573469},{"sourceId":736598,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":561618,"modelId":574257}],"dockerImageVersionId":31234,"isInternetEnabled":false,"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-01-31T02:17:16.647513Z","iopub.execute_input":"2026-01-31T02:17:16.648164Z","iopub.status.idle":"2026-01-31T02:17:18.302462Z","shell.execute_reply.started":"2026-01-31T02:17:16.648133Z","shell.execute_reply":"2026-01-31T02:17:18.301722Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport gc\nimport numpy as np\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport matplotlib.pyplot as plt\nfrom PIL import Image, ImageSequence\nfrom tqdm import tqdm\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:18.303656Z","iopub.execute_input":"2026-01-31T02:17:18.303996Z","iopub.status.idle":"2026-01-31T02:17:22.625410Z","shell.execute_reply.started":"2026-01-31T02:17:18.303973Z","shell.execute_reply":"2026-01-31T02:17:22.624694Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CELL 1 - DATA LOADING & SANITY CHECKS\n\nPurpose:\n- Verify dataset integrity\n- confirm volume - label alignment\n- Catch shape/value bugs early","metadata":{}},{"cell_type":"code","source":"from pathlib import Path\nimport tifffile as tiff\n\nBASE_DIR = Path(\"/kaggle/input/vesuvius-challenge-surface-detection\")\n\nIMAGE_DIR = BASE_DIR / \"train_images\"\nLABEL_DIR = BASE_DIR / \"train_labels\"\n\nimage_files = sorted(IMAGE_DIR.glob(\"*.tif\"))\nlabel_files = sorted(LABEL_DIR.glob(\"*.tif\"))\n\nprint(f\"Found {len(image_files)} image volumes\")\nprint(f\"Found {len(label_files)} label masks\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:22.626375Z","iopub.execute_input":"2026-01-31T02:17:22.626794Z","iopub.status.idle":"2026-01-31T02:17:22.887025Z","shell.execute_reply.started":"2026-01-31T02:17:22.626753Z","shell.execute_reply":"2026-01-31T02:17:22.886132Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"MATCH IMAGE - LABEL BY ID","metadata":{}},{"cell_type":"code","source":"label_ids = {p.stem for p in label_files}\nimage_ids = {p.stem for p in image_files}\ncommon_ids = sorted(label_ids & image_ids)\nprint(f\"Matched fragments: {len(common_ids)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:22.888834Z","iopub.execute_input":"2026-01-31T02:17:22.889145Z","iopub.status.idle":"2026-01-31T02:17:22.895209Z","shell.execute_reply.started":"2026-01-31T02:17:22.889120Z","shell.execute_reply":"2026-01-31T02:17:22.894470Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# CELL 2 - 3D SIGNAL QUANTIFICATION\n\nPurpose:\n- Measure class balance in 3D\n- Inspect per-volume and per-slice signal distribution\n- Inform class choice and patch extraction","metadata":{}},{"cell_type":"code","source":"PATCH_SIZE = 96\nSTRIDE = 16\nGAUSS_SIGMA = 8","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:22.896158Z","iopub.execute_input":"2026-01-31T02:17:22.896474Z","iopub.status.idle":"2026-01-31T02:17:22.907207Z","shell.execute_reply.started":"2026-01-31T02:17:22.896436Z","shell.execute_reply":"2026-01-31T02:17:22.906568Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Reduce CUDA fragmentation\nos.environ[\"PYTORCH_CUDA_ALLOC_CONF\"] = \"expandable_segments:True\"\n\nDEVICE = \"cuda\" if torch.cuda.is_available() else \"cpu\"\nprint(\"Using device:\", DEVICE)\n\nMODEL_PATH = \"/kaggle/input/model-v2/pytorch/default/1/unet3d_vesuvius_model_v2.pth\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:22.908129Z","iopub.execute_input":"2026-01-31T02:17:22.908329Z","iopub.status.idle":"2026-01-31T02:17:23.164091Z","shell.execute_reply.started":"2026-01-31T02:17:22.908309Z","shell.execute_reply":"2026-01-31T02:17:23.163275Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch.nn as nn\nimport torch.nn.functional as F\n\nclass ConvBlock(nn.Module):\n    def __init__(self, in_c, out_c):\n        super().__init__()\n        self.block = nn.Sequential(\n            nn.Conv3d(in_c, out_c, 3, padding=1),\n            nn.BatchNorm3d(out_c),\n            nn.ReLU(inplace=True),\n            nn.Conv3d(out_c, out_c, 3, padding=1),\n            nn.BatchNorm3d(out_c),\n            nn.ReLU(inplace=True),\n        )\n    def forward(self, x):\n        return self.block(x)\n\nclass UNet3D(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.enc1 = ConvBlock(1, 16)\n        self.enc2 = ConvBlock(16, 32)\n        self.enc3 = ConvBlock(32, 64)\n        self.pool = nn.MaxPool3d(2)\n        self.dec2 = ConvBlock(64 + 32, 32)\n        self.dec1 = ConvBlock(32 + 16, 16)\n        self.up = nn.Upsample(scale_factor=2, mode=\"trilinear\", align_corners=False)\n        self.out = nn.Conv3d(16, 1, 1)\n\n    def forward(self, x):\n        e1 = self.enc1(x)\n        e2 = self.enc2(self.pool(e1))\n        e3 = self.enc3(self.pool(e2))\n        d2 = self.up(e3)\n        d2 = self.dec2(torch.cat([d2, e2], dim=1))\n        d1 = self.up(d2)\n        d1 = self.dec1(torch.cat([d1, e1], dim=1))\n        return self.out(d1)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.165081Z","iopub.execute_input":"2026-01-31T02:17:23.165626Z","iopub.status.idle":"2026-01-31T02:17:23.177477Z","shell.execute_reply.started":"2026-01-31T02:17:23.165601Z","shell.execute_reply":"2026-01-31T02:17:23.176659Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Load model","metadata":{}},{"cell_type":"code","source":"model = UNet3D().to(DEVICE)\n\ncheckpoint = torch.load(MODEL_PATH, map_location=DEVICE)\nmodel.load_state_dict(checkpoint[\"model_state_dict\"])\nmodel.eval()\n\nprint(\"Model loaded from: \", MODEL_PATH)\nprint(\"Checpoint epoch: \", checkpoint[\"epoch\"])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.178286Z","iopub.execute_input":"2026-01-31T02:17:23.178492Z","iopub.status.idle":"2026-01-31T02:17:23.624224Z","shell.execute_reply.started":"2026-01-31T02:17:23.178472Z","shell.execute_reply":"2026-01-31T02:17:23.623433Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_tiff_stack(path):\n    img = Image.open(path)\n    arr = []\n    try:\n        while True:\n            arr.append(np.array(img))\n            img.seek(img.tell() + 1)\n    except EOFError:\n        pass\n    return np.stack(arr, axis=0)  # (Z,H,W)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.625362Z","iopub.execute_input":"2026-01-31T02:17:23.625723Z","iopub.status.idle":"2026-01-31T02:17:23.632461Z","shell.execute_reply.started":"2026-01-31T02:17:23.625687Z","shell.execute_reply":"2026-01-31T02:17:23.631685Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# GAUSSIAN WEIGHT 3D","metadata":{}},{"cell_type":"code","source":"def gaussian_weight(patch_size, sigma):\n    ax = np.linspace(-(patch_size//2), patch_size//2, patch_size)\n    xx, yy, zz = np.meshgrid(ax, ax, ax, indexing='ij')\n    kernel = np.exp(-(xx**2 + yy**2 + zz**2) / (2 * sigma**2))\n    return kernel / kernel.max()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.635148Z","iopub.execute_input":"2026-01-31T02:17:23.635457Z","iopub.status.idle":"2026-01-31T02:17:23.648786Z","shell.execute_reply.started":"2026-01-31T02:17:23.635417Z","shell.execute_reply":"2026-01-31T02:17:23.647694Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# RUN MODEL","metadata":{}},{"cell_type":"code","source":"@torch.no_grad()\ndef sliding_window_inference(volume):\n    Z, H, W = volume.shape\n\n    prob_sum = np.zeros((Z, H, W), np.float32)\n    weight_sum = np.zeros((Z, H, W), np.float32)\n\n    weight = gaussian_weight(PATCH_SIZE, GAUSS_SIGMA)\n\n    r = PATCH_SIZE // 2\n\n    for z in tqdm(range(r, Z - r, STRIDE), desc=\"Z\"):\n        for y in range(r, H - r, STRIDE):\n            for x in range(r, W - r, STRIDE):\n\n                patch = volume[\n                    z-r:z+r,\n                    y-r:y+r,\n                    x-r:x+r\n                ]\n\n                patch = torch.tensor(\n                    patch, dtype=torch.float32,\n                    device=DEVICE\n                ).unsqueeze(0).unsqueeze(0) / 255.0\n\n                logits = model(patch)\n                probs = torch.sigmoid(logits)[0,0].cpu().numpy()\n\n                prob_sum[z-r:z+r, y-r:y+r, x-r:x+r] += probs * weight\n                weight_sum[z-r:z+r, y-r:y+r, x-r:x+r] += weight\n\n    return prob_sum / np.maximum(weight_sum, 1e-6)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.650062Z","iopub.execute_input":"2026-01-31T02:17:23.650836Z","iopub.status.idle":"2026-01-31T02:17:23.663163Z","shell.execute_reply.started":"2026-01-31T02:17:23.650812Z","shell.execute_reply":"2026-01-31T02:17:23.662448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"THRESHOLD = 0.08\n\ndef prob_to_mask(prob):\n    return (prob > THRESHOLD).astype(np.uint8)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.663969Z","iopub.execute_input":"2026-01-31T02:17:23.664231Z","iopub.status.idle":"2026-01-31T02:17:23.677670Z","shell.execute_reply.started":"2026-01-31T02:17:23.664210Z","shell.execute_reply":"2026-01-31T02:17:23.676901Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# VISUAL ","metadata":{}},{"cell_type":"code","source":"def visualize_patch_prediction(volume, labels, probs):\n    D, H, W = volume.shape\n    z = np.random.randint(0, D - PATCH_SIZE)\n\n    mid = PATCH_SIZE // 2\n\n    plt.figure(figsize=(15,5))\n\n    plt.subplot(1,3,1)\n    plt.imshow(volume[z+mid], cmap=\"gray\")\n    plt.title(\"CT slice\")\n    plt.axis(\"off\")\n\n    plt.subplot(1,3,2)\n    plt.imshow(labels[z+mid], cmap=\"viridis\", vmin=0, vmax=2)\n    plt.title(\"Label\")\n    plt.axis(\"off\")\n\n    plt.subplot(1,3,3)\n    plt.imshow(volume[z+mid], cmap=\"gray\")\n    plt.imshow(probs[z+mid], cmap=\"Reds\", alpha=0.5)\n    plt.title(\"Prediction\")\n    plt.axis(\"off\")\n\n    plt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.678565Z","iopub.execute_input":"2026-01-31T02:17:23.678872Z","iopub.status.idle":"2026-01-31T02:17:23.690180Z","shell.execute_reply.started":"2026-01-31T02:17:23.678851Z","shell.execute_reply":"2026-01-31T02:17:23.689403Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def normalize_volume_shape(volume):\n    \"\"\"\n    Ensure volume shape is (Z, H, W)\n    \"\"\"\n    if volume.ndim == 4:\n        # (Z, H, W, C) → lấy channel đầu\n        volume = volume[..., 0]\n    elif volume.ndim != 3:\n        raise ValueError(f\"Unexpected volume shape: {volume.shape}\")\n    return volume\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.691136Z","iopub.execute_input":"2026-01-31T02:17:23.691408Z","iopub.status.idle":"2026-01-31T02:17:23.701912Z","shell.execute_reply.started":"2026-01-31T02:17:23.691379Z","shell.execute_reply":"2026-01-31T02:17:23.701268Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# labels = list(label_ids)\n# fid = labels[10]\n# volume = load_tiff_stack(f\"{IMAGE_DIR}/{fid}.tif\")\n# labels = load_tiff_stack(f\"{LABEL_DIR}/{fid}.tif\")\n# # 🔥 FIX SHAPE\n# volume = normalize_volume_shape(volume)\n# labels = normalize_volume_shape(labels)\n# print(\"Fixed volume shape:\", volume.shape)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:23.702890Z","iopub.execute_input":"2026-01-31T02:17:23.703484Z","iopub.status.idle":"2026-01-31T02:17:25.504592Z","shell.execute_reply.started":"2026-01-31T02:17:23.703450Z","shell.execute_reply":"2026-01-31T02:17:25.503971Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # Clear GPU before inference\n# torch.cuda.empty_cache()\n# gc.collect()\n\n# probs = sliding_window_inference(volume)\n\n# visualize_patch_prediction(volume, labels, probs)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:37.185335Z","iopub.execute_input":"2026-01-31T02:17:37.185935Z","iopub.status.idle":"2026-01-31T02:18:43.821957Z","shell.execute_reply.started":"2026-01-31T02:17:37.185904Z","shell.execute_reply":"2026-01-31T02:18:43.820993Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# z = volume.shape[0] // 2\n# plt.figure(figsize=(18, 5))\n\n# plt.subplot(1, 3, 1)\n# plt.imshow(volume[z], cmap=\"gray\")\n# plt.title(\"CT\")\n# plt.axis(\"off\")\n\n# plt.subplot(1,3,2)\n# plt.imshow(labels[z], cmap=\"viridis\", vmin=0, vmax=2)\n# plt.title(\"GT (label)\")\n# plt.axis(\"off\")\n\n# plt.subplot(1,3,3)\n# plt.imshow(volume[z], cmap=\"gray\")\n# plt.imshow(probs[z], cmap=\"Reds\", alpha=0.6)\n# plt.title(\"Prediction\")\n# plt.axis(\"off\")\n\n# plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:25.605843Z","iopub.status.idle":"2026-01-31T02:17:25.606135Z","shell.execute_reply.started":"2026-01-31T02:17:25.605987Z","shell.execute_reply":"2026-01-31T02:17:25.606002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# mask = (probs > 0.5).astype(np.uint8)\n# fg_ratio = mask.mean()\n# print(\"Foreground ratio: \", fg_ratio)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:25.607246Z","iopub.status.idle":"2026-01-31T02:17:25.607660Z","shell.execute_reply.started":"2026-01-31T02:17:25.607426Z","shell.execute_reply":"2026-01-31T02:17:25.607447Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# z_sum = mask.sum(axis=(1, 2))\n# plt.plot(z_sum)\n# plt.xlabel(\"Z slice\")\n# plt.ylabel(\"Foreground voxels\")\n# plt.title(\"Z-continuity\")\n# plt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:25.608962Z","iopub.status.idle":"2026-01-31T02:17:25.609288Z","shell.execute_reply.started":"2026-01-31T02:17:25.609117Z","shell.execute_reply":"2026-01-31T02:17:25.609139Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# from scipy.ndimage import distance_transform_edt\n\n# gt_surface = (labels == 1)\n# pred_mask = (probs > 0.5)\n\n# dist = distance_transform_edt(~gt_surface)\n# mean_dist = dist[pred_mask].mean() if pred_mask.any() else None\n\n# print(\"Mean distance to GT surface: \", mean_dist)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:25.610407Z","iopub.status.idle":"2026-01-31T02:17:25.610770Z","shell.execute_reply.started":"2026-01-31T02:17:25.610580Z","shell.execute_reply":"2026-01-31T02:17:25.610596Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"CREATE SUBMISSION ZIP","metadata":{}},{"cell_type":"code","source":"def save_mask_as_tiff(mask, path):\n    assert mask.dtype == np.uint8\n    assert mask.ndim == 3\n\n    images = [Image.fromarray(mask[z]) for z in range(mask.shape[0])]\n    images[0].save(\n        path,\n        save_all=True,\n        append_images=images[1:],\n        compression=\"tiff_deflate\"\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:19:00.311011Z","iopub.execute_input":"2026-01-31T02:19:00.311377Z","iopub.status.idle":"2026-01-31T02:19:00.316543Z","shell.execute_reply.started":"2026-01-31T02:19:00.311344Z","shell.execute_reply":"2026-01-31T02:19:00.315707Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"SUB_DIR = \"/kaggle/working/submission\"\nos.makedirs(SUB_DIR, exist_ok=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:19:02.860470Z","iopub.execute_input":"2026-01-31T02:19:02.860824Z","iopub.status.idle":"2026-01-31T02:19:02.865178Z","shell.execute_reply.started":"2026-01-31T02:19:02.860791Z","shell.execute_reply":"2026-01-31T02:19:02.864546Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TEST_DIR = \"/kaggle/input/vesuvius-challenge-surface-detection/test_images\"\nTEST_IDS = sorted(os.listdir(TEST_DIR))\nprint(\"Test fragments: \", TEST_IDS)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:19:07.639411Z","iopub.execute_input":"2026-01-31T02:19:07.639745Z","iopub.status.idle":"2026-01-31T02:19:07.651908Z","shell.execute_reply.started":"2026-01-31T02:19:07.639719Z","shell.execute_reply":"2026-01-31T02:19:07.651270Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for fid in TEST_IDS:\n    print(f\"processing test fragment: {fid}\")\n\n    volume = load_tiff_stack(f\"{TEST_DIR}/{fid}\")\n    volume = normalize_volume_shape(volume)\n\n    torch.cuda.empty_cache()\n    gc.collect()\n    probs = sliding_window_inference(volume)\n    mask = prob_to_mask(probs)\n\n    out_path = f\"{SUB_DIR}/{fid}\"\n    save_mask_as_tiff(mask, out_path)\n\n    del volume, probs, mask\n    torch.cuda.empty_cache()\n    gc.collect()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:25:32.705869Z","iopub.execute_input":"2026-01-31T02:25:32.706455Z","iopub.status.idle":"2026-01-31T02:28:49.986019Z","shell.execute_reply.started":"2026-01-31T02:25:32.706425Z","shell.execute_reply":"2026-01-31T02:28:49.985200Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import zipfile\n\nZIP_PATH = \"/kaggle/working/submission.zip\"\n\nwith zipfile.ZipFile(ZIP_PATH, \"w\", zipfile.ZIP_DEFLATED) as zf:\n    for fname in os.listdir(SUB_DIR):\n        zf.write(\n            os.path.join(SUB_DIR, fname),\n            arcname=fname\n        )\n\nprint(\"Created:\", ZIP_PATH)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:29:01.670896Z","iopub.execute_input":"2026-01-31T02:29:01.671804Z","iopub.status.idle":"2026-01-31T02:29:01.710799Z","shell.execute_reply.started":"2026-01-31T02:29:01.671774Z","shell.execute_reply":"2026-01-31T02:29:01.710194Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# zip_path = Path(\"/kaggle/working/submission.zip\")\n\n# with zipfile.ZipFile(zip_path, \"w\", zipfile.ZIP_DEFLATED) as zf:\n#     for tif_file in OUTPUT_DIR.glob(\"*.tif\"):\n#         zf.write(tif_file, arcname=tif_file.name)\n\n# print(f\"Submission zip created at: {zip_path}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-01-31T02:17:25.619531Z","iopub.status.idle":"2026-01-31T02:17:25.619854Z","shell.execute_reply.started":"2026-01-31T02:17:25.619694Z","shell.execute_reply":"2026-01-31T02:17:25.619714Z"}},"outputs":[],"execution_count":null}]}