{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.13.15","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[],"dockerImageVersionId":28755,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# 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\n\n# Use the kagglehub client library to attach Kaggle resources like competitions, datasets, and models to your session\n# Learn more about kagglehub: https://github.com/Kaggle/kagglehub/blob/main/README.md\n\nimport kagglehub\n# kagglehub.dataset_download('<owner>/<dataset-slug>')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"execution_failed":"2026-10-08T16:34:15.011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 1 — IMPORT LIBRARIES\n# ============================================\n\nimport os\nimport random\nimport zipfile\nimport time\nimport hashlib\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nimport tensorflow as tf\n\nfrom PIL import Image\n\nprint(\"TensorFlow Version:\", tf.__version__)\nprint(\"NumPy Version:\", np.__version__)\nprint(\"Pandas Version:\", pd.__version__)\n\nprint(\"\\nAvailable GPU:\")\nprint(tf.config.list_physical_devices('GPU'))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:14.541148Z","iopub.execute_input":"2026-10-08T16:35:14.541484Z","iopub.status.idle":"2026-10-08T16:35:14.548361Z","shell.execute_reply.started":"2026-10-08T16:35:14.541459Z","shell.execute_reply":"2026-10-08T16:35:14.547483Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 2 — FIX RANDOM SEED\n# ============================================\n\nSEED = 42\n\nos.environ[\"PYTHONHASHSEED\"] = str(SEED)\n\nrandom.seed(SEED)\nnp.random.seed(SEED)\ntf.random.set_seed(SEED)\n\nprint(\"Random seed fixed at:\", SEED)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:35.061322Z","iopub.execute_input":"2026-10-08T16:35:35.062151Z","iopub.status.idle":"2026-10-08T16:35:35.068932Z","shell.execute_reply.started":"2026-10-08T16:35:35.062123Z","shell.execute_reply":"2026-10-08T16:35:35.068258Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **2. Dataset Loading and Extraction**","metadata":{}},{"cell_type":"code","source":"# ============================================\n# CELL 3 — CHECK KAGGLE INPUT\n# ============================================\n\nKAGGLE_INPUT = \"/kaggle/input\"\n\nprint(\"Files/folders available in /kaggle/input:\\n\")\n\nfor item in os.listdir(KAGGLE_INPUT):\n    print(item)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:38.614393Z","iopub.execute_input":"2026-10-08T16:35:38.614852Z","iopub.status.idle":"2026-10-08T16:35:38.620813Z","shell.execute_reply.started":"2026-10-08T16:35:38.614822Z","shell.execute_reply":"2026-10-08T16:35:38.619821Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 4 — CHECK KAGGLE INPUT IN DETAIL\n# ============================================\n\nimport os\n\nprint(\"Number of items:\", len(os.listdir(\"/kaggle/input\")))\nprint(\"\\nItems:\")\n\nfor item in os.listdir(\"/kaggle/input\"):\n    print(repr(item))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:40.784286Z","iopub.execute_input":"2026-10-08T16:35:40.784916Z","iopub.status.idle":"2026-10-08T16:35:40.790714Z","shell.execute_reply.started":"2026-10-08T16:35:40.784886Z","shell.execute_reply":"2026-10-08T16:35:40.789912Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 5 — CHECK COMPETITION DATA\n# ============================================\n\nCOMPETITIONS_PATH = \"/kaggle/input/competitions\"\n\nprint(\"Contents of competitions folder:\\n\")\n\nfor item in os.listdir(COMPETITIONS_PATH):\n    print(item)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:44.296222Z","iopub.execute_input":"2026-10-08T16:35:44.29689Z","iopub.status.idle":"2026-10-08T16:35:44.302014Z","shell.execute_reply.started":"2026-10-08T16:35:44.296863Z","shell.execute_reply":"2026-10-08T16:35:44.300993Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 6 — CHECK COMPETITION FILES\n# ============================================\n\nCOMPETITION_PATH = \"/kaggle/input/competitions/dogs-vs-cats-redux-kernels-edition\"\n\nprint(\"Competition files/folders:\\n\")\n\nfor item in os.listdir(COMPETITION_PATH):\n    item_path = os.path.join(COMPETITION_PATH, item)\n\n    if os.path.isdir(item_path):\n        print(f\"[FOLDER] {item}\")\n    else:\n        print(f\"[FILE]   {item}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:46.702968Z","iopub.execute_input":"2026-10-08T16:35:46.703371Z","iopub.status.idle":"2026-10-08T16:35:46.71306Z","shell.execute_reply.started":"2026-10-08T16:35:46.703339Z","shell.execute_reply":"2026-10-08T16:35:46.712418Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 7 — EXTRACT TRAIN AND TEST DATA\n# ============================================\n\nWORK_PATH = \"/kaggle/working/dogs_cats\"\n\nos.makedirs(WORK_PATH, exist_ok=True)\n\ntrain_zip = os.path.join(COMPETITION_PATH, \"train.zip\")\ntest_zip = os.path.join(COMPETITION_PATH, \"test.zip\")\n\ntrain_extract = os.path.join(WORK_PATH, \"train\")\ntest_extract = os.path.join(WORK_PATH, \"test\")\n\nwith zipfile.ZipFile(train_zip, \"r\") as zip_ref:\n    zip_ref.extractall(train_extract)\n\nwith zipfile.ZipFile(test_zip, \"r\") as zip_ref:\n    zip_ref.extractall(test_extract)\n\nprint(\"Train dataset extracted successfully.\")\nprint(\"Test dataset extracted successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:35:47.380217Z","iopub.execute_input":"2026-10-08T16:35:47.380695Z","iopub.status.idle":"2026-10-08T16:35:58.939876Z","shell.execute_reply.started":"2026-10-08T16:35:47.380655Z","shell.execute_reply":"2026-10-08T16:35:58.938889Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 8 — CHECK EXTRACTED DATASET STRUCTURE\n# ============================================\n\nfor root, dirs, files in os.walk(WORK_PATH):\n    print(root, \"->\", len(files), \"files\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:11.191377Z","iopub.execute_input":"2026-10-08T16:36:11.191927Z","iopub.status.idle":"2026-10-08T16:36:11.225881Z","shell.execute_reply.started":"2026-10-08T16:36:11.191901Z","shell.execute_reply":"2026-10-08T16:36:11.224974Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **3.Exploratory Data Analysis (EDA)** ","metadata":{}},{"cell_type":"code","source":"# ============================================\n# CELL 9 — SET IMAGE PATHS AND CHECK FILES\n# ============================================\n\ntrain_images_path = \"/kaggle/working/dogs_cats/train/train\"\ntest_images_path = \"/kaggle/working/dogs_cats/test/test\"\n\ntrain_files = os.listdir(train_images_path)\ntest_files = os.listdir(test_images_path)\n\nprint(\"First 10 training files:\")\nprint(train_files[:10])\n\nprint(\"\\nFirst 10 testing files:\")\nprint(test_files[:10])\n\nprint(\"\\nNumber of training images:\", len(train_files))\nprint(\"Number of testing images:\", len(test_files))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:14.399882Z","iopub.execute_input":"2026-10-08T16:36:14.400156Z","iopub.status.idle":"2026-10-08T16:36:14.425713Z","shell.execute_reply.started":"2026-10-08T16:36:14.400135Z","shell.execute_reply":"2026-10-08T16:36:14.425034Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 10 — CREATE LABEL DATAFRAME\n# ============================================\n\ntrain_df = pd.DataFrame({\n    \"filename\": train_files\n})\n\ntrain_df[\"class\"] = train_df[\"filename\"].apply(\n    lambda x: 0 if x.startswith(\"cat.\") else 1\n)\n\ntrain_df[\"class_name\"] = train_df[\"class\"].map({\n    0: \"Cat\",\n    1: \"Dog\"\n})\n\nprint(\"Training dataset shape:\", train_df.shape)\n\nprint(\"\\nFirst 10 rows:\")\ndisplay(train_df.head(10))\n\nprint(\"\\nClass distribution:\")\nprint(train_df[\"class_name\"].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:16.841017Z","iopub.execute_input":"2026-10-08T16:36:16.841756Z","iopub.status.idle":"2026-10-08T16:36:16.9048Z","shell.execute_reply.started":"2026-10-08T16:36:16.841732Z","shell.execute_reply":"2026-10-08T16:36:16.904101Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 11 — SAMPLE IMAGE VISUALIZATION\n# ============================================\n\nsample_files = train_df.sample(8, random_state=42)\n\nplt.figure(figsize=(12, 8))\n\nfor i, (_, row) in enumerate(sample_files.iterrows()):\n\n    image_path = os.path.join(\n        train_images_path,\n        row[\"filename\"]\n    )\n\n    image = Image.open(image_path)\n\n    plt.subplot(2, 4, i + 1)\n    plt.imshow(image)\n    plt.title(row[\"class_name\"])\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:19.333993Z","iopub.execute_input":"2026-10-08T16:36:19.334278Z","iopub.status.idle":"2026-10-08T16:36:20.216694Z","shell.execute_reply.started":"2026-10-08T16:36:19.334257Z","shell.execute_reply":"2026-10-08T16:36:20.215642Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 12 — IMAGE DIMENSIONS ANALYSIS\n# ============================================\n\nimage_sizes = []\n\nfor filename in train_files[:1000]:\n\n    image_path = os.path.join(\n        train_images_path,\n        filename\n    )\n\n    with Image.open(image_path) as img:\n        image_sizes.append(img.size)\n\nsize_df = pd.DataFrame(\n    image_sizes,\n    columns=[\"width\", \"height\"]\n)\n\nprint(\"Image size statistics:\")\ndisplay(size_df.describe())\n\nprint(\"\\nMost common image sizes:\")\nprint(size_df.value_counts().head(10))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:30.128043Z","iopub.execute_input":"2026-10-08T16:36:30.12846Z","iopub.status.idle":"2026-10-08T16:36:30.226576Z","shell.execute_reply.started":"2026-10-08T16:36:30.128433Z","shell.execute_reply":"2026-10-08T16:36:30.225808Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 13 — CORRUPTED IMAGE CHECK\n# ============================================\n\ncorrupted_images = []\n\nfor filename in train_files:\n\n    image_path = os.path.join(\n        train_images_path,\n        filename\n    )\n\n    try:\n        with Image.open(image_path) as img:\n            img.verify()\n\n    except Exception:\n        corrupted_images.append(filename)\n\nprint(\"Total training images:\", len(train_files))\nprint(\"Corrupted images:\", len(corrupted_images))\n\nif len(corrupted_images) > 0:\n    print(\"\\nCorrupted files:\")\n    print(corrupted_images[:20])\nelse:\n    print(\"No corrupted images found.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:33.201243Z","iopub.execute_input":"2026-10-08T16:36:33.201978Z","iopub.status.idle":"2026-10-08T16:36:34.889321Z","shell.execute_reply.started":"2026-10-08T16:36:33.201943Z","shell.execute_reply":"2026-10-08T16:36:34.888309Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 14 — DUPLICATE IMAGE CHECK\n# ============================================\n\nhashes = {}\nduplicates = []\n\nfor filename in train_files:\n\n    image_path = os.path.join(\n        train_images_path,\n        filename\n    )\n\n    with open(image_path, \"rb\") as f:\n        file_hash = hashlib.md5(f.read()).hexdigest()\n\n    if file_hash in hashes:\n        duplicates.append(\n            (filename, hashes[file_hash])\n        )\n    else:\n        hashes[file_hash] = filename\n\nprint(\"Total images checked:\", len(train_files))\nprint(\"Duplicate occurrences found:\", len(duplicates))\n\nif duplicates:\n    print(\"\\nDuplicate pairs:\")\n    for duplicate in duplicates:\n        print(duplicate)\nelse:\n    print(\"No duplicates found.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:37.116467Z","iopub.execute_input":"2026-10-08T16:36:37.116837Z","iopub.status.idle":"2026-10-08T16:36:38.848502Z","shell.execute_reply.started":"2026-10-08T16:36:37.116814Z","shell.execute_reply":"2026-10-08T16:36:38.847573Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 15 — CLASS DISTRIBUTION PLOT\n# ============================================\n\nclass_counts = train_df[\"class_name\"].value_counts()\n\nplt.figure(figsize=(7, 5))\n\nplt.bar(\n    class_counts.index,\n    class_counts.values\n)\n\nplt.title(\"Training Dataset Class Distribution\")\nplt.xlabel(\"Class\")\nplt.ylabel(\"Number of Images\")\n\nfor i, value in enumerate(class_counts.values):\n    plt.text(\n        i,\n        value + 200,\n        str(value),\n        ha=\"center\"\n    )\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:40.481153Z","iopub.execute_input":"2026-10-08T16:36:40.481901Z","iopub.status.idle":"2026-10-08T16:36:40.60056Z","shell.execute_reply.started":"2026-10-08T16:36:40.481873Z","shell.execute_reply":"2026-10-08T16:36:40.599566Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **4. Data Preprocessing** ","metadata":{}},{"cell_type":"code","source":"# ============================================\n# CELL 16 — TRAIN-VALIDATION SPLIT\n# ============================================\n\nfrom sklearn.model_selection import train_test_split\n\ntrain_df_split, val_df = train_test_split(\n    train_df,\n    test_size=0.20,\n    random_state=42,\n    stratify=train_df[\"class\"]\n)\n\nprint(\"Training samples:\", len(train_df_split))\nprint(\"Validation samples:\", len(val_df))\n\nprint(\"\\nTraining class distribution:\")\nprint(train_df_split[\"class_name\"].value_counts())\n\nprint(\"\\nValidation class distribution:\")\nprint(val_df[\"class_name\"].value_counts())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:43.119904Z","iopub.execute_input":"2026-10-08T16:36:43.120484Z","iopub.status.idle":"2026-10-08T16:36:43.29198Z","shell.execute_reply.started":"2026-10-08T16:36:43.12046Z","shell.execute_reply":"2026-10-08T16:36:43.291163Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 17 — IMAGE SIZE\n# ============================================\n\nIMG_SIZE = (224, 224)\nBATCH_SIZE = 32\n\nprint(\"Target image size:\", IMG_SIZE)\nprint(\"Batch size:\", BATCH_SIZE)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:46.240143Z","iopub.execute_input":"2026-10-08T16:36:46.240926Z","iopub.status.idle":"2026-10-08T16:36:46.246045Z","shell.execute_reply.started":"2026-10-08T16:36:46.240899Z","shell.execute_reply":"2026-10-08T16:36:46.245112Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 18 — EFFICIENTNET PREPROCESSING\n# ============================================\n\nfrom tensorflow.keras.applications.efficientnet import preprocess_input\n\nprint(\"EfficientNet preprocessing function loaded successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:47.238284Z","iopub.execute_input":"2026-10-08T16:36:47.238833Z","iopub.status.idle":"2026-10-08T16:36:47.255771Z","shell.execute_reply.started":"2026-10-08T16:36:47.238806Z","shell.execute_reply":"2026-10-08T16:36:47.255028Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 19 — DATA AUGMENTATION\n# ============================================\n\nfrom tensorflow.keras import layers\n\ndata_augmentation = tf.keras.Sequential([\n    layers.RandomFlip(\"horizontal\"),\n    layers.RandomRotation(0.1),\n    layers.RandomZoom(0.1)\n])\n\nprint(\"Data augmentation pipeline created successfully.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:49.497012Z","iopub.execute_input":"2026-10-08T16:36:49.497441Z","iopub.status.idle":"2026-10-08T16:36:50.029891Z","shell.execute_reply.started":"2026-10-08T16:36:49.497415Z","shell.execute_reply":"2026-10-08T16:36:50.029011Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 20 — CREATE TRAIN AND VALIDATION DATASETS\n# ============================================\n\ndef load_image(filename, label):\n\n    # Convert TensorFlow tensors to Python-compatible values\n    filename = filename.numpy().decode(\"utf-8\")\n    label = label.numpy()\n\n    image_path = os.path.join(\n        train_images_path,\n        filename\n    )\n\n    # Read image using PIL\n    image = Image.open(image_path).convert(\"RGB\")\n    image = image.resize(IMG_SIZE)\n\n    # Convert to NumPy array\n    image = np.array(image, dtype=np.float32)\n\n    # EfficientNet preprocessing\n    image = preprocess_input(image)\n\n    return image, np.array([label], dtype=np.float32)\n\n\ndef tf_load_image(filename, label):\n\n    image, label = tf.py_function(\n        func=load_image,\n        inp=[filename, label],\n        Tout=[tf.float32, tf.float32]\n    )\n\n    image.set_shape(\n        [IMG_SIZE[0], IMG_SIZE[1], 3]\n    )\n\n    label.set_shape([1])\n\n    return image, label\n\n\n# ============================================\n# CREATE TRAIN DATASET\n# ============================================\n\ntrain_dataset = tf.data.Dataset.from_tensor_slices(\n    (\n        train_df_split[\"filename\"].astype(str).values,\n        train_df_split[\"class\"].astype(np.float32).values\n    )\n)\n\ntrain_dataset = train_dataset.shuffle(\n    buffer_size=len(train_df_split),\n    seed=SEED\n)\n\ntrain_dataset = train_dataset.map(\n    tf_load_image,\n    num_parallel_calls=tf.data.AUTOTUNE\n)\n\ntrain_dataset = train_dataset.batch(\n    BATCH_SIZE\n)\n\ntrain_dataset = train_dataset.prefetch(\n    tf.data.AUTOTUNE\n)\n\n\n# ============================================\n# CREATE VALIDATION DATASET\n# ============================================\n\nval_dataset = tf.data.Dataset.from_tensor_slices(\n    (\n        val_df[\"filename\"].astype(str).values,\n        val_df[\"class\"].astype(np.float32).values\n    )\n)\n\nval_dataset = val_dataset.map(\n    tf_load_image,\n    num_parallel_calls=tf.data.AUTOTUNE\n)\n\nval_dataset = val_dataset.batch(\n    BATCH_SIZE\n)\n\nval_dataset = val_dataset.prefetch(\n    tf.data.AUTOTUNE\n)\n\n\nprint(\"Train dataset created successfully.\")\nprint(\"Validation dataset created successfully.\")\n\nprint(\"Training samples:\", len(train_df_split))\nprint(\"Validation samples:\", len(val_df))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:36:55.652063Z","iopub.execute_input":"2026-10-08T16:36:55.652758Z","iopub.status.idle":"2026-10-08T16:36:57.954297Z","shell.execute_reply.started":"2026-10-08T16:36:55.65273Z","shell.execute_reply":"2026-10-08T16:36:57.953674Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 21 — CHECK ONE BATCH\n# ============================================\n\nfor images, labels in train_dataset.take(1):\n\n    print(\"Image batch shape:\", images.shape)\n    print(\"Label batch shape:\", labels.shape)\n    print(\"Image data type:\", images.dtype)\n    print(\"First 10 labels:\", labels[:10].numpy())\n    print(\n        \"Pixel value range:\",\n        tf.reduce_min(images).numpy(),\n        \"to\",\n        tf.reduce_max(images).numpy()\n    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:37:02.78288Z","iopub.execute_input":"2026-10-08T16:37:02.783161Z","iopub.status.idle":"2026-10-08T16:37:03.104893Z","shell.execute_reply.started":"2026-10-08T16:37:02.783142Z","shell.execute_reply":"2026-10-08T16:37:03.104121Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **5. Pretrained CNN — EfficientNetB0**","metadata":{}},{"cell_type":"code","source":"# ============================================\n# CELL 22 — PRETRAINED CNN: EfficientNetB0\n# ============================================\n\nfrom tensorflow.keras.applications import EfficientNetB0\n\nbase_model = EfficientNetB0(\n    weights=\"imagenet\",\n    include_top=False,\n    input_shape=(224, 224, 3)\n)\n\nprint(\"EfficientNetB0 loaded successfully!\")\nprint(\"Total layers:\", len(base_model.layers))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:37:07.366852Z","iopub.execute_input":"2026-10-08T16:37:07.367269Z","iopub.status.idle":"2026-10-08T16:37:10.003686Z","shell.execute_reply.started":"2026-10-08T16:37:07.367244Z","shell.execute_reply":"2026-10-08T16:37:10.002693Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 23 — BUILD BASELINE MODEL M0\n# ============================================\n\nfrom tensorflow.keras import layers, Model\n\ninputs = layers.Input(shape=(224, 224, 3))\n\nx = base_model(\n    inputs,\n    training=False\n)\n\nx = layers.GlobalAveragePooling2D()(x)\n\nx = layers.Dropout(0.2)(x)\n\noutputs = layers.Dense(\n    1,\n    activation=\"sigmoid\"\n)(x)\n\nmodel_m0 = Model(\n    inputs,\n    outputs,\n    name=\"EfficientNetB0_M0\"\n)\n\nmodel_m0.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:37:14.450784Z","iopub.execute_input":"2026-10-08T16:37:14.451219Z","iopub.status.idle":"2026-10-08T16:37:14.500576Z","shell.execute_reply.started":"2026-10-08T16:37:14.451192Z","shell.execute_reply":"2026-10-08T16:37:14.499666Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 24 — FREEZE & COMPILE M0\n# ============================================\n\nimport tensorflow as tf\n\nbase_model.trainable = False\n\nmodel_m0.compile(\n    optimizer=tf.keras.optimizers.Adam(\n        learning_rate=1e-3\n    ),\n    loss=tf.keras.losses.BinaryCrossentropy(),\n    metrics=[\n        tf.keras.metrics.BinaryAccuracy(name=\"accuracy\"),\n        tf.keras.metrics.BinaryCrossentropy(name=\"log_loss\")\n    ]\n)\n\nprint(\"M0 compiled successfully!\")\nprint(\"Base model trainable:\", base_model.trainable)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:37:29.09311Z","iopub.execute_input":"2026-10-08T16:37:29.093865Z","iopub.status.idle":"2026-10-08T16:37:29.120933Z","shell.execute_reply.started":"2026-10-08T16:37:29.093838Z","shell.execute_reply":"2026-10-08T16:37:29.120127Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 25 — TRAIN BASELINE MODEL M0\n# ============================================\n\nimport time\n\nEPOCHS_M0 = 5\n\nstart_time = time.time()\n\nhistory_m0 = model_m0.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=EPOCHS_M0\n)\n\ntraining_time = time.time() - start_time\n\nprint(\"\\nM0 training completed.\")\nprint(f\"Training time: {training_time / 60:.2f} minutes\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:37:31.347921Z","iopub.execute_input":"2026-10-08T16:37:31.348358Z","iopub.status.idle":"2026-10-08T16:46:47.219089Z","shell.execute_reply.started":"2026-10-08T16:37:31.348329Z","shell.execute_reply":"2026-10-08T16:46:47.218477Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 26 — M0 TRAINING CURVES\n# ============================================\n\nplt.figure(figsize=(12, 5))\n\n# Accuracy\nplt.subplot(1, 2, 1)\n\nplt.plot(\n    history_m0.history[\"accuracy\"],\n    label=\"Training Accuracy\"\n)\n\nplt.plot(\n    history_m0.history[\"val_accuracy\"],\n    label=\"Validation Accuracy\"\n)\n\nplt.title(\"M0 Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid(True)\n\n\n# Loss\nplt.subplot(1, 2, 2)\n\nplt.plot(\n    history_m0.history[\"loss\"],\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    history_m0.history[\"val_loss\"],\n    label=\"Validation Loss\"\n)\n\nplt.title(\"M0 Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:46:47.220339Z","iopub.execute_input":"2026-10-08T16:46:47.220701Z","iopub.status.idle":"2026-10-08T16:46:47.600951Z","shell.execute_reply.started":"2026-10-08T16:46:47.220679Z","shell.execute_reply":"2026-10-08T16:46:47.600079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 27 — EVALUATE BASELINE MODEL M0\n# ============================================\n\nm0_results = model_m0.evaluate(\n    val_dataset,\n    verbose=1,\n    return_dict=True\n)\n\nprint(\"\\nM0 Validation Results:\")\n\nfor metric_name, metric_value in m0_results.items():\n    print(f\"{metric_name}: {metric_value:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:46:58.022487Z","iopub.execute_input":"2026-10-08T16:46:58.022895Z","iopub.status.idle":"2026-10-08T16:47:18.60015Z","shell.execute_reply.started":"2026-10-08T16:46:58.022871Z","shell.execute_reply":"2026-10-08T16:47:18.599458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 28 — BUILD MODEL M1 WITH DATA AUGMENTATION\n# ============================================\n\nfrom tensorflow.keras import layers, Model\n\n# Input layer\ninputs = layers.Input(\n    shape=(224, 224, 3)\n)\n\n# Data augmentation\nx = data_augmentation(inputs)\n\n# EfficientNetB0\nx = base_model(\n    x,\n    training=False\n)\n\n# Global pooling\nx = layers.GlobalAveragePooling2D()(x)\n\n# Dropout\nx = layers.Dropout(0.2)(x)\n\n# Output layer\noutputs = layers.Dense(\n    1,\n    activation=\"sigmoid\"\n)(x)\n\n# Create M1 model\nmodel_m1 = Model(\n    inputs,\n    outputs,\n    name=\"EfficientNetB0_M1_Augmented\"\n)\n\nmodel_m1.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:47:20.849209Z","iopub.execute_input":"2026-10-08T16:47:20.850125Z","iopub.status.idle":"2026-10-08T16:47:20.899496Z","shell.execute_reply.started":"2026-10-08T16:47:20.850088Z","shell.execute_reply":"2026-10-08T16:47:20.898915Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 29 — COMPILE MODEL M1\n# ============================================\n\nbase_model.trainable = False\n\nmodel_m1.compile(\n    optimizer=tf.keras.optimizers.Adam(\n        learning_rate=1e-3\n    ),\n    loss=tf.keras.losses.BinaryCrossentropy(),\n    metrics=[\n        tf.keras.metrics.BinaryAccuracy(name=\"accuracy\"),\n        tf.keras.metrics.BinaryCrossentropy(name=\"log_loss\")\n    ]\n)\n\nprint(\"M1 compiled successfully!\")\nprint(\"Base model trainable:\", base_model.trainable)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:47:26.685755Z","iopub.execute_input":"2026-10-08T16:47:26.686213Z","iopub.status.idle":"2026-10-08T16:47:26.700951Z","shell.execute_reply.started":"2026-10-08T16:47:26.686186Z","shell.execute_reply":"2026-10-08T16:47:26.700344Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 30 — TRAIN MODEL M1\n# ============================================\n\nimport time\n\nEPOCHS_M1 = 5\n\nstart_time = time.time()\n\nhistory_m1 = model_m1.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=EPOCHS_M1\n)\n\ntraining_time_m1 = time.time() - start_time\n\nprint(\"\\nM1 training completed.\")\nprint(f\"Training time: {training_time_m1 / 60:.2f} minutes\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:47:30.926279Z","iopub.execute_input":"2026-10-08T16:47:30.926893Z","iopub.status.idle":"2026-10-08T16:57:57.839831Z","shell.execute_reply.started":"2026-10-08T16:47:30.926866Z","shell.execute_reply":"2026-10-08T16:57:57.839162Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 31 — M1 TRAINING CURVES\n# ============================================\n\nplt.figure(figsize=(12, 5))\n\n# Accuracy\nplt.subplot(1, 2, 1)\n\nplt.plot(\n    history_m1.history[\"accuracy\"],\n    label=\"Training Accuracy\"\n)\n\nplt.plot(\n    history_m1.history[\"val_accuracy\"],\n    label=\"Validation Accuracy\"\n)\n\nplt.title(\"M1 Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid(True)\n\n\n# Loss\nplt.subplot(1, 2, 2)\n\nplt.plot(\n    history_m1.history[\"loss\"],\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    history_m1.history[\"val_loss\"],\n    label=\"Validation Loss\"\n)\n\nplt.title(\"M1 Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:58:10.902336Z","iopub.execute_input":"2026-10-08T16:58:10.902657Z","iopub.status.idle":"2026-10-08T16:58:11.290761Z","shell.execute_reply.started":"2026-10-08T16:58:10.902634Z","shell.execute_reply":"2026-10-08T16:58:11.290022Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 32 — EVALUATE MODEL M1\n# ============================================\n\nm1_results = model_m1.evaluate(\n    val_dataset,\n    verbose=1,\n    return_dict=True\n)\n\nprint(\"\\nM1 Validation Results:\")\n\nfor metric_name, metric_value in m1_results.items():\n    print(f\"{metric_name}: {metric_value:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:58:17.284233Z","iopub.execute_input":"2026-10-08T16:58:17.284959Z","iopub.status.idle":"2026-10-08T16:58:41.481219Z","shell.execute_reply.started":"2026-10-08T16:58:17.284934Z","shell.execute_reply":"2026-10-08T16:58:41.480547Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 33 — COMPARE M0 VS M1\n# ============================================\n\ncomparison = pd.DataFrame({\n    \"Model\": [\n        \"M0 Baseline\",\n        \"M1 Augmented\"\n    ],\n    \"Validation Accuracy\": [\n        m0_results[\"accuracy\"],\n        m1_results[\"accuracy\"]\n    ],\n    \"Validation Loss\": [\n        m0_results[\"loss\"],\n        m1_results[\"loss\"]\n    ],\n    \"Validation Log Loss\": [\n        m0_results[\"log_loss\"],\n        m1_results[\"log_loss\"]\n    ]\n})\n\ndisplay(comparison)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:58:47.68005Z","iopub.execute_input":"2026-10-08T16:58:47.680452Z","iopub.status.idle":"2026-10-08T16:58:47.692356Z","shell.execute_reply.started":"2026-10-08T16:58:47.680426Z","shell.execute_reply":"2026-10-08T16:58:47.691503Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 34 — CALCULATE M1 IMPROVEMENT\n# ============================================\n\nm0_accuracy = m0_results[\"accuracy\"]\nm1_accuracy = m1_results[\"accuracy\"]\n\naccuracy_change = (m1_accuracy - m0_accuracy) * 100\n\nprint(f\"M0 Accuracy: {m0_accuracy:.4f}\")\nprint(f\"M1 Accuracy: {m1_accuracy:.4f}\")\n\nprint(f\"\\nAccuracy change: {accuracy_change:+.2f} percentage points\")\n\nif accuracy_change > 0:\n    print(\"M1 improved over M0.\")\nelif accuracy_change < 0:\n    print(\"M1 is lower than M0.\")\nelse:\n    print(\"M1 and M0 have the same accuracy.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:58:51.928527Z","iopub.execute_input":"2026-10-08T16:58:51.929215Z","iopub.status.idle":"2026-10-08T16:58:51.935541Z","shell.execute_reply.started":"2026-10-08T16:58:51.929187Z","shell.execute_reply":"2026-10-08T16:58:51.93453Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 35 — SAVE TRAINED MODELS\n# ============================================\n\nM0_PATH = \"/kaggle/working/dogs_cats_M0.keras\"\nM1_PATH = \"/kaggle/working/dogs_cats_M1.keras\"\n\nmodel_m0.save(M0_PATH)\nmodel_m1.save(M1_PATH)\n\nprint(\"Models saved successfully.\")\n\nprint(\"M0:\", M0_PATH)\nprint(\"M1:\", M1_PATH)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:58:56.604821Z","iopub.execute_input":"2026-10-08T16:58:56.605773Z","iopub.status.idle":"2026-10-08T16:58:58.421198Z","shell.execute_reply.started":"2026-10-08T16:58:56.605742Z","shell.execute_reply":"2026-10-08T16:58:58.420309Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 36 — VERIFY SAVED M1 MODEL\n# ============================================\n\nloaded_m1 = tf.keras.models.load_model(M1_PATH)\n\nprint(\"M1 model loaded successfully!\")\n\nprint(\"Model name:\", loaded_m1.name)\nprint(\"Input shape:\", loaded_m1.input_shape)\nprint(\"Output shape:\", loaded_m1.output_shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:59:00.039347Z","iopub.execute_input":"2026-10-08T16:59:00.039805Z","iopub.status.idle":"2026-10-08T16:59:01.40237Z","shell.execute_reply.started":"2026-10-08T16:59:00.039777Z","shell.execute_reply":"2026-10-08T16:59:01.40148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 37 — TEST SINGLE IMAGE\n# ============================================\n\nsample_filename = train_df.sample(\n    1,\n    random_state=42\n)[\"filename\"].iloc[0]\n\nsample_path = os.path.join(\n    train_images_path,\n    sample_filename\n)\n\nimage = Image.open(sample_path).convert(\"RGB\")\n\ndisplay(image.resize((224, 224)))\n\nimage_array = np.array(\n    image.resize(IMG_SIZE),\n    dtype=np.float32\n)\n\nimage_array = preprocess_input(image_array)\n\nimage_array = np.expand_dims(\n    image_array,\n    axis=0\n)\n\nprediction = loaded_m1.predict(\n    image_array,\n    verbose=0\n)[0][0]\n\npredicted_class = \"Dog\" if prediction >= 0.5 else \"Cat\"\n\nactual_class = (\n    \"Cat\"\n    if sample_filename.startswith(\"cat.\")\n    else \"Dog\"\n)\n\nprint(\"Filename:\", sample_filename)\nprint(\"Actual class:\", actual_class)\nprint(f\"Dog probability: {prediction:.4f}\")\nprint(\"Predicted class:\", predicted_class)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:59:08.477788Z","iopub.execute_input":"2026-10-08T16:59:08.478186Z","iopub.status.idle":"2026-10-08T16:59:11.097729Z","shell.execute_reply.started":"2026-10-08T16:59:08.47816Z","shell.execute_reply":"2026-10-08T16:59:11.097039Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 38 — TEST MULTIPLE IMAGES\n# ============================================\n\nsample_files = train_df.sample(\n    8,\n    random_state=42\n)\n\nplt.figure(figsize=(12, 8))\n\nfor i, (_, row) in enumerate(sample_files.iterrows()):\n\n    image_path = os.path.join(\n        train_images_path,\n        row[\"filename\"]\n    )\n\n    image = Image.open(image_path).convert(\"RGB\")\n\n    image_array = np.array(\n        image.resize(IMG_SIZE),\n        dtype=np.float32\n    )\n\n    image_array = preprocess_input(image_array)\n    image_array = np.expand_dims(image_array, axis=0)\n\n    prediction = loaded_m1.predict(\n        image_array,\n        verbose=0\n    )[0][0]\n\n    predicted_class = (\n        \"Dog\"\n        if prediction >= 0.5\n        else \"Cat\"\n    )\n\n    actual_class = row[\"class_name\"]\n\n    plt.subplot(2, 4, i + 1)\n\n    plt.imshow(image)\n\n    plt.title(\n        f\"Actual: {actual_class}\\nPredicted: {predicted_class}\"\n    )\n\n    plt.axis(\"off\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:59:27.292353Z","iopub.execute_input":"2026-10-08T16:59:27.293111Z","iopub.status.idle":"2026-10-08T16:59:28.918062Z","shell.execute_reply.started":"2026-10-08T16:59:27.293083Z","shell.execute_reply":"2026-10-08T16:59:28.917002Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 39 — CONFUSION MATRIX\n# ============================================\n\nfrom sklearn.metrics import confusion_matrix, classification_report\n\ny_true = []\ny_pred = []\n\nfor images, labels in val_dataset:\n\n    predictions = loaded_m1.predict(\n        images,\n        verbose=0\n    )\n\n    predicted_labels = (\n        predictions.flatten() >= 0.5\n    ).astype(int)\n\n    true_labels = labels.numpy().flatten().astype(int)\n\n    y_true.extend(true_labels)\n    y_pred.extend(predicted_labels)\n\ncm = confusion_matrix(\n    y_true,\n    y_pred\n)\n\nprint(\"Confusion Matrix:\")\nprint(cm)\n\nprint(\"\\nClassification Report:\")\nprint(\n    classification_report(\n        y_true,\n        y_pred,\n        target_names=[\"Cat\", \"Dog\"]\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T16:59:51.887436Z","iopub.execute_input":"2026-10-08T16:59:51.888067Z","iopub.status.idle":"2026-10-08T17:00:29.375229Z","shell.execute_reply.started":"2026-10-08T16:59:51.888041Z","shell.execute_reply":"2026-10-08T17:00:29.374541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 40 — CONFUSION MATRIX VISUALIZATION\n# ============================================\n\nplt.figure(figsize=(7, 6))\n\nsns.heatmap(\n    cm,\n    annot=True,\n    fmt=\"d\",\n    cmap=\"Blues\",\n    xticklabels=[\"Cat\", \"Dog\"],\n    yticklabels=[\"Cat\", \"Dog\"]\n)\n\nplt.title(\"M1 Confusion Matrix\")\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:00:36.582322Z","iopub.execute_input":"2026-10-08T17:00:36.582849Z","iopub.status.idle":"2026-10-08T17:00:36.747342Z","shell.execute_reply.started":"2026-10-08T17:00:36.582822Z","shell.execute_reply":"2026-10-08T17:00:36.74662Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 41 — FINAL MODEL COMPARISON\n# ============================================\n\nfinal_comparison = pd.DataFrame({\n    \"Model\": [\n        \"M0 - Baseline\",\n        \"M1 - Data Augmentation\"\n    ],\n    \"Accuracy\": [\n        m0_results[\"accuracy\"],\n        m1_results[\"accuracy\"]\n    ],\n    \"Loss\": [\n        m0_results[\"loss\"],\n        m1_results[\"loss\"]\n    ],\n    \"Log Loss\": [\n        m0_results[\"log_loss\"],\n        m1_results[\"log_loss\"]\n    ]\n})\n\ndisplay(final_comparison)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:00:57.86936Z","iopub.execute_input":"2026-10-08T17:00:57.869949Z","iopub.status.idle":"2026-10-08T17:00:57.880814Z","shell.execute_reply.started":"2026-10-08T17:00:57.869923Z","shell.execute_reply":"2026-10-08T17:00:57.879878Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 42 — FINAL PROJECT SUMMARY\n# ============================================\n\nprint(\"=\" * 60)\nprint(\"DOGS VS CATS IMAGE CLASSIFICATION — FINAL SUMMARY\")\nprint(\"=\" * 60)\n\nprint(\"\\nDataset:\")\nprint(\"Training images:\", len(train_df_split))\nprint(\"Validation images:\", len(val_df))\nprint(\"Image size:\", IMG_SIZE)\n\nprint(\"\\nM0 — Baseline:\")\nprint(f\"Accuracy: {m0_results['accuracy']:.4f}\")\nprint(f\"Loss: {m0_results['loss']:.4f}\")\nprint(f\"Log Loss: {m0_results['log_loss']:.4f}\")\n\nprint(\"\\nM1 — Data Augmentation:\")\nprint(f\"Accuracy: {m1_results['accuracy']:.4f}\")\nprint(f\"Loss: {m1_results['loss']:.4f}\")\nprint(f\"Log Loss: {m1_results['log_loss']:.4f}\")\n\nprint(\"\\nImprovement:\")\nprint(\n    f\"Accuracy change: \"\n    f\"{(m1_results['accuracy'] - m0_results['accuracy']) * 100:+.2f} percentage points\"\n)\n\nprint(\"\\nModels:\")\nprint(\"M0 saved:\", M0_PATH)\nprint(\"M1 saved:\", M1_PATH)\n\nprint(\"\\n\" + \"=\" * 60)\nprint(\"PROJECT COMPLETED SUCCESSFULLY\")\nprint(\"=\" * 60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:02.056732Z","iopub.execute_input":"2026-10-08T17:01:02.057171Z","iopub.status.idle":"2026-10-08T17:01:02.065487Z","shell.execute_reply.started":"2026-10-08T17:01:02.057146Z","shell.execute_reply":"2026-10-08T17:01:02.064676Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 43 — CREATE MODEL M2 FOR FINE-TUNING\n# ============================================\n\n# Start from the already trained M1 architecture\nmodel_m2 = tf.keras.models.clone_model(model_m1)\n\n# Copy M1 weights into M2\nmodel_m2.set_weights(model_m1.get_weights())\n\nprint(\"M2 model created successfully!\")\nprint(\"Model name:\", model_m2.name)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:06.203968Z","iopub.execute_input":"2026-10-08T17:01:06.204885Z","iopub.status.idle":"2026-10-08T17:01:07.286581Z","shell.execute_reply.started":"2026-10-08T17:01:06.204848Z","shell.execute_reply":"2026-10-08T17:01:07.285688Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 44 — UNFREEZE LAST EFFICIENTNET LAYERS\n# ============================================\n\n# Find EfficientNet inside M2\nm2_base_model = None\n\nfor layer in model_m2.layers:\n    if isinstance(layer, tf.keras.Model) and \"efficientnet\" in layer.name.lower():\n        m2_base_model = layer\n        break\n\nif m2_base_model is None:\n    raise ValueError(\"EfficientNet base model not found.\")\n\n# Freeze all layers first\nm2_base_model.trainable = True\n\n# Freeze earlier layers\nfine_tune_from = len(m2_base_model.layers) - 20\n\nfor layer in m2_base_model.layers[:fine_tune_from]:\n    layer.trainable = False\n\n# Keep the last 20 layers trainable\nfor layer in m2_base_model.layers[fine_tune_from:]:\n    layer.trainable = True\n\nprint(\"Fine-tuning configuration completed.\")\nprint(\"Total EfficientNet layers:\", len(m2_base_model.layers))\nprint(\"Fine-tuning from layer:\", fine_tune_from)\nprint(\n    \"Trainable EfficientNet layers:\",\n    sum(layer.trainable for layer in m2_base_model.layers)\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:09.04439Z","iopub.execute_input":"2026-10-08T17:01:09.045089Z","iopub.status.idle":"2026-10-08T17:01:09.058699Z","shell.execute_reply.started":"2026-10-08T17:01:09.04506Z","shell.execute_reply":"2026-10-08T17:01:09.05774Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 45 — CHECK M2 TRAINABLE PARAMETERS\n# ============================================\n\nmodel_m2.summary()\n\ntrainable_count = np.sum([\n    np.prod(variable.shape)\n    for variable in model_m2.trainable_variables\n])\n\nnon_trainable_count = np.sum([\n    np.prod(variable.shape)\n    for variable in model_m2.non_trainable_variables\n])\n\nprint(\"\\nTrainable parameters:\", trainable_count)\nprint(\"Non-trainable parameters:\", non_trainable_count)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:11.591542Z","iopub.execute_input":"2026-10-08T17:01:11.592013Z","iopub.status.idle":"2026-10-08T17:01:11.627646Z","shell.execute_reply.started":"2026-10-08T17:01:11.591987Z","shell.execute_reply":"2026-10-08T17:01:11.626789Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 46 — COMPILE MODEL M2\n# ============================================\n\nmodel_m2.compile(\n    optimizer=tf.keras.optimizers.Adam(\n        learning_rate=1e-5\n    ),\n    loss=tf.keras.losses.BinaryCrossentropy(),\n    metrics=[\n        tf.keras.metrics.BinaryAccuracy(name=\"accuracy\"),\n        tf.keras.metrics.BinaryCrossentropy(name=\"log_loss\")\n    ]\n)\n\nprint(\"M2 compiled successfully!\")\nprint(\"Learning rate:\", 1e-5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:15.841217Z","iopub.execute_input":"2026-10-08T17:01:15.841834Z","iopub.status.idle":"2026-10-08T17:01:15.856938Z","shell.execute_reply.started":"2026-10-08T17:01:15.841807Z","shell.execute_reply":"2026-10-08T17:01:15.856031Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 47 — TRAIN MODEL M2\n# ============================================\n\nEPOCHS_M2 = 5\n\nstart_time = time.time()\n\nhistory_m2 = model_m2.fit(\n    train_dataset,\n    validation_data=val_dataset,\n    epochs=EPOCHS_M2\n)\n\ntraining_time_m2 = time.time() - start_time\n\nprint(\"\\nM2 training completed.\")\nprint(f\"Training time: {training_time_m2 / 60:.2f} minutes\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:01:19.211856Z","iopub.execute_input":"2026-10-08T17:01:19.21236Z","iopub.status.idle":"2026-10-08T17:12:02.901522Z","shell.execute_reply.started":"2026-10-08T17:01:19.212335Z","shell.execute_reply":"2026-10-08T17:12:02.900488Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 48 — M2 TRAINING CURVES\n# ============================================\n\nplt.figure(figsize=(12, 5))\n\n# Accuracy\nplt.subplot(1, 2, 1)\n\nplt.plot(\n    history_m2.history[\"accuracy\"],\n    label=\"Training Accuracy\"\n)\n\nplt.plot(\n    history_m2.history[\"val_accuracy\"],\n    label=\"Validation Accuracy\"\n)\n\nplt.title(\"M2 Fine-Tuning Accuracy\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Accuracy\")\nplt.legend()\nplt.grid(True)\n\n\n# Loss\nplt.subplot(1, 2, 2)\n\nplt.plot(\n    history_m2.history[\"loss\"],\n    label=\"Training Loss\"\n)\n\nplt.plot(\n    history_m2.history[\"val_loss\"],\n    label=\"Validation Loss\"\n)\n\nplt.title(\"M2 Fine-Tuning Loss\")\nplt.xlabel(\"Epoch\")\nplt.ylabel(\"Loss\")\nplt.legend()\nplt.grid(True)\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:13:06.826707Z","iopub.execute_input":"2026-10-08T17:13:06.827472Z","iopub.status.idle":"2026-10-08T17:13:07.214638Z","shell.execute_reply.started":"2026-10-08T17:13:06.827447Z","shell.execute_reply":"2026-10-08T17:13:07.213935Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 49 — EVALUATE MODEL M2\n# ============================================\n\nm2_results = model_m2.evaluate(\n    val_dataset,\n    verbose=1,\n    return_dict=True\n)\n\nprint(\"\\nM2 Validation Results:\")\n\nfor metric_name, metric_value in m2_results.items():\n    print(f\"{metric_name}: {metric_value:.4f}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:13:11.174584Z","iopub.execute_input":"2026-10-08T17:13:11.175395Z","iopub.status.idle":"2026-10-08T17:13:36.083647Z","shell.execute_reply.started":"2026-10-08T17:13:11.175367Z","shell.execute_reply":"2026-10-08T17:13:36.082853Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 50 — COMPARE M0, M1 AND M2\n# ============================================\n\nall_models_comparison = pd.DataFrame({\n    \"Model\": [\n        \"M0 - Baseline\",\n        \"M1 - Data Augmentation\",\n        \"M2 - Fine-Tuning\"\n    ],\n    \"Validation Accuracy\": [\n        m0_results[\"accuracy\"],\n        m1_results[\"accuracy\"],\n        m2_results[\"accuracy\"]\n    ],\n    \"Validation Loss\": [\n        m0_results[\"loss\"],\n        m1_results[\"loss\"],\n        m2_results[\"loss\"]\n    ],\n    \"Validation Log Loss\": [\n        m0_results[\"log_loss\"],\n        m1_results[\"log_loss\"],\n        m2_results[\"log_loss\"]\n    ]\n})\n\ndisplay(all_models_comparison)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:13:36.085432Z","iopub.execute_input":"2026-10-08T17:13:36.085742Z","iopub.status.idle":"2026-10-08T17:13:36.097326Z","shell.execute_reply.started":"2026-10-08T17:13:36.085721Z","shell.execute_reply":"2026-10-08T17:13:36.096381Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 51 — SELECT BEST MODEL\n# ============================================\n\nmodel_results = {\n    \"M0 - Baseline\": m0_results[\"accuracy\"],\n    \"M1 - Data Augmentation\": m1_results[\"accuracy\"],\n    \"M2 - Fine-Tuning\": m2_results[\"accuracy\"]\n}\n\nbest_model_name = max(\n    model_results,\n    key=model_results.get\n)\n\nbest_accuracy = model_results[best_model_name]\n\nprint(\"Best Model:\", best_model_name)\nprint(f\"Best Validation Accuracy: {best_accuracy:.4f}\")\nprint(f\"Best Validation Accuracy: {best_accuracy * 100:.2f}%\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:14:10.590436Z","iopub.execute_input":"2026-10-08T17:14:10.590766Z","iopub.status.idle":"2026-10-08T17:14:10.596566Z","shell.execute_reply.started":"2026-10-08T17:14:10.590743Z","shell.execute_reply":"2026-10-08T17:14:10.595673Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 52 — SAVE M2 MODEL\n# ============================================\n\nM2_PATH = \"/kaggle/working/dogs_cats_M2_finetuned.keras\"\n\nmodel_m2.save(M2_PATH)\n\nprint(\"M2 model saved successfully.\")\nprint(\"M2:\", M2_PATH)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:14:14.946229Z","iopub.execute_input":"2026-10-08T17:14:14.947062Z","iopub.status.idle":"2026-10-08T17:14:15.710209Z","shell.execute_reply.started":"2026-10-08T17:14:14.947033Z","shell.execute_reply":"2026-10-08T17:14:15.709494Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 53 — M2 CONFUSION MATRIX\n# ============================================\n\ny_true_m2 = []\ny_pred_m2 = []\n\nfor images, labels in val_dataset:\n\n    predictions = model_m2.predict(\n        images,\n        verbose=0\n    )\n\n    predicted_labels = (\n        predictions.flatten() >= 0.5\n    ).astype(int)\n\n    true_labels = (\n        labels.numpy()\n        .flatten()\n        .astype(int)\n    )\n\n    y_true_m2.extend(true_labels)\n    y_pred_m2.extend(predicted_labels)\n\ncm_m2 = confusion_matrix(\n    y_true_m2,\n    y_pred_m2\n)\n\nprint(\"M2 Confusion Matrix:\")\nprint(cm_m2)\n\nprint(\"\\nM2 Classification Report:\")\n\nprint(\n    classification_report(\n        y_true_m2,\n        y_pred_m2,\n        target_names=[\"Cat\", \"Dog\"]\n    )\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:14:16.98707Z","iopub.execute_input":"2026-10-08T17:14:16.987896Z","iopub.status.idle":"2026-10-08T17:14:56.322958Z","shell.execute_reply.started":"2026-10-08T17:14:16.987867Z","shell.execute_reply":"2026-10-08T17:14:56.322091Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 54 — M2 CONFUSION MATRIX VISUALIZATION\n# ============================================\n\nplt.figure(figsize=(7, 6))\n\nsns.heatmap(\n    cm_m2,\n    annot=True,\n    fmt=\"d\",\n    cmap=\"Blues\",\n    xticklabels=[\"Cat\", \"Dog\"],\n    yticklabels=[\"Cat\", \"Dog\"]\n)\n\nplt.title(\"M2 Fine-Tuned Model — Confusion Matrix\")\nplt.xlabel(\"Predicted Label\")\nplt.ylabel(\"True Label\")\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:00.959029Z","iopub.execute_input":"2026-10-08T17:15:00.959476Z","iopub.status.idle":"2026-10-08T17:15:01.125799Z","shell.execute_reply.started":"2026-10-08T17:15:00.959449Z","shell.execute_reply":"2026-10-08T17:15:01.125017Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 55 — FINAL MODEL ACCURACY COMPARISON\n# ============================================\n\nmodel_names = [\n    \"M0 Baseline\",\n    \"M1 Augmentation\",\n    \"M2 Fine-Tuning\"\n]\n\naccuracies = [\n    m0_results[\"accuracy\"] * 100,\n    m1_results[\"accuracy\"] * 100,\n    m2_results[\"accuracy\"] * 100\n]\n\nplt.figure(figsize=(9, 6))\n\nbars = plt.bar(\n    model_names,\n    accuracies\n)\n\nplt.title(\"Model Accuracy Comparison\")\nplt.xlabel(\"Model\")\nplt.ylabel(\"Validation Accuracy (%)\")\n\nplt.ylim(\n    min(accuracies) - 1,\n    100\n)\n\nfor bar, accuracy in zip(bars, accuracies):\n    plt.text(\n        bar.get_x() + bar.get_width() / 2,\n        bar.get_height() + 0.05,\n        f\"{accuracy:.2f}%\",\n        ha=\"center\"\n    )\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:06.086314Z","iopub.execute_input":"2026-10-08T17:15:06.087098Z","iopub.status.idle":"2026-10-08T17:15:06.251395Z","shell.execute_reply.started":"2026-10-08T17:15:06.087069Z","shell.execute_reply":"2026-10-08T17:15:06.250639Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# CELL 56 — FINAL PROJECT SUMMARY\n# ============================================\n\nprint(\"=\" * 65)\nprint(\"DOGS VS CATS IMAGE CLASSIFICATION — FINAL PROJECT\")\nprint(\"=\" * 65)\n\nprint(\"\\nDATASET\")\nprint(\"-\" * 65)\nprint(\"Training images:\", len(train_df_split))\nprint(\"Validation images:\", len(val_df))\nprint(\"Image size:\", IMG_SIZE)\nprint(\"Batch size:\", BATCH_SIZE)\n\nprint(\"\\nMODEL RESULTS\")\nprint(\"-\" * 65)\n\nprint(\n    f\"M0 Baseline       : \"\n    f\"{m0_results['accuracy'] * 100:.2f}% accuracy\"\n)\n\nprint(\n    f\"M1 Augmentation   : \"\n    f\"{m1_results['accuracy'] * 100:.2f}% accuracy\"\n)\n\nprint(\n    f\"M2 Fine-Tuning    : \"\n    f\"{m2_results['accuracy'] * 100:.2f}% accuracy\"\n)\n\nprint(\"\\nBEST MODEL\")\nprint(\"-\" * 65)\nprint(\"Model:\", best_model_name)\nprint(f\"Accuracy: {best_accuracy * 100:.2f}%\")\n\nprint(\"\\nSAVED MODELS\")\nprint(\"-\" * 65)\nprint(M0_PATH)\nprint(M1_PATH)\nprint(M2_PATH)\n\nprint(\"\\n\" + \"=\" * 65)\nprint(\"PROJECT COMPLETED SUCCESSFULLY\")\nprint(\"=\" * 65)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:10.748247Z","iopub.execute_input":"2026-10-08T17:15:10.748838Z","iopub.status.idle":"2026-10-08T17:15:10.756374Z","shell.execute_reply.started":"2026-10-08T17:15:10.748812Z","shell.execute_reply":"2026-10-08T17:15:10.755509Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Check competition files\nprint(\"Competition files:\")\nfor file in os.listdir(COMPETITION_PATH):\n    print(file)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:15.324398Z","iopub.execute_input":"2026-10-08T17:15:15.324844Z","iopub.status.idle":"2026-10-08T17:15:15.329829Z","shell.execute_reply.started":"2026-10-08T17:15:15.324817Z","shell.execute_reply":"2026-10-08T17:15:15.32909Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"sample_submission_path = os.path.join(\n    COMPETITION_PATH,\n    \"sample_submission.csv\"\n)\n\nsample_submission = pd.read_csv(sample_submission_path)\n\nprint(\"Sample submission shape:\", sample_submission.shape)\ndisplay(sample_submission.head())\nprint(\"Columns:\", sample_submission.columns.tolist())","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:17.806055Z","iopub.execute_input":"2026-10-08T17:15:17.806509Z","iopub.status.idle":"2026-10-08T17:15:17.835789Z","shell.execute_reply.started":"2026-10-08T17:15:17.806481Z","shell.execute_reply":"2026-10-08T17:15:17.834961Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"m0_model = tf.keras.models.load_model(\n    \"/kaggle/working/dogs_cats_M0.keras\"\n)\n\nprint(\"M0 loaded successfully!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:23.174979Z","iopub.execute_input":"2026-10-08T17:15:23.175646Z","iopub.status.idle":"2026-10-08T17:15:24.56283Z","shell.execute_reply.started":"2026-10-08T17:15:23.175617Z","shell.execute_reply":"2026-10-08T17:15:24.561847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 58 — Check test images\n\ntest_files = sorted(\n    os.listdir(test_images_path),\n    key=lambda x: int(os.path.splitext(x)[0])\n)\n\nprint(\"Number of test images:\", len(test_files))\nprint(\"First 10 files:\", test_files[:10])\nprint(\"Last 10 files:\", test_files[-10:])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:25.837755Z","iopub.execute_input":"2026-10-08T17:15:25.838552Z","iopub.status.idle":"2026-10-08T17:15:25.865002Z","shell.execute_reply.started":"2026-10-08T17:15:25.838523Z","shell.execute_reply":"2026-10-08T17:15:25.864046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 59 — Generate M0 predictions for all test images\n\ndef load_test_image(filename):\n    image_path = os.path.join(test_images_path, filename)\n\n    image = Image.open(image_path).convert(\"RGB\")\n    image = image.resize(IMG_SIZE)\n\n    image = np.array(image, dtype=np.float32)\n    image = preprocess_input(image)\n\n    return image\n\n\n# Load test images in Kaggle ID order\ntest_images = np.stack([\n    load_test_image(filename)\n    for filename in test_files\n])\n\nprint(\"Test images array shape:\", test_images.shape)\n\n# Generate predictions\nm0_predictions = m0_model.predict(\n    test_images,\n    batch_size=BATCH_SIZE,\n    verbose=1\n).flatten()\n\nprint(\"\\nM0 predictions generated successfully!\")\nprint(\"Number of predictions:\", len(m0_predictions))\nprint(\"Minimum probability:\", m0_predictions.min())\nprint(\"Maximum probability:\", m0_predictions.max())\nprint(\"First 10 predictions:\", m0_predictions[:10])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:15:29.054208Z","iopub.execute_input":"2026-10-08T17:15:29.054723Z","iopub.status.idle":"2026-10-08T17:17:13.134828Z","shell.execute_reply.started":"2026-10-08T17:15:29.054694Z","shell.execute_reply":"2026-10-08T17:17:13.133988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 60 — Check whether M0 predictions were generated\n\nif \"m0_predictions\" in globals():\n    print(\"M0 predictions generated successfully!\")\n    print(\"Number of predictions:\", len(m0_predictions))\n    print(\"Minimum probability:\", m0_predictions.min())\n    print(\"Maximum probability:\", m0_predictions.max())\n    print(\"First 10 predictions:\", m0_predictions[:10])\nelse:\n    print(\"M0 predictions have NOT been generated yet.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:17:47.227371Z","iopub.execute_input":"2026-10-08T17:17:47.22799Z","iopub.status.idle":"2026-10-08T17:17:47.236006Z","shell.execute_reply.started":"2026-10-08T17:17:47.227963Z","shell.execute_reply":"2026-10-08T17:17:47.235037Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 61 — Create M0 Kaggle submission\n\nm0_submission = sample_submission.copy()\n\n# Keep the exact ID order from sample_submission.csv\nm0_submission[\"label\"] = m0_predictions\n\n# Save using the required submission filename\nm0_submission_path = \"/kaggle/working/M0_submission.csv\"\nm0_submission.to_csv(m0_submission_path, index=False)\n\nprint(\"M0 submission created successfully!\")\nprint(\"File:\", m0_submission_path)\nprint(\"Shape:\", m0_submission.shape)\n\ndisplay(m0_submission.head(10))\n\nprint(\"\\nColumns:\", m0_submission.columns.tolist())\nprint(\"Number of rows:\", len(m0_submission))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:18:47.562051Z","iopub.execute_input":"2026-10-08T17:18:47.562491Z","iopub.status.idle":"2026-10-08T17:18:47.611234Z","shell.execute_reply.started":"2026-10-08T17:18:47.562465Z","shell.execute_reply":"2026-10-08T17:18:47.610234Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 62 — Verify M0 submission format\n\nprint(\"=== M0 SUBMISSION VERIFICATION ===\")\n\n# 1. Shape\nprint(\"Shape:\", m0_submission.shape)\n\n# 2. Columns\nprint(\"Columns:\", m0_submission.columns.tolist())\n\n# 3. ID checks\nprint(\"First ID:\", m0_submission[\"id\"].iloc[0])\nprint(\"Last ID:\", m0_submission[\"id\"].iloc[-1])\nprint(\"IDs in correct order:\",\n      m0_submission[\"id\"].equals(sample_submission[\"id\"]))\n\n# 4. Label checks\nprint(\"Missing labels:\", m0_submission[\"label\"].isna().sum())\nprint(\"Labels between 0 and 1:\",\n      m0_submission[\"label\"].between(0, 1).all())\n\n# 5. Exact structure\nprint(\"Same columns as sample:\",\n      m0_submission.columns.tolist() == sample_submission.columns.tolist())\n\nprint(\"\\n=== VERIFICATION COMPLETE ===\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:19:55.715134Z","iopub.execute_input":"2026-10-08T17:19:55.715845Z","iopub.status.idle":"2026-10-08T17:19:55.724799Z","shell.execute_reply.started":"2026-10-08T17:19:55.715816Z","shell.execute_reply":"2026-10-08T17:19:55.723937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 63 — Create final M0 submission file with required filename\n\nROLL_NO = \"YOUR_ROLLNO\"   # <-- yahan apna roll number likho\n\nfinal_m0_path = f\"/kaggle/working/{ROLL_NO}_M0_submission.csv\"\n\nm0_submission.to_csv(final_m0_path, index=False)\n\nprint(\"Final M0 submission file created:\")\nprint(final_m0_path)\nprint(\"Shape:\", m0_submission.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:35:44.555532Z","iopub.execute_input":"2026-10-08T17:35:44.556485Z","iopub.status.idle":"2026-10-08T17:35:44.588806Z","shell.execute_reply.started":"2026-10-08T17:35:44.556456Z","shell.execute_reply":"2026-10-08T17:35:44.588079Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Cell 64 — Download M0 submission\n\nfrom IPython.display import Javascript, display\n\nfile_path = \"/kaggle/working/26_M0_submission.csv\"\n\nprint(\"File exists:\", os.path.exists(file_path))\nprint(\"File size:\", os.path.getsize(file_path), \"bytes\")\n\ndisplay(Javascript(f\"\"\"\n(async () => {{\n    const response = await fetch('/api/v1/files/download?path={file_path}');\n    if (!response.ok) {{\n        alert('Download failed. Please use the Output/Files panel.');\n        return;\n    }}\n\n    const blob = await response.blob();\n    const url = URL.createObjectURL(blob);\n\n    const a = document.createElement('a');\n    a.href = url;\n    a.download = '26_M0_submission.csv';\n    document.body.appendChild(a);\n    a.click();\n    a.remove();\n\n    URL.revokeObjectURL(url);\n}})();\n\"\"\"))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:27:41.138423Z","iopub.execute_input":"2026-10-08T17:27:41.138845Z","iopub.status.idle":"2026-10-08T17:27:41.145422Z","shell.execute_reply.started":"2026-10-08T17:27:41.138821Z","shell.execute_reply":"2026-10-08T17:27:41.144847Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# M1 SUBMISSION — EfficientNet-B0 + Data Augmentation\n# ============================================\n\n# Load trained M1 model\nm1_model = tf.keras.models.load_model(\n    \"/kaggle/working/dogs_cats_M1.keras\"\n)\n\nprint(\"M1 model loaded successfully!\")\n\n# Generate predictions for all test images\nm1_predictions = m1_model.predict(\n    test_images,\n    batch_size=BATCH_SIZE,\n    verbose=1\n).flatten()\n\nprint(\"\\nM1 predictions generated!\")\nprint(\"Number of predictions:\", len(m1_predictions))\nprint(\"Minimum probability:\", m1_predictions.min())\nprint(\"Maximum probability:\", m1_predictions.max())\n\n# Create submission using the official sample_submission format\nm1_submission = sample_submission.copy()\nm1_submission[\"label\"] = m1_predictions\n\n# Save final M1 submission\nm1_submission_path = \"/kaggle/working/26_M1_submission.csv\"\n\nm1_submission.to_csv(\n    m1_submission_path,\n    index=False\n)\n\nprint(\"\\n============================================\")\nprint(\"M1 SUBMISSION CREATED SUCCESSFULLY!\")\nprint(\"============================================\")\nprint(\"File:\", m1_submission_path)\nprint(\"Shape:\", m1_submission.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:34:18.072327Z","iopub.execute_input":"2026-10-08T17:34:18.073113Z","iopub.status.idle":"2026-10-08T17:35:12.367926Z","shell.execute_reply.started":"2026-10-08T17:34:18.073082Z","shell.execute_reply":"2026-10-08T17:35:12.366677Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# M1 SUBMISSION — VERIFICATION\n# ============================================\n\nprint(\"=== M1 SUBMISSION VERIFICATION ===\")\n\nprint(\"Shape:\", m1_submission.shape)\nprint(\"Columns:\", list(m1_submission.columns))\n\nprint(\"First ID:\", m1_submission[\"id\"].iloc[0])\nprint(\"Last ID:\", m1_submission[\"id\"].iloc[-1])\n\nprint(\n    \"IDs in correct order:\",\n    m1_submission[\"id\"].tolist() == sample_submission[\"id\"].tolist()\n)\n\nprint(\n    \"Missing labels:\",\n    m1_submission[\"label\"].isna().sum()\n)\n\nprint(\n    \"Labels between 0 and 1:\",\n    ((m1_submission[\"label\"] >= 0) &\n     (m1_submission[\"label\"] <= 1)).all()\n)\n\nprint(\n    \"Same columns as sample:\",\n    list(m1_submission.columns) == list(sample_submission.columns)\n)\n\nprint(\"\\nFirst 5 rows:\")\ndisplay(m1_submission.head())\n\nprint(\"\\n=== M1 VERIFICATION COMPLETE ===\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:36:29.803792Z","iopub.execute_input":"2026-10-08T17:36:29.80426Z","iopub.status.idle":"2026-10-08T17:36:29.818133Z","shell.execute_reply.started":"2026-10-08T17:36:29.804234Z","shell.execute_reply":"2026-10-08T17:36:29.817251Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# M2 SUBMISSION — EfficientNet-B0 + Fine-Tuning\n# ============================================\n\n# Load trained M2 model\nm2_model = tf.keras.models.load_model(\n    \"/kaggle/working/dogs_cats_M2_finetuned.keras\"\n)\n\nprint(\"M2 model loaded successfully!\")\n\n# Generate predictions for all test images\nm2_predictions = m2_model.predict(\n    test_images,\n    batch_size=BATCH_SIZE,\n    verbose=1\n).flatten()\n\nprint(\"\\nM2 predictions generated!\")\nprint(\"Number of predictions:\", len(m2_predictions))\nprint(\"Minimum probability:\", m2_predictions.min())\nprint(\"Maximum probability:\", m2_predictions.max())\n\n# Create submission using official sample_submission format\nm2_submission = sample_submission.copy()\nm2_submission[\"label\"] = m2_predictions\n\n# Save M2 submission\nm2_submission_path = \"/kaggle/working/26_M2_submission.csv\"\n\nm2_submission.to_csv(\n    m2_submission_path,\n    index=False\n)\n\nprint(\"\\n============================================\")\nprint(\"M2 SUBMISSION CREATED SUCCESSFULLY!\")\nprint(\"============================================\")\nprint(\"File:\", m2_submission_path)\nprint(\"Shape:\", m2_submission.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:42:46.58089Z","iopub.execute_input":"2026-10-08T17:42:46.581371Z","iopub.status.idle":"2026-10-08T17:43:41.366908Z","shell.execute_reply.started":"2026-10-08T17:42:46.581344Z","shell.execute_reply":"2026-10-08T17:43:41.36598Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# M2 SUBMISSION — VERIFICATION\n# ============================================\n\nprint(\"=== M2 SUBMISSION VERIFICATION ===\")\n\nprint(\"Shape:\", m2_submission.shape)\nprint(\"Columns:\", list(m2_submission.columns))\n\nprint(\"First ID:\", m2_submission[\"id\"].iloc[0])\nprint(\"Last ID:\", m2_submission[\"id\"].iloc[-1])\n\nprint(\n    \"IDs in correct order:\",\n    m2_submission[\"id\"].tolist() == sample_submission[\"id\"].tolist()\n)\n\nprint(\n    \"Missing labels:\",\n    m2_submission[\"label\"].isna().sum()\n)\n\nprint(\n    \"Labels between 0 and 1:\",\n    ((m2_submission[\"label\"] >= 0) &\n     (m2_submission[\"label\"] <= 1)).all()\n)\n\nprint(\n    \"Same columns as sample:\",\n    list(m2_submission.columns) == list(sample_submission.columns)\n)\n\nprint(\"\\nFirst 5 rows:\")\ndisplay(m2_submission.head())\n\nprint(\"\\n=== M2 VERIFICATION COMPLETE ===\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T17:50:07.017722Z","iopub.execute_input":"2026-10-08T17:50:07.018185Z","iopub.status.idle":"2026-10-08T17:50:07.033309Z","shell.execute_reply.started":"2026-10-08T17:50:07.018158Z","shell.execute_reply":"2026-10-08T17:50:07.032328Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# FINAL MODEL COMPARISON\n# ============================================\n\nfinal_results = pd.DataFrame({\n    \"Model\": [\n        \"M0 - EfficientNet-B0 Baseline\",\n        \"M1 - EfficientNet-B0 + Augmentation\",\n        \"M2 - EfficientNet-B0 + Fine-Tuning\"\n    ],\n    \"Validation Accuracy\": [\n        0.9924,\n        0.9922,\n        0.9898\n    ],\n    \"Validation Log Loss\": [\n        0.021344,\n        0.025529,\n        0.027192\n    ],\n    \"Kaggle Log Loss\": [\n        0.05908,\n        0.05679,\n        0.05892\n    ]\n})\n\ndisplay(final_results)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T18:20:34.413421Z","iopub.execute_input":"2026-10-08T18:20:34.414228Z","iopub.status.idle":"2026-10-08T18:20:34.425309Z","shell.execute_reply.started":"2026-10-08T18:20:34.414197Z","shell.execute_reply":"2026-10-08T18:20:34.424515Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# BEST MODEL\n# ============================================\n\nbest_model_name = \"M1 - EfficientNet-B0 + Data Augmentation\"\nbest_kaggle_score = 0.05679\n\nprint(\"BEST MODEL:\", best_model_name)\nprint(\"BEST KAGGLE LOG LOSS:\", best_kaggle_score)\nprint(\"LOWER KAGGLE LOG LOSS = BETTER\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T18:22:06.756134Z","iopub.execute_input":"2026-10-08T18:22:06.757133Z","iopub.status.idle":"2026-10-08T18:22:06.762013Z","shell.execute_reply.started":"2026-10-08T18:22:06.7571Z","shell.execute_reply":"2026-10-08T18:22:06.761393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# FINAL CONCLUSION\n# ============================================\n\nprint(\"\"\"\nFINAL CONCLUSION\n================\n\nThree EfficientNet-B0 configurations were trained and evaluated.\n\nM0 used frozen ImageNet-pretrained EfficientNet-B0 as the baseline.\nM1 added data augmentation to improve generalization.\nM2 added fine-tuning of the last 20 EfficientNet layers.\n\nOn the validation set, M0 achieved the highest accuracy of 99.24%.\nHowever, the Kaggle evaluation metric is Log Loss, where a lower\nscore is better.\n\nM1 achieved the best Kaggle Log Loss of 0.05679, compared with\n0.05908 for M0 and 0.05892 for M2.\n\nTherefore, M1 with data augmentation was selected as the final\nbest-performing model based on the Kaggle competition score.\n\nAll three required Kaggle submissions were completed successfully.\n\"\"\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T18:23:06.829031Z","iopub.execute_input":"2026-10-08T18:23:06.829788Z","iopub.status.idle":"2026-10-08T18:23:06.834717Z","shell.execute_reply.started":"2026-10-08T18:23:06.829759Z","shell.execute_reply":"2026-10-08T18:23:06.833853Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# TRAINING TIME SUMMARY\n# ============================================\n\ntraining_times = pd.DataFrame({\n    \"Model\": [\n        \"M0 - Baseline\",\n        \"M1 - Data Augmentation\",\n        \"M2 - Fine-Tuning\"\n    ],\n    \"Training Time (minutes)\": [\n        9.52,\n        10.43,\n        10.87\n    ]\n})\n\ntraining_times[\"Training Time (hours)\"] = (\n    training_times[\"Training Time (minutes)\"] / 60\n)\n\ndisplay(training_times)\n\ntotal_training_minutes = training_times[\"Training Time (minutes)\"].sum()\n\nprint(f\"Total training time: {total_training_minutes:.2f} minutes\")\nprint(f\"Total training time: {total_training_minutes/60:.2f} hours\")\nprint(\"Within 2-hour requirement:\", total_training_minutes <= 120)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T18:23:19.076777Z","iopub.execute_input":"2026-10-08T18:23:19.077366Z","iopub.status.idle":"2026-10-08T18:23:19.090002Z","shell.execute_reply.started":"2026-10-08T18:23:19.077338Z","shell.execute_reply":"2026-10-08T18:23:19.089014Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# ============================================\n# LIBRARY VERSIONS\n# ============================================\n\nimport sys\nimport tensorflow as tf\nimport numpy as np\nimport pandas as pd\nimport sklearn\nimport PIL\n\nprint(\"Python:\", sys.version)\nprint(\"TensorFlow:\", tf.__version__)\nprint(\"NumPy:\", np.__version__)\nprint(\"Pandas:\", pd.__version__)\nprint(\"Scikit-learn:\", sklearn.__version__)\nprint(\"Pillow:\", PIL.__version__)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-10-08T18:23:49.717062Z","iopub.execute_input":"2026-10-08T18:23:49.717852Z","iopub.status.idle":"2026-10-08T18:23:49.723243Z","shell.execute_reply.started":"2026-10-08T18:23:49.717825Z","shell.execute_reply":"2026-10-08T18:23:49.722605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}