{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":31260,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:03.687276Z","iopub.execute_input":"2026-02-03T10:20:03.687581Z","iopub.status.idle":"2026-02-03T10:20:03.693120Z","shell.execute_reply.started":"2026-02-03T10:20:03.687556Z","shell.execute_reply":"2026-02-03T10:20:03.692475Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Creating a project folder\nimport os\nos.makedirs('/kaggle/working/dogs-vs-cats', exist_ok=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:04.195562Z","iopub.execute_input":"2026-02-03T10:20:04.196086Z","iopub.status.idle":"2026-02-03T10:20:04.199659Z","shell.execute_reply.started":"2026-02-03T10:20:04.196058Z","shell.execute_reply":"2026-02-03T10:20:04.198850Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"I created a directory named dogs-vs-cats inside kaggle's working directory and set exist_ok = True ensures no error if the folder already exists.","metadata":{}},{"cell_type":"code","source":"# Unzip the train.zip file\nimport zipfile\n\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/dogs-vs-cats')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:04.289174Z","iopub.execute_input":"2026-02-03T10:20:04.289588Z","iopub.status.idle":"2026-02-03T10:20:13.711947Z","shell.execute_reply.started":"2026-02-03T10:20:04.289551Z","shell.execute_reply":"2026-02-03T10:20:13.711172Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"just opened the train.zip from kaggle's input directory and extracted all training images into my working directory","metadata":{}},{"cell_type":"code","source":"os.listdir('/kaggle/working/dogs-vs-cats')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:13.713158Z","iopub.execute_input":"2026-02-03T10:20:13.713652Z","iopub.status.idle":"2026-02-03T10:20:13.719094Z","shell.execute_reply.started":"2026-02-03T10:20:13.713628Z","shell.execute_reply":"2026-02-03T10:20:13.718550Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"os.listdir('/kaggle/working/dogs-vs-cats/train')[:5]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:13.719935Z","iopub.execute_input":"2026-02-03T10:20:13.720202Z","iopub.status.idle":"2026-02-03T10:20:13.742060Z","shell.execute_reply.started":"2026-02-03T10:20:13.720154Z","shell.execute_reply":"2026-02-03T10:20:13.741564Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Creating a class folder\nbase_dir = '/kaggle/working/dogs-vs-cats/train'\n\nos.makedirs(base_dir + '/cats', exist_ok=True)\nos.makedirs(base_dir + '/dogs', exist_ok=True)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:13.743286Z","iopub.execute_input":"2026-02-03T10:20:13.743479Z","iopub.status.idle":"2026-02-03T10:20:13.747261Z","shell.execute_reply.started":"2026-02-03T10:20:13.743462Z","shell.execute_reply":"2026-02-03T10:20:13.746703Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"created subdirectories per class ","metadata":{}},{"cell_type":"code","source":"# Moving images into correct folders\nimport shutil\n\nfor file in os.listdir(base_dir):\n    path = os.path.join(base_dir, file)\n\n    if os.path.isdir(path):\n        continue\n\n    if file.startswith('cat'):\n        shutil.move(path, base_dir + '/cats/' + file)\n    elif file.startswith('dog'):\n        shutil.move(path, base_dir + '/dogs/' + file)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:13.747951Z","iopub.execute_input":"2026-02-03T10:20:13.748120Z","iopub.status.idle":"2026-02-03T10:20:14.452475Z","shell.execute_reply.started":"2026-02-03T10:20:13.748104Z","shell.execute_reply":"2026-02-03T10:20:14.451640Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Looping through all files in trian/ and moves cat*.jpg -> cats/ and dog*.jpg -> dogs/ ","metadata":{}},{"cell_type":"code","source":"os.listdir('/kaggle/working/dogs-vs-cats/train')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:14.453626Z","iopub.execute_input":"2026-02-03T10:20:14.453931Z","iopub.status.idle":"2026-02-03T10:20:14.458697Z","shell.execute_reply.started":"2026-02-03T10:20:14.453898Z","shell.execute_reply":"2026-02-03T10:20:14.457988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Unzip test.zip file\nimport zipfile, os\n\nos.makedirs('/kaggle/working/dogs-vs-cats/test', exist_ok=True)\n\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/test1.zip', 'r') as zip_ref:\n    zip_ref.extractall('/kaggle/working/dogs-vs-cats/test')\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:14.459714Z","iopub.execute_input":"2026-02-03T10:20:14.459951Z","iopub.status.idle":"2026-02-03T10:20:18.537654Z","shell.execute_reply.started":"2026-02-03T10:20:14.459930Z","shell.execute_reply":"2026-02-03T10:20:18.537076Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Created a test directory and extracted test images which are unlabeled","metadata":{"execution":{"iopub.status.busy":"2026-02-03T05:13:06.497274Z","iopub.execute_input":"2026-02-03T05:13:06.497782Z","iopub.status.idle":"2026-02-03T05:13:06.505028Z","shell.execute_reply.started":"2026-02-03T05:13:06.497742Z","shell.execute_reply":"2026-02-03T05:13:06.503566Z"}}},{"cell_type":"code","source":"# Creating training and validation dataset\nimport tensorflow as tf\n\nDATA_DIR = '/kaggle/working/dogs-vs-cats/train'\n\ntrain_ds = tf.keras.utils.image_dataset_from_directory(\n    DATA_DIR,\n    image_size=(256, 256),\n    batch_size=64,\n    labels='inferred',\n    label_mode='int',\n    validation_split=0.2,\n    subset='training',\n    seed=42\n)\n\nval_ds = tf.keras.utils.image_dataset_from_directory(\n    DATA_DIR,\n    image_size=(256, 256),\n    batch_size=32,\n    labels='inferred',\n    label_mode='int',\n    validation_split=0.2,\n    subset='validation',\n    seed=42\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:18.538466Z","iopub.execute_input":"2026-02-03T10:20:18.538749Z","iopub.status.idle":"2026-02-03T10:20:22.645522Z","shell.execute_reply.started":"2026-02-03T10:20:18.538726Z","shell.execute_reply":"2026-02-03T10:20:22.644946Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras import layers\nfrom tensorflow import keras\nfrom keras import Sequential\nfrom keras.layers import Conv2D , MaxPooling2D , GlobalAveragePooling2D , Dense , BatchNormalization , Dropout","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:22.646387Z","iopub.execute_input":"2026-02-03T10:20:22.646661Z","iopub.status.idle":"2026-02-03T10:20:22.650571Z","shell.execute_reply.started":"2026-02-03T10:20:22.646638Z","shell.execute_reply":"2026-02-03T10:20:22.649835Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Keras preprocessing layers \n# Resizing and Rescaling \nIMG_SIZE = 160\n\nresize_and_rescale = tf.keras.Sequential([\n    layers.Resizing(IMG_SIZE , IMG_SIZE),\n    layers.Rescaling(1./255)\n])\n\n# Data Augmentation\ndata_augmentation = tf.keras.Sequential([\n    tf.keras.layers.RandomFlip(\"horizontal\"),\n    tf.keras.layers.RandomRotation(0.1),\n    tf.keras.layers.RandomZoom(0.1),\n    tf.keras.layers.RandomWidth(0.1),\n    tf.keras.layers.RandomHeight(0.1),\n])\n\n# Making the preprocessing layers part of our model\nmodel = Sequential([\n    tf.keras.Input(shape=(256,256,3)),\n    resize_and_rescale,\n    data_augmentation,\n\n    Conv2D(32, (3,3), padding='same', activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(),\n\n    Conv2D(64, (3,3), padding='same', activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(),\n\n    Conv2D(128, 3, padding='same', activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(),\n\n    Conv2D(256, 3, padding='same', activation='relu'),\n    BatchNormalization(),\n    MaxPooling2D(),\n\n    GlobalAveragePooling2D(),\n\n    Dense(128, activation='relu'),\n    Dropout(0.4),\n    Dense(1, activation='sigmoid')\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:22.652557Z","iopub.execute_input":"2026-02-03T10:20:22.652774Z","iopub.status.idle":"2026-02-03T10:20:23.502310Z","shell.execute_reply.started":"2026-02-03T10:20:22.652755Z","shell.execute_reply":"2026-02-03T10:20:23.501513Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Lowering the learning rate \noptimizer = tf.keras.optimizers.Adam(learning_rate=1e-4)\nmodel.compile(optimizer=optimizer, loss='binary_crossentropy',\n             metrics=['accuracy'])\n# Using Early Stopping\ncallbacks = [\n    tf.keras.callbacks.EarlyStopping(\n        monitor='val_loss',\n        patience=3,\n        restore_best_weights=True\n    ),\n    tf.keras.callbacks.ReduceLROnPlateau(\n        monitor='val_loss',\n        factor=0.2,\n        patience=2\n    )\n]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:23.503267Z","iopub.execute_input":"2026-02-03T10:20:23.503541Z","iopub.status.idle":"2026-02-03T10:20:23.515791Z","shell.execute_reply.started":"2026-02-03T10:20:23.503514Z","shell.execute_reply":"2026-02-03T10:20:23.515177Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:23.516576Z","iopub.execute_input":"2026-02-03T10:20:23.516832Z","iopub.status.idle":"2026-02-03T10:20:23.542696Z","shell.execute_reply.started":"2026-02-03T10:20:23.516812Z","shell.execute_reply":"2026-02-03T10:20:23.542172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time\n\nstart = time.time()\n\nhistory = model.fit(\n    train_ds,\n    validation_data=val_ds,\n    epochs=20,\n    callbacks=callbacks\n)\n\nend = time.time()\n\nprint(f\"Training time: {end - start:.2f} seconds\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:20:23.543434Z","iopub.execute_input":"2026-02-03T10:20:23.543688Z","iopub.status.idle":"2026-02-03T10:40:09.775224Z","shell.execute_reply.started":"2026-02-03T10:20:23.543668Z","shell.execute_reply":"2026-02-03T10:40:09.774618Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"By increasing CNN depth and carefully controlling regularization and learning rate, I improved validation accuracy from ~70% to ~85% while maintaining good generalization, using a CNN trained entirely from scratch.","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.plot(history.history['accuracy'], color='red' , label='train')\nplt.plot(history.history['val_accuracy'], color='blue', label='validation')\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:40:09.776104Z","iopub.execute_input":"2026-02-03T10:40:09.776418Z","iopub.status.idle":"2026-02-03T10:40:09.946118Z","shell.execute_reply.started":"2026-02-03T10:40:09.776393Z","shell.execute_reply":"2026-02-03T10:40:09.945593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.plot(history.history['loss'], color='red' , label='train')\nplt.plot(history.history['val_loss'], color='blue', label='validation')\nplt.legend()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:45:05.825776Z","iopub.execute_input":"2026-02-03T10:45:05.826424Z","iopub.status.idle":"2026-02-03T10:45:05.931149Z","shell.execute_reply.started":"2026-02-03T10:45:05.826393Z","shell.execute_reply":"2026-02-03T10:45:05.930465Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Prediction on test data","metadata":{}},{"cell_type":"code","source":"TEST_DIR = \"/kaggle/working/dogs-vs-cats/test/test1\"\nIMG_SIZE = 160     # same as training\nBATCH_SIZE = 32\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:59:29.571822Z","iopub.execute_input":"2026-02-03T10:59:29.572545Z","iopub.status.idle":"2026-02-03T10:59:29.575925Z","shell.execute_reply.started":"2026-02-03T10:59:29.572513Z","shell.execute_reply":"2026-02-03T10:59:29.575242Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_ds = tf.keras.utils.image_dataset_from_directory(\n    TEST_DIR,\n    image_size=(IMG_SIZE, IMG_SIZE),\n    batch_size=BATCH_SIZE,\n    shuffle=False,      \n    labels=None\n)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:59:31.447660Z","iopub.execute_input":"2026-02-03T10:59:31.447942Z","iopub.status.idle":"2026-02-03T10:59:31.698627Z","shell.execute_reply.started":"2026-02-03T10:59:31.447917Z","shell.execute_reply":"2026-02-03T10:59:31.698038Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\nimage_files = sorted(\n    [f for f in os.listdir(TEST_DIR) if f.endswith(\".jpg\")],\n    key=lambda x: int(x.split(\".\")[0])\n)\n\nimage_ids = [int(f.split(\".\")[0]) for f in image_files]\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T10:59:56.566710Z","iopub.execute_input":"2026-02-03T10:59:56.567388Z","iopub.status.idle":"2026-02-03T10:59:56.589387Z","shell.execute_reply.started":"2026-02-03T10:59:56.567348Z","shell.execute_reply":"2026-02-03T10:59:56.588691Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = model.predict(test_ds)\npredicted_labels = (predictions > 0.5).astype(int).reshape(-1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:00:25.376462Z","iopub.execute_input":"2026-02-03T11:00:25.377002Z","iopub.status.idle":"2026-02-03T11:00:31.194785Z","shell.execute_reply.started":"2026-02-03T11:00:25.376973Z","shell.execute_reply":"2026-02-03T11:00:31.194231Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = model.predict(test_ds)\npredicted_labels = (predictions > 0.5).astype(int).reshape(-1)\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:00:40.482484Z","iopub.execute_input":"2026-02-03T11:00:40.482743Z","iopub.status.idle":"2026-02-03T11:00:46.343103Z","shell.execute_reply.started":"2026-02-03T11:00:40.482722Z","shell.execute_reply":"2026-02-03T11:00:46.342541Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(image_ids[:5])\nprint(predicted_labels[:5])\nprint(len(image_ids), len(predicted_labels))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:01:02.956576Z","iopub.execute_input":"2026-02-03T11:01:02.957210Z","iopub.status.idle":"2026-02-03T11:01:02.961748Z","shell.execute_reply.started":"2026-02-03T11:01:02.957162Z","shell.execute_reply":"2026-02-03T11:01:02.960993Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nlabel_map = {0: \"cat\", 1: \"dog\"}\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:02:04.283727Z","iopub.execute_input":"2026-02-03T11:02:04.284463Z","iopub.status.idle":"2026-02-03T11:02:04.289907Z","shell.execute_reply.started":"2026-02-03T11:02:04.284432Z","shell.execute_reply":"2026-02-03T11:02:04.288939Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport os\n\n# show first N images\nN = 5\n\nplt.figure(figsize=(15, 5))\n\nfor i in range(N):\n    img_path = os.path.join(TEST_DIR, image_files[i])\n    img = plt.imread(img_path)\n\n    plt.subplot(1, N, i + 1)\n    plt.imshow(img)\n    plt.axis(\"off\")\n    plt.title(f\"ID: {image_ids[i]}\\nPred: {label_map[predicted_labels[i]]}\")\n\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:02:09.945669Z","iopub.execute_input":"2026-02-03T11:02:09.945949Z","iopub.status.idle":"2026-02-03T11:02:10.255526Z","shell.execute_reply.started":"2026-02-03T11:02:09.945925Z","shell.execute_reply":"2026-02-03T11:02:10.254709Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(predictions[:5].reshape(-1))\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-02-03T11:04:13.524805Z","iopub.execute_input":"2026-02-03T11:04:13.525330Z","iopub.status.idle":"2026-02-03T11:04:13.529879Z","shell.execute_reply.started":"2026-02-03T11:04:13.525298Z","shell.execute_reply":"2026-02-03T11:04:13.529172Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}