{"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":8089,"databundleVersionId":44321}],"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-14T06:27:49.579697Z","iopub.execute_input":"2026-05-14T06:27:49.580067Z","iopub.status.idle":"2026-05-14T06:27:50.721205Z","shell.execute_reply.started":"2026-05-14T06:27:49.580039Z","shell.execute_reply":"2026-05-14T06:27:50.720321Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# =========================================\n# 1. 기본 라이브러리\n# =========================================\nimport os\nimport random\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nfrom tqdm import tqdm\nfrom skimage.io import imread\nfrom skimage.transform import resize\n\nimport torch\n\n# =========================================\n# 2. Seed 고정\n# =========================================\nseed = 42\n\nrandom.seed(seed)\nnp.random.seed(seed)\n\ntorch.manual_seed(seed)\ntorch.cuda.manual_seed(seed)\ntorch.cuda.manual_seed_all(seed)\n\ntorch.backends.cudnn.deterministic = True\ntorch.backends.cudnn.benchmark = False\n\nprint(\"Seed fixed:\", seed)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:27:50.723032Z","iopub.execute_input":"2026-05-14T06:27:50.723438Z","iopub.status.idle":"2026-05-14T06:27:56.894391Z","shell.execute_reply.started":"2026-05-14T06:27:50.723411Z","shell.execute_reply":"2026-05-14T06:27:56.893507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport zipfile\n\nBASE_PATH = \"/kaggle/input/competitions/data-science-bowl-2018/\"\nOUTPUT_PATH = \"/kaggle/working\"\n\nos.makedirs(OUTPUT_PATH, exist_ok=True)\n\nzip_files = [\n    \"stage1_sample_submission.csv.zip\",\n    \"stage1_solution.csv.zip\",\n    \"stage1_test.zip\",\n    \"stage1_train.zip\",\n    \"stage1_train_labels.csv.zip\",\n    \"stage2_sample_submission_final.csv.zip\",\n    \"stage2_test_final.zip\"\n]\n\nfor zip_name in zip_files:\n\n    zip_path = os.path.join(BASE_PATH, zip_name)\n\n    # .zip 제거해서 폴더명 생성\n    folder_name = zip_name.replace(\".zip\", \"\")\n\n    extract_path = os.path.join(OUTPUT_PATH, folder_name)\n\n    os.makedirs(extract_path, exist_ok=True)\n\n    print(f\"Extracting: {zip_name}\")\n\n    with zipfile.ZipFile(zip_path, 'r') as zip_ref:\n        zip_ref.extractall(extract_path)\n\nprint(\"Done!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:27:56.895421Z","iopub.execute_input":"2026-05-14T06:27:56.896347Z","iopub.status.idle":"2026-05-14T06:28:03.951468Z","shell.execute_reply.started":"2026-05-14T06:27:56.896318Z","shell.execute_reply":"2026-05-14T06:28:03.950681Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nROOT = \"/kaggle/working\"\n\nfor name in os.listdir(ROOT):\n\n    path = os.path.join(ROOT, name)\n\n    if os.path.isdir(path):\n        count = len(os.listdir(path))\n        print(f\"[DIR] {name}\")\n        print(f\"  files : {count}\")\n\n    else:\n        print(f\"[FILE] {name}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:03.952351Z","iopub.execute_input":"2026-05-14T06:28:03.952661Z","iopub.status.idle":"2026-05-14T06:28:03.961596Z","shell.execute_reply.started":"2026-05-14T06:28:03.952636Z","shell.execute_reply":"2026-05-14T06:28:03.960746Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom skimage.io import imread\n\nROOT = \"/kaggle/working\"\n\nTRAIN_DIR = os.path.join(ROOT, \"stage1_train\")\n\ntrain_ids = os.listdir(TRAIN_DIR)[:6]\n\nplt.figure(figsize=(10, 24))\n\nfor i, image_id in enumerate(train_ids):\n\n    image_path = os.path.join(\n        TRAIN_DIR,\n        image_id,\n        \"images\",\n        image_id + \".png\"\n    )\n\n    mask_dir = os.path.join(\n        TRAIN_DIR,\n        image_id,\n        \"masks\"\n    )\n\n    image = imread(image_path)\n\n    combined_mask = np.zeros(image.shape[:2], dtype=np.uint8)\n\n    for mask_file in os.listdir(mask_dir):\n\n        mask_path = os.path.join(mask_dir, mask_file)\n\n        mask = imread(mask_path)\n\n        combined_mask = np.maximum(combined_mask, mask)\n\n    # 원본 이미지\n    plt.subplot(6, 2, i * 2 + 1)\n    plt.imshow(image)\n    plt.title(f\"Original\\n{image_id[:10]}\")\n    plt.axis(\"off\")\n\n    # 합쳐진 GT mask\n    plt.subplot(6, 2, i * 2 + 2)\n    plt.imshow(combined_mask, cmap=\"gray\")\n    plt.title(\"GT Combined Mask\")\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:03.962695Z","iopub.execute_input":"2026-05-14T06:28:03.963113Z","iopub.status.idle":"2026-05-14T06:28:06.388645Z","shell.execute_reply.started":"2026-05-14T06:28:03.963078Z","shell.execute_reply":"2026-05-14T06:28:06.387686Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nfrom skimage.io import imread\n\nROOT = \"/kaggle/working\"\nTRAIN_DIR = os.path.join(ROOT, \"stage1_train\")\n\ntrain_ids = os.listdir(TRAIN_DIR)\n\nfor image_id in train_ids[:10]:\n    image_path = os.path.join(TRAIN_DIR, image_id, \"images\", image_id + \".png\")\n    image = imread(image_path)\n\n    print(image_id, image.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:06.389744Z","iopub.execute_input":"2026-05-14T06:28:06.390169Z","iopub.status.idle":"2026-05-14T06:28:06.488927Z","shell.execute_reply.started":"2026-05-14T06:28:06.390140Z","shell.execute_reply":"2026-05-14T06:28:06.488269Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport numpy as np\nfrom skimage.io import imread\nfrom skimage.transform import resize\n\nimport torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:06.491387Z","iopub.execute_input":"2026-05-14T06:28:06.491656Z","iopub.status.idle":"2026-05-14T06:28:07.261743Z","shell.execute_reply.started":"2026-05-14T06:28:06.491617Z","shell.execute_reply":"2026-05-14T06:28:07.260964Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"ROOT = \"/kaggle/working\"\nTRAIN_DIR = os.path.join(ROOT, \"stage1_train\")\n\nIMG_HEIGHT = 256\nIMG_WIDTH = 256\nIMG_CHANNELS = 3\n\nall_ids = os.listdir(TRAIN_DIR)\n\ntrain_ids, valid_ids = train_test_split(\n    all_ids,\n    test_size=0.1,      # valid 10%, train 90%\n    random_state=42,\n    shuffle=True\n)\n\nprint(\"train:\", len(train_ids))\nprint(\"valid:\", len(valid_ids))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:07.262674Z","iopub.execute_input":"2026-05-14T06:28:07.263075Z","iopub.status.idle":"2026-05-14T06:28:07.271597Z","shell.execute_reply.started":"2026-05-14T06:28:07.263048Z","shell.execute_reply":"2026-05-14T06:28:07.270774Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class NucleiSegDataset(Dataset):\n    def __init__(self, ids, train_dir, img_height=256, img_width=256):\n        self.ids = ids\n        self.train_dir = train_dir\n        self.img_height = img_height\n        self.img_width = img_width\n\n    def __len__(self):\n        return len(self.ids)\n\n    def __getitem__(self, idx):\n        image_id = self.ids[idx]\n        base_path = os.path.join(self.train_dir, image_id)\n\n        image_path = os.path.join(base_path, \"images\", image_id + \".png\")\n        mask_dir = os.path.join(base_path, \"masks\")\n\n        image = imread(image_path)[:, :, :IMG_CHANNELS]\n        image = resize(\n            image,\n            (self.img_height, self.img_width),\n            mode=\"constant\",\n            preserve_range=True\n        ).astype(np.float32)\n\n        image = image / 255.0\n\n        combined_mask = np.zeros((self.img_height, self.img_width), dtype=np.float32)\n\n        for mask_file in os.listdir(mask_dir):\n            mask_path = os.path.join(mask_dir, mask_file)\n            mask = imread(mask_path)\n\n            mask = resize(\n                mask,\n                (self.img_height, self.img_width),\n                mode=\"constant\",\n                preserve_range=True\n            )\n\n            mask = (mask > 0).astype(np.float32)\n            combined_mask = np.maximum(combined_mask, mask)\n\n        image = torch.tensor(image, dtype=torch.float32).permute(2, 0, 1)\n        mask = torch.tensor(combined_mask, dtype=torch.float32).unsqueeze(0)\n\n        return image, mask","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:07.272579Z","iopub.execute_input":"2026-05-14T06:28:07.272901Z","iopub.status.idle":"2026-05-14T06:28:07.284125Z","shell.execute_reply.started":"2026-05-14T06:28:07.272866Z","shell.execute_reply":"2026-05-14T06:28:07.283274Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_dataset = NucleiSegDataset(\n    ids=train_ids,\n    train_dir=TRAIN_DIR,\n    img_height=IMG_HEIGHT,\n    img_width=IMG_WIDTH\n)\n\nvalid_dataset = NucleiSegDataset(\n    ids=valid_ids,\n    train_dir=TRAIN_DIR,\n    img_height=IMG_HEIGHT,\n    img_width=IMG_WIDTH\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:07.285259Z","iopub.execute_input":"2026-05-14T06:28:07.286588Z","iopub.status.idle":"2026-05-14T06:28:07.300605Z","shell.execute_reply.started":"2026-05-14T06:28:07.286550Z","shell.execute_reply":"2026-05-14T06:28:07.298937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"batch_size = 16\n\ntrain_loader = DataLoader(\n    train_dataset,\n    batch_size=batch_size,\n    shuffle=True,\n    num_workers=2,\n    pin_memory=True\n)\n\nvalid_loader = DataLoader(\n    valid_dataset,\n    batch_size=batch_size,\n    shuffle=False,\n    num_workers=2,\n    pin_memory=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:07.302110Z","iopub.execute_input":"2026-05-14T06:28:07.302512Z","iopub.status.idle":"2026-05-14T06:28:07.312558Z","shell.execute_reply.started":"2026-05-14T06:28:07.302487Z","shell.execute_reply":"2026-05-14T06:28:07.311592Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"images, masks = next(iter(train_loader))\n\nprint(\"images:\", images.shape)\nprint(\"masks:\", masks.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:07.313425Z","iopub.execute_input":"2026-05-14T06:28:07.313808Z","iopub.status.idle":"2026-05-14T06:28:19.362136Z","shell.execute_reply.started":"2026-05-14T06:28:07.313783Z","shell.execute_reply":"2026-05-14T06:28:19.360935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\n\ndevice = torch.device(\n    \"cuda\" if torch.cuda.is_available() else \"cpu\"\n)\n\nprint(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:19.364428Z","iopub.execute_input":"2026-05-14T06:28:19.364897Z","iopub.status.idle":"2026-05-14T06:28:19.371467Z","shell.execute_reply.started":"2026-05-14T06:28:19.364854Z","shell.execute_reply":"2026-05-14T06:28:19.370454Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\n\nclass DoubleConv(nn.Module):\n    def __init__(self, in_ch, out_ch):\n        super().__init__()\n        self.net = nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1),\n            nn.ReLU(inplace=True),\n        )\n\n    def forward(self, x):\n        return self.net(x)\n\n\nclass UNet(nn.Module):\n    def __init__(self, in_channels=3, out_channels=1):\n        super().__init__()\n\n        self.c1 = DoubleConv(in_channels, 64)\n        self.p1 = nn.MaxPool2d(2)\n\n        self.c2 = DoubleConv(64, 128)\n        self.p2 = nn.MaxPool2d(2)\n\n        self.c3 = DoubleConv(128, 256)\n        self.p3 = nn.MaxPool2d(2)\n\n        self.c4 = DoubleConv(256, 512)\n        self.p4 = nn.MaxPool2d(2)\n\n        self.c5 = DoubleConv(512, 1024)\n\n        self.u6 = nn.ConvTranspose2d(1024, 512, kernel_size=2, stride=2)\n        self.c6 = DoubleConv(1024, 512)\n\n        self.u7 = nn.ConvTranspose2d(512, 256, kernel_size=2, stride=2)\n        self.c7 = DoubleConv(512, 256)\n\n        self.u8 = nn.ConvTranspose2d(256, 128, kernel_size=2, stride=2)\n        self.c8 = DoubleConv(256, 128)\n\n        self.u9 = nn.ConvTranspose2d(128, 64, kernel_size=2, stride=2)\n        self.c9 = DoubleConv(128, 64)\n\n        self.out = nn.Conv2d(64, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        c1 = self.c1(x)\n        p1 = self.p1(c1)\n\n        c2 = self.c2(p1)\n        p2 = self.p2(c2)\n\n        c3 = self.c3(p2)\n        p3 = self.p3(c3)\n\n        c4 = self.c4(p3)\n        p4 = self.p4(c4)\n\n        c5 = self.c5(p4)\n\n        u6 = self.u6(c5)\n        u6 = torch.cat([u6, c4], dim=1)\n        c6 = self.c6(u6)\n\n        u7 = self.u7(c6)\n        u7 = torch.cat([u7, c3], dim=1)\n        c7 = self.c7(u7)\n\n        u8 = self.u8(c7)\n        u8 = torch.cat([u8, c2], dim=1)\n        c8 = self.c8(u8)\n\n        u9 = self.u9(c8)\n        u9 = torch.cat([u9, c1], dim=1)\n        c9 = self.c9(u9)\n\n        return self.out(c9)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:19.373641Z","iopub.execute_input":"2026-05-14T06:28:19.374071Z","iopub.status.idle":"2026-05-14T06:28:19.387971Z","shell.execute_reply.started":"2026-05-14T06:28:19.374044Z","shell.execute_reply":"2026-05-14T06:28:19.387052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dice_score(preds, targets, eps=1e-7):\n    preds = preds.float()\n    targets = targets.float()\n\n    intersection = (preds * targets).sum(dim=(1, 2, 3))\n    union = preds.sum(dim=(1, 2, 3)) + targets.sum(dim=(1, 2, 3))\n\n    dice = (2 * intersection + eps) / (union + eps)\n    return dice.mean().item()\n\n\ndef iou_score(preds, targets, eps=1e-7):\n    preds = preds.float()\n    targets = targets.float()\n\n    intersection = (preds * targets).sum(dim=(1, 2, 3))\n    union = ((preds + targets) > 0).float().sum(dim=(1, 2, 3))\n\n    iou = (intersection + eps) / (union + eps)\n    return iou.mean().item()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:19.389067Z","iopub.execute_input":"2026-05-14T06:28:19.389324Z","iopub.status.idle":"2026-05-14T06:28:19.404175Z","shell.execute_reply.started":"2026-05-14T06:28:19.389303Z","shell.execute_reply":"2026-05-14T06:28:19.403475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = UNet().to(device)\n\ncriterion = nn.BCEWithLogitsLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-4)\n\nEPOCHS = 10\nTHRESHOLD = 0.5\n\nhistory = {\n    \"train_loss\": [],\n    \"valid_loss\": [],\n    \"valid_dice\": [],\n    \"valid_iou\": []\n}\n\nbest_iou = 0","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:19.405141Z","iopub.execute_input":"2026-05-14T06:28:19.405400Z","iopub.status.idle":"2026-05-14T06:28:23.006811Z","shell.execute_reply.started":"2026-05-14T06:28:19.405339Z","shell.execute_reply":"2026-05-14T06:28:23.005897Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for epoch in range(EPOCHS):\n    model.train()\n    train_loss = 0.0\n    train_total = 0\n\n    for images, masks in tqdm(train_loader, desc=f\"Epoch {epoch+1}/{EPOCHS} [Train]\"):\n        images = images.to(device, non_blocking=True)\n        masks = masks.to(device, non_blocking=True)\n\n        optimizer.zero_grad()\n\n        logits = model(images)\n        loss = criterion(logits, masks)\n\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item() * images.size(0)\n        train_total += images.size(0)\n\n    avg_train_loss = train_loss / train_total\n\n    model.eval()\n    valid_loss = 0.0\n    valid_total = 0\n    dice_total = 0.0\n    iou_total = 0.0\n    batch_count = 0\n\n    with torch.no_grad():\n        for images, masks in tqdm(valid_loader, desc=f\"Epoch {epoch+1}/{EPOCHS} [Valid]\"):\n            images = images.to(device, non_blocking=True)\n            masks = masks.to(device, non_blocking=True)\n\n            logits = model(images)\n            loss = criterion(logits, masks)\n\n            probs = torch.sigmoid(logits)\n            preds = (probs > THRESHOLD).float()\n\n            valid_loss += loss.item() * images.size(0)\n            valid_total += images.size(0)\n\n            dice_total += dice_score(preds, masks)\n            iou_total += iou_score(preds, masks)\n            batch_count += 1\n\n    avg_valid_loss = valid_loss / valid_total\n    avg_dice = dice_total / batch_count\n    avg_iou = iou_total / batch_count\n\n    history[\"train_loss\"].append(avg_train_loss)\n    history[\"valid_loss\"].append(avg_valid_loss)\n    history[\"valid_dice\"].append(avg_dice)\n    history[\"valid_iou\"].append(avg_iou)\n\n    print(f\"Epoch [{epoch+1}/{EPOCHS}]\")\n    print(f\"Train Loss : {avg_train_loss:.4f}\")\n    print(f\"Valid Loss : {avg_valid_loss:.4f}\")\n    print(f\"Valid Dice : {avg_dice:.4f}\")\n    print(f\"Valid IoU  : {avg_iou:.4f}\")\n    print(\"-\" * 40)\n\n    if avg_iou > best_iou:\n        best_iou = avg_iou\n        torch.save(model.state_dict(), \"/kaggle/working/best_unet.pth\")\n        print(\"Best model saved!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:28:23.007916Z","iopub.execute_input":"2026-05-14T06:28:23.008816Z","iopub.status.idle":"2026-05-14T06:50:15.131618Z","shell.execute_reply.started":"2026-05-14T06:28:23.008787Z","shell.execute_reply":"2026-05-14T06:50:15.130763Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(8, 5))\nplt.plot(history[\"train_loss\"], label=\"Train Loss\")\nplt.plot(history[\"valid_loss\"], label=\"Valid Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.title(\"Train / Valid Loss\")\nplt.legend()\nplt.grid()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:50:15.133197Z","iopub.execute_input":"2026-05-14T06:50:15.133501Z","iopub.status.idle":"2026-05-14T06:50:15.279457Z","shell.execute_reply.started":"2026-05-14T06:50:15.133470Z","shell.execute_reply":"2026-05-14T06:50:15.278743Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(8, 5))\nplt.plot(history[\"valid_dice\"], label=\"Valid Dice\")\nplt.plot(history[\"valid_iou\"], label=\"Valid IoU\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Score\")\nplt.title(\"Validation Metrics\")\nplt.legend()\nplt.grid()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:50:15.280559Z","iopub.execute_input":"2026-05-14T06:50:15.280871Z","iopub.status.idle":"2026-05-14T06:50:15.415592Z","shell.execute_reply.started":"2026-05-14T06:50:15.280846Z","shell.execute_reply":"2026-05-14T06:50:15.414898Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.load_state_dict(torch.load(\"/kaggle/working/best_unet.pth\", map_location=device))\nmodel.eval()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:50:15.416669Z","iopub.execute_input":"2026-05-14T06:50:15.417393Z","iopub.status.idle":"2026-05-14T06:50:15.526003Z","shell.execute_reply.started":"2026-05-14T06:50:15.417365Z","shell.execute_reply":"2026-05-14T06:50:15.525140Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_predictions(model, dataset, count=3, threshold=0.5):\n    plt.figure(figsize=(12, count * 4))\n\n    for i in range(count):\n        image, gt_mask = dataset[i]\n\n        input_tensor = image.unsqueeze(0).to(device)\n\n        with torch.no_grad():\n            logits = model(input_tensor)\n            prob = torch.sigmoid(logits)[0, 0].cpu().numpy()\n\n        pred_mask = (prob > threshold).astype(np.uint8)\n\n        img_np = image.permute(1, 2, 0).cpu().numpy()\n        gt_np = gt_mask.squeeze().cpu().numpy()\n\n        plt.subplot(count, 3, i * 3 + 1)\n        plt.imshow(img_np)\n        plt.title(\"Input Image\")\n        plt.axis(\"off\")\n\n        plt.subplot(count, 3, i * 3 + 2)\n        plt.imshow(gt_np, cmap=\"gray\")\n        plt.title(\"GT Mask\")\n        plt.axis(\"off\")\n\n        plt.subplot(count, 3, i * 3 + 3)\n        plt.imshow(img_np)\n        plt.imshow(pred_mask, cmap=\"jet\", alpha=0.4)\n        plt.title(\"Predicted Mask\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\n\n\nshow_predictions(model, valid_dataset, count=10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:59:35.254781Z","iopub.execute_input":"2026-05-14T06:59:35.255478Z","iopub.status.idle":"2026-05-14T06:59:40.272305Z","shell.execute_reply.started":"2026-05-14T06:59:35.255445Z","shell.execute_reply":"2026-05-14T06:59:40.271413Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TestNucleiDataset(Dataset):\n    def __init__(self, ids, root_dir, img_size=256):\n        self.ids = ids\n        self.root_dir = root_dir\n        self.img_size = img_size\n\n    def __len__(self):\n        return len(self.ids)\n\n    def __getitem__(self, idx):\n        image_id = self.ids[idx]\n        base_path = os.path.join(self.root_dir, image_id)\n\n        img_path = os.path.join(base_path, \"images\", image_id + \".png\")\n\n        image = imread(img_path)[:, :, :3]\n        original_h, original_w = image.shape[:2]\n\n        image_resized = resize(\n            image,\n            (self.img_size, self.img_size),\n            mode=\"constant\",\n            preserve_range=True,\n            anti_aliasing=True\n        ).astype(np.float32)\n\n        image_resized = image_resized / 255.0\n\n        image_tensor = torch.tensor(image_resized, dtype=torch.float32).permute(2, 0, 1)\n\n        return image_tensor, image_id, original_h, original_w","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T06:59:04.863296Z","iopub.execute_input":"2026-05-14T06:59:04.863586Z","iopub.status.idle":"2026-05-14T06:59:04.871248Z","shell.execute_reply.started":"2026-05-14T06:59:04.863561Z","shell.execute_reply":"2026-05-14T06:59:04.870273Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from skimage.measure import label\ndef rle_encode(mask):\n    pixels = mask.T.flatten()\n    pixels = np.concatenate([[0], pixels, [0]])\n\n    runs = np.where(pixels[1:] != pixels[:-1])[0] + 1\n    runs[1::2] -= runs[::2]\n\n    return \" \".join(str(x) for x in runs)\n\n\ndef mask_to_rles(binary_mask):\n    labeled_mask = label(binary_mask)\n    rles = []\n\n    for i in range(1, labeled_mask.max() + 1):\n        instance = (labeled_mask == i).astype(np.uint8)\n\n        if instance.sum() == 0:\n            continue\n\n        rles.append(rle_encode(instance))\n\n    return rles","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T07:06:52.675597Z","iopub.execute_input":"2026-05-14T07:06:52.676504Z","iopub.status.idle":"2026-05-14T07:06:52.691865Z","shell.execute_reply.started":"2026-05-14T07:06:52.676460Z","shell.execute_reply":"2026-05-14T07:06:52.691155Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"TEST_DIR = OUTPUT_PATH + \"/stage1_test\"\n\ntest_ids = os.listdir(TEST_DIR)\n\ntest_ds = TestNucleiDataset(test_ids, TEST_DIR, 256)\n\ntest_loader = DataLoader(\n    test_ds,\n    batch_size=1,\n    shuffle=False,\n    num_workers=2,\n    pin_memory=True\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T07:05:14.727637Z","iopub.execute_input":"2026-05-14T07:05:14.727902Z","iopub.status.idle":"2026-05-14T07:05:14.733130Z","shell.execute_reply.started":"2026-05-14T07:05:14.727878Z","shell.execute_reply":"2026-05-14T07:05:14.732444Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.eval()\n\nsubmission_rows = []\n\nwith torch.no_grad():\n    for image, image_id, original_h, original_w in tqdm(test_loader, desc=\"Predict Test\"):\n        image = image.to(device)\n\n        logits = model(image)\n        prob = torch.sigmoid(logits)[0, 0].cpu().numpy()\n\n        original_h = int(original_h.item())\n        original_w = int(original_w.item())\n\n        prob_resized = resize(\n            prob,\n            (original_h, original_w),\n            mode=\"constant\",\n            preserve_range=True,\n            anti_aliasing=False\n        )\n\n        binary_mask = (prob_resized > THRESHOLD).astype(np.uint8)\n\n        rles = mask_to_rles(binary_mask)\n\n        image_id = image_id[0]\n\n        if len(rles) == 0:\n            submission_rows.append({\n                \"ImageId\": image_id,\n                \"EncodedPixels\": \"\"\n            })\n        else:\n            for rle in rles:\n                submission_rows.append({\n                    \"ImageId\": image_id,\n                    \"EncodedPixels\": rle\n                })\n\nsubmission = pd.DataFrame(submission_rows)\ndisplay(submission.head())\n\nsubmission.to_csv(\"/kaggle/working/submission.csv\", index=False)\nprint(\"saved: /kaggle/working/submission.csv\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T07:06:55.334629Z","iopub.execute_input":"2026-05-14T07:06:55.335410Z","iopub.status.idle":"2026-05-14T07:06:59.210875Z","shell.execute_reply.started":"2026-05-14T07:06:55.335379Z","shell.execute_reply":"2026-05-14T07:06:59.210017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def show_test_predictions(model, test_dataset, count=3, threshold=0.5):\n    model.eval()\n\n    plt.figure(figsize=(12, count * 4))\n\n    with torch.no_grad():\n        for i in range(count):\n            image, image_id, original_h, original_w = test_dataset[i]\n\n            input_tensor = image.unsqueeze(0).to(device)\n\n            logits = model(input_tensor)\n            prob = torch.sigmoid(logits)[0, 0].cpu().numpy()\n\n            pred_mask = (prob > threshold).astype(np.uint8)\n\n            img_np = image.permute(1, 2, 0).cpu().numpy()\n            img_np = np.clip(img_np, 0, 1)\n\n            plt.subplot(count, 3, i * 3 + 1)\n            plt.imshow(img_np)\n            plt.title(f\"Test Image\\n{image_id[:10]}\")\n            plt.axis(\"off\")\n\n            plt.subplot(count, 3, i * 3 + 2)\n            plt.imshow(pred_mask, cmap=\"gray\")\n            plt.title(\"Predicted Mask\")\n            plt.axis(\"off\")\n\n            plt.subplot(count, 3, i * 3 + 3)\n            plt.imshow(img_np)\n            plt.imshow(pred_mask, cmap=\"jet\", alpha=0.4)\n            plt.title(\"Overlay\")\n            plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\n\nshow_test_predictions(model, test_ds, count=10, threshold=THRESHOLD)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-14T07:09:49.139511Z","iopub.execute_input":"2026-05-14T07:09:49.140162Z","iopub.status.idle":"2026-05-14T07:09:52.871517Z","shell.execute_reply.started":"2026-05-14T07:09:49.140129Z","shell.execute_reply":"2026-05-14T07:09:52.870513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}