{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":6927,"databundleVersionId":45059,"sourceType":"competition"}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Import packadges\nimport os\nimport numpy as np\nimport pandas as pd\nimport zipfile\nfrom glob import glob\nfrom os.path import basename, splitext\nimport shutil\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport cv2\nfrom PIL import Image\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import confusion_matrix, classification_report\n\nfrom torchvision import models\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:06:00.266221Z","iopub.execute_input":"2025-08-13T06:06:00.266587Z","iopub.status.idle":"2025-08-13T06:06:00.273186Z","shell.execute_reply.started":"2025-08-13T06:06:00.266564Z","shell.execute_reply":"2025-08-13T06:06:00.272183Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Metadata Exploration**","metadata":{}},{"cell_type":"code","source":"# Read metadata\nzip_meta_path = '/kaggle/input/carvana-image-masking-challenge/metadata.csv.zip'\n\nwith zipfile.ZipFile(zip_meta_path, 'r') as zip_ref:\n    csv_name = zip_ref.namelist()[0]\n    with zip_ref.open(csv_name) as csv_file:\n        metadata_df = pd.read_csv(csv_file)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.056944Z","iopub.execute_input":"2025-08-13T05:13:55.057530Z","iopub.status.idle":"2025-08-13T05:13:55.110390Z","shell.execute_reply.started":"2025-08-13T05:13:55.057493Z","shell.execute_reply":"2025-08-13T05:13:55.109525Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(metadata_df.head())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.111329Z","iopub.execute_input":"2025-08-13T05:13:55.111661Z","iopub.status.idle":"2025-08-13T05:13:55.129329Z","shell.execute_reply.started":"2025-08-13T05:13:55.111640Z","shell.execute_reply":"2025-08-13T05:13:55.128399Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"**Information about the features**\n\n1. id --> unique identifier for each car\n2. year --> year of manufacture of the car\n3. make --> name of company (brand) of the car\n4. model --> model of the car\n5. trim1 --> the basic version of the model\n6. trim2 --> additional details about the preparation of the model","metadata":{}},{"cell_type":"code","source":"print(metadata_df.info())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.131312Z","iopub.execute_input":"2025-08-13T05:13:55.131687Z","iopub.status.idle":"2025-08-13T05:13:55.158796Z","shell.execute_reply.started":"2025-08-13T05:13:55.131661Z","shell.execute_reply":"2025-08-13T05:13:55.157792Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> All features are sublective 'object' dtype, only 1 feature is numeric 'float' : year column\n\n> There are some null values","metadata":{}},{"cell_type":"code","source":"duplicates = metadata_df[metadata_df.duplicated()]\n\nprint(\"Duplicate rows:\")\nprint(duplicates)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.159736Z","iopub.execute_input":"2025-08-13T05:13:55.160013Z","iopub.status.idle":"2025-08-13T05:13:55.184556Z","shell.execute_reply.started":"2025-08-13T05:13:55.159992Z","shell.execute_reply":"2025-08-13T05:13:55.183775Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> There are no duplicated rows","metadata":{}},{"cell_type":"code","source":"null_rows = metadata_df[metadata_df.isnull().any(axis=1)]\n\nprint(\"Rows with null values:\")\nprint(null_rows)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.185731Z","iopub.execute_input":"2025-08-13T05:13:55.186090Z","iopub.status.idle":"2025-08-13T05:13:55.201689Z","shell.execute_reply.started":"2025-08-13T05:13:55.186056Z","shell.execute_reply":"2025-08-13T05:13:55.200551Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> There are 87 rows that have null values in the different features","metadata":{}},{"cell_type":"code","source":"all_null_rows = metadata_df[metadata_df.isnull().all(axis=1)]\nprint(all_null_rows)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.202629Z","iopub.execute_input":"2025-08-13T05:13:55.202953Z","iopub.status.idle":"2025-08-13T05:13:55.220996Z","shell.execute_reply.started":"2025-08-13T05:13:55.202928Z","shell.execute_reply":"2025-08-13T05:13:55.220160Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> There aren't any rows that have all values null","metadata":{}},{"cell_type":"code","source":"# Dealing with nulls: fill numeric nulls with median and text nulls with 'Unknown'\nmetadata_df['year'].fillna(metadata_df['year'].median(), inplace=True)\nmetadata_df[['make', 'model', 'trim1', 'trim2']] = \\\n    metadata_df[['make', 'model', 'trim1', 'trim2']].fillna('Unknown')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.221932Z","iopub.execute_input":"2025-08-13T05:13:55.222302Z","iopub.status.idle":"2025-08-13T05:13:55.239872Z","shell.execute_reply.started":"2025-08-13T05:13:55.222265Z","shell.execute_reply":"2025-08-13T05:13:55.238907Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for col in metadata_df.columns:\n    if col != 'id':\n        print(f\"{col}: {metadata_df[col].unique()}\")\n        print(\"-\" * 40)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.240780Z","iopub.execute_input":"2025-08-13T05:13:55.241218Z","iopub.status.idle":"2025-08-13T05:13:55.254396Z","shell.execute_reply.started":"2025-08-13T05:13:55.241193Z","shell.execute_reply":"2025-08-13T05:13:55.253468Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(10, 5))\nsns.countplot(data=metadata_df, x='year')\n\nplt.title('Count of Records by Year')\nplt.xticks(rotation=45)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.257516Z","iopub.execute_input":"2025-08-13T05:13:55.257766Z","iopub.status.idle":"2025-08-13T05:13:55.583252Z","shell.execute_reply.started":"2025-08-13T05:13:55.257748Z","shell.execute_reply":"2025-08-13T05:13:55.582289Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"> Most cars samples from 2012 to 2016 ","metadata":{}},{"cell_type":"code","source":"# Top 3 company cars samples from 2012 to 2016\n\nmetadata_df['year'] = metadata_df['year'].astype(int)\n\nfiltered_df = metadata_df[(metadata_df['year'] >= 2012) & (metadata_df['year'] <= 2016)]\n\ntop_3_makes = filtered_df['make'].value_counts().head(3).index\n\nfiltered_df = filtered_df[filtered_df['make'].isin(top_3_makes)]\n\ncounts = filtered_df.groupby(['year', 'make']).size().reset_index(name='count')\n\nplt.figure(figsize=(10, 6))\nsns.lineplot(data=counts, x='year', y='count', hue='make', marker='o')\n\nplt.title('Top 3 Cars Companies (2012–2016)')\nplt.xticks(range(2012, 2017))\nplt.ylabel('Count')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.584257Z","iopub.execute_input":"2025-08-13T05:13:55.584650Z","iopub.status.idle":"2025-08-13T05:13:55.947269Z","shell.execute_reply.started":"2025-08-13T05:13:55.584626Z","shell.execute_reply":"2025-08-13T05:13:55.946259Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Get top 5 models for each make\ntop_models_per_make = (\n    filtered_df.groupby('make')['model']\n    .value_counts()\n    .groupby(level=0)\n    .head(5)\n    .reset_index(name='count')\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.948401Z","iopub.execute_input":"2025-08-13T05:13:55.948717Z","iopub.status.idle":"2025-08-13T05:13:55.963191Z","shell.execute_reply.started":"2025-08-13T05:13:55.948695Z","shell.execute_reply":"2025-08-13T05:13:55.962105Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Plot top 5 models for each make\n\nplt.figure(figsize=(12, 6))\nsns.barplot(data=top_models_per_make, x='model', y='count', hue='make')\n\nplt.title('Top 5 Models for Top 3 Makes')\nplt.xticks(rotation=45)\nplt.ylabel('Count')\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:55.964307Z","iopub.execute_input":"2025-08-13T05:13:55.964709Z","iopub.status.idle":"2025-08-13T05:13:56.530381Z","shell.execute_reply.started":"2025-08-13T05:13:55.964678Z","shell.execute_reply":"2025-08-13T05:13:56.529396Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Deal with Images**","metadata":{}},{"cell_type":"code","source":"train_zip = '/kaggle/input/carvana-image-masking-challenge/train.zip'\ntest_zip = '/kaggle/input/carvana-image-masking-challenge/test.zip'\nmask_zip = '/kaggle/input/carvana-image-masking-challenge/train_masks.zip'","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:56.531561Z","iopub.execute_input":"2025-08-13T05:13:56.531902Z","iopub.status.idle":"2025-08-13T05:13:56.536393Z","shell.execute_reply.started":"2025-08-13T05:13:56.531872Z","shell.execute_reply":"2025-08-13T05:13:56.535607Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Unzip to clean folders \ndef unzip_to_folder(zip_path, out_dir):\n    os.makedirs(out_dir, exist_ok=True)\n    with zipfile.ZipFile(zip_path, 'r') as zip_ref:\n        zip_ref.extractall(out_dir)\n\ntrain_zip = '/kaggle/input/carvana-image-masking-challenge/train.zip'\ntest_zip = '/kaggle/input/carvana-image-masking-challenge/test.zip'\nmask_zip = '/kaggle/input/carvana-image-masking-challenge/train_masks.zip'\n\nunzip_to_folder(train_zip, \"train\")\nunzip_to_folder(mask_zip, \"train_masks\")\nunzip_to_folder(test_zip, \"test\")\n\n# Load all file paths \ntrain_images = sorted(glob(\"train/**/*.*\", recursive=True))\nmask_images = sorted(glob(\"train_masks/**/*.*\", recursive=True))\n\n# Create a matching function \ndef normalize_name(path):\n    \"\"\"\n    Extracts the base name without extension and removes any '_mask' suffix.\n    \"\"\"\n    name = splitext(basename(path))[0]\n    name = name.replace(\"_mask\", \"\")  # remove '_mask' if exists\n    return name\n\n# Build DataFrame for train images \ndf = pd.DataFrame({\n    \"image_path\": train_images\n})\ndf[\"key_id\"] = df[\"image_path\"].apply(normalize_name)\n\n# Build a lookup dict for masks \nmask_lookup = {normalize_name(p): p for p in mask_images}\n\n# Match images to masks \ndf[\"mask_path\"] = df[\"key_id\"].map(mask_lookup)\n\n# Check results \nmissing_masks = df[df[\"mask_path\"].isnull()]\nif not missing_masks.empty:\n    print(f\"⚠ Warning: {len(missing_masks)} images do not have a matching mask!\")\n    print(missing_masks.head())\n\nprint(f\"✅ Total images: {len(df)}, Matched masks: {df['mask_path'].notnull().sum()}\")\nprint(df.sample(5))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:13:56.537252Z","iopub.execute_input":"2025-08-13T05:13:56.538304Z","iopub.status.idle":"2025-08-13T05:16:53.122598Z","shell.execute_reply.started":"2025-08-13T05:13:56.538269Z","shell.execute_reply":"2025-08-13T05:16:53.121697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Display 3 images and their masks\ndef visualize_samples(df, n=3):\n    samples = df.sample(n)\n    plt.figure(figsize=(10, n * 3))\n\n    for i, (_, row) in enumerate(samples.iterrows()):\n        img = cv2.imread(row['image_path'])\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\n        mask = Image.open(row['mask_path'])\n        mask = np.array(mask)\n\n        plt.subplot(n, 2, 2*i + 1)\n        plt.imshow(img)\n        plt.title(\"Image\")\n        plt.axis(\"off\")\n\n        plt.subplot(n, 2, 2*i + 2)\n        plt.imshow(mask, cmap='gray')\n        plt.title(\"Mask\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\nvisualize_samples(df, n=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:53.123545Z","iopub.execute_input":"2025-08-13T05:16:53.123832Z","iopub.status.idle":"2025-08-13T05:16:55.060083Z","shell.execute_reply.started":"2025-08-13T05:16:53.123810Z","shell.execute_reply":"2025-08-13T05:16:55.059208Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Count images in each file\ntrain_dir = \"train/train\"\nmask_dir = \"train_masks/train_masks\"\ntest_dir = \"test/test\"\n\n# List files\ntrain_images = sorted(os.listdir(train_dir))\ntrain_masks = sorted(os.listdir(mask_dir))\ntest_images = sorted(os.listdir(test_dir))\n\n# Counts\nprint(f\"Train images: {len(train_images)}\")\nprint(f\"Train masks:  {len(train_masks)}\")\nprint(f\"Test images:  {len(test_images)}\")\n\n# Check matching\ntrain_keys = [os.path.splitext(img)[0] for img in train_images]\nmask_keys = [os.path.splitext(mask)[0].replace(\"_mask\", \"\") for mask in train_masks]\n\nif set(train_keys) == set(mask_keys):\n    print(\"✅ All train images have matching masks.\")\nelse:\n    missing_masks = set(train_keys) - set(mask_keys)\n    missing_images = set(mask_keys) - set(train_keys)\n    if missing_masks:\n        print(f\"Missing masks for: {missing_masks}\")\n    if missing_images:\n        print(f\"Missing train images for: {missing_images}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:55.061176Z","iopub.execute_input":"2025-08-13T05:16:55.061506Z","iopub.status.idle":"2025-08-13T05:16:55.197431Z","shell.execute_reply.started":"2025-08-13T05:16:55.061480Z","shell.execute_reply":"2025-08-13T05:16:55.196451Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(df.columns)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:55.198454Z","iopub.execute_input":"2025-08-13T05:16:55.198712Z","iopub.status.idle":"2025-08-13T05:16:55.203992Z","shell.execute_reply.started":"2025-08-13T05:16:55.198693Z","shell.execute_reply":"2025-08-13T05:16:55.202831Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_DIR = '/kaggle/working/'\nTRAIN_IMG_DIR = os.path.join(DATA_DIR, 'train/train')\nTRAIN_MASK_DIR = os.path.join(DATA_DIR, 'train_masks/train_masks')\n\ntrain_images = sorted(glob(os.path.join(TRAIN_IMG_DIR, '*.jpg')) + \n                      glob(os.path.join(TRAIN_IMG_DIR, '*.png')))\n\ntrain_masks = sorted(glob(os.path.join(TRAIN_MASK_DIR, '*.gif')))\n\nprint(f\"num of images: {len(train_images)}\")\nprint(f\"num of masks: {len(train_masks)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:55.204867Z","iopub.execute_input":"2025-08-13T05:16:55.205197Z","iopub.status.idle":"2025-08-13T05:16:55.250378Z","shell.execute_reply.started":"2025-08-13T05:16:55.205174Z","shell.execute_reply":"2025-08-13T05:16:55.249509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img = cv2.imread(train_images[0])\nimg = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n\nmask_gif = Image.open(train_masks[0])\nmask_gif = mask_gif.convert(\"L\")  \nmask = cv2.resize(np.array(mask_gif), (img.shape[1], img.shape[0]))\n\nplt.figure(figsize=(8,4))\nplt.subplot(1,2,1)\nplt.imshow(img)\nplt.title(\"Image\")\nplt.axis(False)\n\nplt.subplot(1,2,2)\nplt.imshow(mask, cmap='gray')\nplt.title(\"Mask\")\nplt.axis(False)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:55.251189Z","iopub.execute_input":"2025-08-13T05:16:55.251471Z","iopub.status.idle":"2025-08-13T05:16:55.964468Z","shell.execute_reply.started":"2025-08-13T05:16:55.251450Z","shell.execute_reply":"2025-08-13T05:16:55.963578Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **1st model: Simple Unet model**","metadata":{}},{"cell_type":"code","source":"DATA_DIR = '/kaggle/working/'\nTRAIN_IMG_DIR = os.path.join(DATA_DIR, 'train/train')\nTRAIN_MASK_DIR = os.path.join(DATA_DIR, 'train_masks/train_masks')\n\nimg_paths = sorted(glob(os.path.join(TRAIN_IMG_DIR, '*.jpg')) +\n                   glob(os.path.join(TRAIN_IMG_DIR, '*.png')))\nmask_paths = sorted(glob(os.path.join(TRAIN_MASK_DIR, '*.gif')))\n\nprint(f\"num images: {len(img_paths)}, num masks: {len(mask_paths)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:55.965438Z","iopub.execute_input":"2025-08-13T05:16:55.965685Z","iopub.status.idle":"2025-08-13T05:16:56.003612Z","shell.execute_reply.started":"2025-08-13T05:16:55.965666Z","shell.execute_reply":"2025-08-13T05:16:56.002692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# hyperparams\nIMG_SIZE = (128, 128)     \nBATCH_SIZE = 2             \nNUM_EPOCHS = 10\nLR = 1e-3\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.004594Z","iopub.execute_input":"2025-08-13T05:16:56.004918Z","iopub.status.idle":"2025-08-13T05:16:56.091731Z","shell.execute_reply.started":"2025-08-13T05:16:56.004896Z","shell.execute_reply":"2025-08-13T05:16:56.090710Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegmentationDataset(Dataset):\n    def __init__(self, image_paths, mask_paths, img_size=(128,128)):\n        self.image_paths = image_paths\n        self.mask_paths = mask_paths\n        self.img_size = img_size\n        self.to_tensor = transforms.ToTensor()\n\n    def __len__(self):\n        return len(self.image_paths)\n\n    def __getitem__(self, idx):\n        img = cv2.imread(self.image_paths[idx])\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = cv2.resize(img, self.img_size)\n\n        mask_gif = Image.open(self.mask_paths[idx]).convert(\"L\")\n        mask = np.array(mask_gif)\n        mask = cv2.resize(mask, self.img_size, interpolation=cv2.INTER_NEAREST)\n        mask = (mask > 127).astype(np.uint8)\n\n        img_t = self.to_tensor(img)\n        mask_t = torch.from_numpy(mask).unsqueeze(0).float()\n        return img_t, mask_t","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.092972Z","iopub.execute_input":"2025-08-13T05:16:56.093202Z","iopub.status.idle":"2025-08-13T05:16:56.103588Z","shell.execute_reply.started":"2025-08-13T05:16:56.093183Z","shell.execute_reply":"2025-08-13T05:16:56.102527Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# U-Net model \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, 3, padding=1, bias=False),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_ch, out_ch, 3, padding=1, bias=False),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n        )\n    def forward(self, x):\n        return self.net(x)\n\nclass UNet(nn.Module):\n    def __init__(self, in_channels=3, out_channels=1, features=[32,64,128]):\n        super().__init__()\n        self.downs = nn.ModuleList()\n        self.ups = nn.ModuleList()\n        self.pool = nn.MaxPool2d(2)\n\n        # Encoder\n        ch = in_channels\n        for f in features:\n            self.downs.append(DoubleConv(ch, f))\n            ch = f\n\n        self.bottleneck = DoubleConv(features[-1], features[-1]*2)\n\n        # Decoder\n        rev_f = features[::-1]\n        for f in rev_f:\n            self.ups.append(nn.ConvTranspose2d(f*2 if f!=rev_f[0] else features[-1]*2, f, 2, stride=2))\n            self.ups.append(DoubleConv(f*2, f))\n\n        self.final_conv = nn.Conv2d(features[0], out_channels, 1)\n\n    def forward(self, x):\n        skips = []\n        for down in self.downs:\n            x = down(x)\n            skips.append(x)\n            x = self.pool(x)\n\n        x = self.bottleneck(x)\n        skips = skips[::-1]\n\n        for i in range(0, len(self.ups), 2):\n            x = self.ups[i](x)\n            skip = skips[i//2]\n            if x.shape != skip.shape:\n                x = torch.nn.functional.interpolate(x, size=skip.shape[2:])\n            x = torch.cat([skip, x], dim=1)\n            x = self.ups[i+1](x)\n\n        return self.final_conv(x)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.104635Z","iopub.execute_input":"2025-08-13T05:16:56.105530Z","iopub.status.idle":"2025-08-13T05:16:56.123530Z","shell.execute_reply.started":"2025-08-13T05:16:56.105504Z","shell.execute_reply":"2025-08-13T05:16:56.122597Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dice_loss(pred, target, smooth=1e-6):\n    pred = torch.sigmoid(pred)\n    pred_flat = pred.view(pred.size(0), -1)\n    target_flat = target.view(target.size(0), -1)\n    intersection = (pred_flat * target_flat).sum(1)\n    return 1 - ((2.*intersection + smooth) / (pred_flat.sum(1) + target_flat.sum(1) + smooth)).mean()\n\ndef iou_score(pred, target, thr=0.5, eps=1e-6):\n    pred = torch.sigmoid(pred)\n    pred = (pred > thr).float()\n    intersect = (pred * target).sum((1,2,3))\n    union = ((pred + target) > 0).float().sum((1,2,3))\n    return ((intersect + eps) / (union + eps)).mean().item()\n\nbce = nn.BCEWithLogitsLoss()\ndef combined_loss(pred, target, alpha=0.5):\n    return alpha*bce(pred, target) + (1-alpha)*dice_loss(pred, target)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.124936Z","iopub.execute_input":"2025-08-13T05:16:56.125260Z","iopub.status.idle":"2025-08-13T05:16:56.142740Z","shell.execute_reply.started":"2025-08-13T05:16:56.125225Z","shell.execute_reply":"2025-08-13T05:16:56.141697Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Train test split\nIMG_SIZE = (128,128)\nBATCH_SIZE = 2\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ntrain_imgs, val_imgs, train_masks_p, val_masks_p = train_test_split(\n    img_paths, mask_paths, test_size=0.15, random_state=42)\n\ntrain_loader = DataLoader(SegmentationDataset(train_imgs, train_masks_p, IMG_SIZE), batch_size=BATCH_SIZE, shuffle=True, num_workers=0, pin_memory=False)\nval_loader = DataLoader(SegmentationDataset(val_imgs, val_masks_p, IMG_SIZE), batch_size=BATCH_SIZE, shuffle=False, num_workers=0, pin_memory=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.143957Z","iopub.execute_input":"2025-08-13T05:16:56.144491Z","iopub.status.idle":"2025-08-13T05:16:56.165332Z","shell.execute_reply.started":"2025-08-13T05:16:56.144451Z","shell.execute_reply":"2025-08-13T05:16:56.164211Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = UNet().to(DEVICE)\noptimizer = torch.optim.Adam(model.parameters(), lr=1e-3)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=0.5, patience=3, verbose=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.166523Z","iopub.execute_input":"2025-08-13T05:16:56.166866Z","iopub.status.idle":"2025-08-13T05:16:56.433810Z","shell.execute_reply.started":"2025-08-13T05:16:56.166832Z","shell.execute_reply":"2025-08-13T05:16:56.432870Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Training\ntrain_losses, val_losses, val_ious = [], [], []\nNUM_EPOCHS = 15  \n\nfor epoch in range(1, NUM_EPOCHS+1):\n    model.train()\n    running_loss = 0.0\n    for imgs, masks in train_loader:\n        imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n        preds = model(imgs)\n        loss = combined_loss(preds, masks, alpha=0.5)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item() * imgs.size(0)\n\n    epoch_loss = running_loss / len(train_loader.dataset)\n\n    # Validation\n    model.eval()\n    val_loss, ious = 0.0, []\n    with torch.no_grad():\n        for imgs, masks in val_loader:\n            imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n            preds = model(imgs)\n            loss = combined_loss(preds, masks, alpha=0.5)\n            val_loss += loss.item() * imgs.size(0)\n            ious.append(iou_score(preds, masks))\n    val_loss /= len(val_loader.dataset)\n    mean_iou = np.mean(ious)\n\n    train_losses.append(epoch_loss)\n    val_losses.append(val_loss)\n    val_ious.append(mean_iou)\n\n    scheduler.step(val_loss)\n\n    print(f\"Epoch [{epoch}/{NUM_EPOCHS}] Train Loss: {epoch_loss:.4f} | Val Loss: {val_loss:.4f} | Val IoU: {mean_iou:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T05:16:56.437460Z","iopub.execute_input":"2025-08-13T05:16:56.437732Z","iopub.status.idle":"2025-08-13T06:00:50.817121Z","shell.execute_reply.started":"2025-08-13T05:16:56.437713Z","shell.execute_reply":"2025-08-13T06:00:50.815800Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Loss & Val IoU\nplt.figure(figsize=(12,5))\nplt.subplot(1,2,1)\nplt.plot(train_losses, label='Train Loss')\nplt.plot(val_losses, label='Val Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\nplt.title('Loss over Epochs')\n\nplt.subplot(1,2,2)\nplt.plot(val_ious, label='Val IoU', color='green')\nplt.xlabel('Epoch')\nplt.ylabel('IoU')\nplt.legend()\nplt.title('IoU over Epochs')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:00:50.818825Z","iopub.execute_input":"2025-08-13T06:00:50.819217Z","iopub.status.idle":"2025-08-13T06:00:51.272828Z","shell.execute_reply.started":"2025-08-13T06:00:50.819181Z","shell.execute_reply":"2025-08-13T06:00:51.271866Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Classification Report & Confusion Matrix\nall_preds, all_targets = [], []\nmodel.eval()\nwith torch.no_grad():\n    for imgs, masks in val_loader:\n        imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n        preds = model(imgs)\n        preds = torch.sigmoid(preds)\n        preds = (preds > 0.5).float()\n        all_preds.append(preds.cpu().numpy())\n        all_targets.append(masks.cpu().numpy())\n\nall_preds = np.concatenate(all_preds).reshape(-1)\nall_targets = np.concatenate(all_targets).reshape(-1)\n\ncm = confusion_matrix(all_targets, all_preds)\nprint(\"\\nClassification Report:\\n\", classification_report(all_targets, all_preds, digits=4))\n\nplt.figure(figsize=(5,4))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\",\n            xticklabels=[\"Background (0)\", \"Object (1)\"],\n            yticklabels=[\"Background (0)\", \"Object (1)\"])\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\nplt.title(\"Confusion Matrix\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:00:51.273926Z","iopub.execute_input":"2025-08-13T06:00:51.274624Z","iopub.status.idle":"2025-08-13T06:02:28.133670Z","shell.execute_reply.started":"2025-08-13T06:00:51.274589Z","shell.execute_reply":"2025-08-13T06:02:28.132958Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prediction & Visualization\ndef predict_and_visualize(model, dataset, num_samples=3):\n    model.eval()\n    plt.figure(figsize=(12, num_samples*4))\n    for i in range(num_samples):\n        img, mask = dataset[i]\n        img_input = img.unsqueeze(0).to(DEVICE)\n\n        with torch.no_grad():\n            pred = model(img_input)\n            pred = torch.sigmoid(pred)\n            pred = (pred > 0.5).float()\n\n        img_np = img.permute(1, 2, 0).numpy()\n        mask_np = mask.squeeze().numpy()\n        pred_np = pred.squeeze().cpu().numpy()\n\n        plt.subplot(num_samples, 3, i*3 + 1)\n        plt.imshow(img_np)\n        plt.title(\"Original Image\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 2)\n        plt.imshow(mask_np, cmap=\"gray\")\n        plt.title(\"Ground Truth\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 3)\n        plt.imshow(pred_np, cmap=\"gray\")\n        plt.title(\"Predicted Mask\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\npredict_and_visualize(model, SegmentationDataset(val_imgs, val_masks_p, IMG_SIZE), num_samples=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:02:28.134617Z","iopub.execute_input":"2025-08-13T06:02:28.134888Z","iopub.status.idle":"2025-08-13T06:02:29.253919Z","shell.execute_reply.started":"2025-08-13T06:02:28.134869Z","shell.execute_reply":"2025-08-13T06:02:29.252795Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def apply_colormap(mask, color=(255, 0, 0)):\n    mask_rgb = np.zeros((mask.shape[0], mask.shape[1], 3), dtype=np.uint8)\n    mask_rgb[mask == 1] = color\n    return mask_rgb\n\ndef overlay_mask(image, mask_rgb, alpha=0.5):\n    overlay = image.copy()\n    overlay = (overlay * (1 - alpha) + mask_rgb * alpha).astype(np.uint8)\n    return overlay\n\ndef predict_and_visualize(model, dataset, num_samples=3):\n    model.eval()\n    plt.figure(figsize=(12, num_samples * 4))\n\n    for i in range(num_samples):\n        img, mask = dataset[i]\n        img_input = img.unsqueeze(0).to(DEVICE)\n\n        with torch.no_grad():\n            pred = model(img_input)\n            pred = torch.sigmoid(pred)\n            pred = (pred > 0.5).float()\n\n        img_np = (img.permute(1, 2, 0).numpy() * 255).astype(np.uint8)\n        mask_np = mask.squeeze().numpy().astype(np.uint8)\n        pred_np = pred.squeeze().cpu().numpy().astype(np.uint8)\n\n        mask_color = apply_colormap(mask_np, color=(0, 255, 0))\n        pred_color = apply_colormap(pred_np, color=(255, 0, 0))  \n\n        img_mask_gt = overlay_mask(img_np, mask_color, alpha=0.4)\n        img_mask_pred = overlay_mask(img_np, pred_color, alpha=0.4)\n\n        plt.subplot(num_samples, 3, i*3 + 1)\n        plt.imshow(img_np)\n        plt.title(\"Original Image\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 2)\n        plt.imshow(img_mask_gt)\n        plt.title(\"Ground Truth Mask (Green)\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 3)\n        plt.imshow(img_mask_pred)\n        plt.title(\"Predicted Mask (Red)\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\npredict_and_visualize(model, SegmentationDataset(val_imgs, val_masks_p, IMG_SIZE), num_samples=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:02:29.255045Z","iopub.execute_input":"2025-08-13T06:02:29.255711Z","iopub.status.idle":"2025-08-13T06:02:30.447813Z","shell.execute_reply.started":"2025-08-13T06:02:29.255676Z","shell.execute_reply":"2025-08-13T06:02:30.446703Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **2nd model: Unet Model + Resnet-50 Model**","metadata":{}},{"cell_type":"code","source":"DATA_DIR = '/kaggle/working/'\nTRAIN_IMG_DIR = os.path.join(DATA_DIR, 'train/train')\nTRAIN_MASK_DIR = os.path.join(DATA_DIR, 'train_masks/train_masks')\n\nimg_paths = sorted(glob(os.path.join(TRAIN_IMG_DIR, '*.jpg')) +\n                   glob(os.path.join(TRAIN_IMG_DIR, '*.png')))\nmask_paths = sorted(glob(os.path.join(TRAIN_MASK_DIR, '*.gif')))\n\nprint(f\"num images: {len(img_paths)}, num masks: {len(mask_paths)}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:13.316828Z","iopub.execute_input":"2025-08-13T06:18:13.317119Z","iopub.status.idle":"2025-08-13T06:18:13.355459Z","shell.execute_reply.started":"2025-08-13T06:18:13.317100Z","shell.execute_reply":"2025-08-13T06:18:13.354717Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class SegmentationDataset(Dataset):\n    def __init__(self, image_paths, mask_paths, img_size=(128,128)):\n        self.image_paths = image_paths\n        self.mask_paths = mask_paths\n        self.img_size = img_size\n        self.to_tensor = transforms.ToTensor()\n\n    def __len__(self):\n        return len(self.image_paths)\n\n    def __getitem__(self, idx):\n        img = cv2.imread(self.image_paths[idx])\n        img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n        img = cv2.resize(img, self.img_size)\n\n        mask_gif = Image.open(self.mask_paths[idx]).convert(\"L\")\n        mask = np.array(mask_gif)\n        mask = cv2.resize(mask, self.img_size, interpolation=cv2.INTER_NEAREST)\n        mask = (mask > 127).astype(np.uint8)\n\n        img_t = self.to_tensor(img)\n        mask_t = torch.from_numpy(mask).unsqueeze(0).float()\n        return img_t, mask_t","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:14.044898Z","iopub.execute_input":"2025-08-13T06:18:14.045192Z","iopub.status.idle":"2025-08-13T06:18:14.052007Z","shell.execute_reply.started":"2025-08-13T06:18:14.045173Z","shell.execute_reply":"2025-08-13T06:18:14.051181Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class UNetResNet50(nn.Module):\n    def __init__(self, num_classes=1, pretrained=True):\n        super().__init__()\n        backbone = models.resnet50(pretrained=pretrained)\n        self.enc1 = nn.Sequential(backbone.conv1, backbone.bn1, backbone.relu)  # 64\n        self.enc2 = nn.Sequential(backbone.maxpool, backbone.layer1)  # 256\n        self.enc3 = backbone.layer2  # 512\n        self.enc4 = backbone.layer3  # 1024\n        self.enc5 = backbone.layer4  # 2048\n\n        self.up4 = self._up_block(2048, 1024)\n        self.dec4 = self._conv_block(2048, 1024)\n\n        self.up3 = self._up_block(1024, 512)\n        self.dec3 = self._conv_block(1024, 512)\n\n        self.up2 = self._up_block(512, 256)\n        self.dec2 = self._conv_block(512, 256)\n\n        self.up1 = self._up_block(256, 64)\n        self.dec1 = self._conv_block(128, 64)\n\n        self.final_conv = nn.Conv2d(64, num_classes, kernel_size=1)\n\n    def _conv_block(self, in_ch, out_ch):\n        return nn.Sequential(\n            nn.Conv2d(in_ch, out_ch, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True),\n            nn.Conv2d(out_ch, out_ch, kernel_size=3, padding=1, bias=False),\n            nn.BatchNorm2d(out_ch),\n            nn.ReLU(inplace=True)\n        )\n\n    def _up_block(self, in_ch, out_ch):\n        return nn.ConvTranspose2d(in_ch, out_ch, kernel_size=2, stride=2)\n\n    def forward(self, x):\n        e1 = self.enc1(x)\n        e2 = self.enc2(e1)\n        e3 = self.enc3(e2)\n        e4 = self.enc4(e3)\n        e5 = self.enc5(e4)\n\n        d4 = self.up4(e5)\n        d4 = torch.cat([d4, e4], dim=1)\n        d4 = self.dec4(d4)\n\n        d3 = self.up3(d4)\n        d3 = torch.cat([d3, e3], dim=1)\n        d3 = self.dec3(d3)\n\n        d2 = self.up2(d3)\n        d2 = torch.cat([d2, e2], dim=1)\n        d2 = self.dec2(d2)\n\n        d1 = self.up1(d2)\n        d1 = torch.cat([d1, e1], dim=1)\n        d1 = self.dec1(d1)\n\n        out = self.final_conv(d1)\n        out = torch.nn.functional.interpolate(out, size=x.shape[2:], mode='bilinear', align_corners=False)\n        return out","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:15.873955Z","iopub.execute_input":"2025-08-13T06:18:15.874538Z","iopub.status.idle":"2025-08-13T06:18:15.886912Z","shell.execute_reply.started":"2025-08-13T06:18:15.874509Z","shell.execute_reply":"2025-08-13T06:18:15.885843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def dice_loss(pred, target, smooth=1e-6):\n    pred = torch.sigmoid(pred)\n    pred_flat = pred.view(pred.size(0), -1)\n    target_flat = target.view(target.size(0), -1)\n    intersection = (pred_flat * target_flat).sum(1)\n    return 1 - ((2.*intersection + smooth) / (pred_flat.sum(1) + target_flat.sum(1) + smooth)).mean()\n\nbce = nn.BCEWithLogitsLoss()\ndef combined_loss(pred, target, alpha=0.5):\n    return alpha*bce(pred, target) + (1-alpha)*dice_loss(pred, target)\n\ndef iou_score(pred, target, thr=0.5, eps=1e-6):\n    pred = torch.sigmoid(pred)\n    pred = (pred > thr).float()\n    intersect = (pred * target).sum((1,2,3))\n    union = ((pred + target) > 0).float().sum((1,2,3))\n    return ((intersect + eps) / (union + eps)).mean().item()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:18.601819Z","iopub.execute_input":"2025-08-13T06:18:18.602143Z","iopub.status.idle":"2025-08-13T06:18:18.610156Z","shell.execute_reply.started":"2025-08-13T06:18:18.602121Z","shell.execute_reply":"2025-08-13T06:18:18.608899Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"IMG_SIZE = (128,128)\nBATCH_SIZE = 2\nDEVICE = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ntrain_imgs, val_imgs, train_masks_p, val_masks_p = train_test_split(\n    img_paths, mask_paths, test_size=0.15, random_state=42)\n\ntrain_loader = DataLoader(SegmentationDataset(train_imgs, train_masks_p, IMG_SIZE), batch_size=BATCH_SIZE, shuffle=True)\nval_loader = DataLoader(SegmentationDataset(val_imgs, val_masks_p, IMG_SIZE), batch_size=BATCH_SIZE, shuffle=False)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:23.411769Z","iopub.execute_input":"2025-08-13T06:18:23.412084Z","iopub.status.idle":"2025-08-13T06:18:23.422764Z","shell.execute_reply.started":"2025-08-13T06:18:23.412062Z","shell.execute_reply":"2025-08-13T06:18:23.421682Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model1 = UNetResNet50(num_classes=1, pretrained=True).to(DEVICE)\noptimizer = torch.optim.Adam(model1.parameters(), lr=1e-3)\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, factor=0.5, patience=3, verbose=True)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:25.578171Z","iopub.execute_input":"2025-08-13T06:18:25.578653Z","iopub.status.idle":"2025-08-13T06:18:26.634087Z","shell.execute_reply.started":"2025-08-13T06:18:25.578620Z","shell.execute_reply":"2025-08-13T06:18:26.633052Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_losses, val_losses, val_ious = [], [], []\nNUM_EPOCHS = 5\n\nfor epoch in range(1, NUM_EPOCHS+1):\n    model1.train()\n    running_loss = 0.0\n    for imgs, masks in train_loader:\n        imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n        preds = model1(imgs)\n        loss = combined_loss(preds, masks)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item() * imgs.size(0)\n\n    epoch_loss = running_loss / len(train_loader.dataset)\n\n    model1.eval()\n    val_loss, ious = 0.0, []\n    with torch.no_grad():\n        for imgs, masks in val_loader:\n            imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n            preds = model1(imgs)\n            loss = combined_loss(preds, masks)\n            val_loss += loss.item() * imgs.size(0)\n            ious.append(iou_score(preds, masks))\n    val_loss /= len(val_loader.dataset)\n    mean_iou = np.mean(ious)\n\n    train_losses.append(epoch_loss)\n    val_losses.append(val_loss)\n    val_ious.append(mean_iou)\n\n    scheduler.step(val_loss)\n\n    print(f\"Epoch [{epoch}/{NUM_EPOCHS}] Train Loss: {epoch_loss:.4f} | Val Loss: {val_loss:.4f} | Val IoU: {mean_iou:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:18:28.394874Z","iopub.execute_input":"2025-08-13T06:18:28.395688Z","iopub.status.idle":"2025-08-13T06:41:55.721505Z","shell.execute_reply.started":"2025-08-13T06:18:28.395660Z","shell.execute_reply":"2025-08-13T06:41:55.720319Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Confusion Matrix & Classification Report\nall_preds, all_targets = [], []\nmodel1.eval()\nwith torch.no_grad():\n    for imgs, masks in val_loader:\n        imgs, masks = imgs.to(DEVICE), masks.to(DEVICE)\n        preds = model1(imgs)\n        preds = torch.sigmoid(preds)\n        preds = (preds > 0.5).float()\n        all_preds.append(preds.cpu().numpy())\n        all_targets.append(masks.cpu().numpy())\n\nall_preds = np.concatenate(all_preds).reshape(-1)\nall_targets = np.concatenate(all_targets).reshape(-1)\n\ncm = confusion_matrix(all_targets, all_preds)\nprint(\"\\nClassification Report:\\n\", classification_report(all_targets, all_preds, digits=4))\n\nplt.figure(figsize=(5,4))\nsns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\",\n            xticklabels=[\"Background (0)\", \"Object (1)\"],\n            yticklabels=[\"Background (0)\", \"Object (1)\"])\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\nplt.title(\"Confusion Matrix\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:42:20.474823Z","iopub.execute_input":"2025-08-13T06:42:20.475560Z","iopub.status.idle":"2025-08-13T06:44:04.409223Z","shell.execute_reply.started":"2025-08-13T06:42:20.475532Z","shell.execute_reply":"2025-08-13T06:44:04.408309Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Prediction & Visualization\ndef predict_and_visualize(model, dataset, num_samples=3):\n    model.eval()\n    plt.figure(figsize=(12, num_samples*4))\n    for i in range(num_samples):\n        img, mask = dataset[i]\n        img_input = img.unsqueeze(0).to(DEVICE)\n\n        with torch.no_grad():\n            pred = model(img_input)\n            pred = torch.sigmoid(pred)\n            pred = (pred > 0.5).float()\n\n        img_np = img.permute(1, 2, 0).numpy()\n        mask_np = mask.squeeze().numpy()\n        pred_np = pred.squeeze().cpu().numpy()\n\n        plt.subplot(num_samples, 3, i*3 + 1)\n        plt.imshow(img_np)\n        plt.title(\"Original Image\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 2)\n        plt.imshow(mask_np, cmap=\"gray\")\n        plt.title(\"Ground Truth\")\n        plt.axis(\"off\")\n\n        plt.subplot(num_samples, 3, i*3 + 3)\n        plt.imshow(pred_np, cmap=\"gray\")\n        plt.title(\"Predicted Mask\")\n        plt.axis(\"off\")\n\n    plt.tight_layout()\n    plt.show()\n\npredict_and_visualize(model1, SegmentationDataset(val_imgs, val_masks_p, IMG_SIZE), num_samples=3)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:44:43.748516Z","iopub.execute_input":"2025-08-13T06:44:43.748843Z","iopub.status.idle":"2025-08-13T06:44:44.955508Z","shell.execute_reply.started":"2025-08-13T06:44:43.748822Z","shell.execute_reply":"2025-08-13T06:44:44.954212Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Save Unet Model**","metadata":{}},{"cell_type":"code","source":"torch.save(model.state_dict(), \"model.pth\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-13T06:54:18.750529Z","iopub.execute_input":"2025-08-13T06:54:18.751133Z","iopub.status.idle":"2025-08-13T06:54:19.369617Z","shell.execute_reply.started":"2025-08-13T06:54:18.751112Z","shell.execute_reply":"2025-08-13T06:54:19.368674Z"}},"outputs":[],"execution_count":null}]}