{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":30153,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nimport numpy as np\nimport zipfile\nimport shutil\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' # Supress tensorflow log outputs","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2025-10-23T14:39:50.161687Z","iopub.execute_input":"2025-10-23T14:39:50.161879Z","iopub.status.idle":"2025-10-23T14:39:55.291400Z","shell.execute_reply.started":"2025-10-23T14:39:50.161823Z","shell.execute_reply":"2025-10-23T14:39:55.290591Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Unzip train.zip to working directory","metadata":{}},{"cell_type":"code","source":"with zipfile.ZipFile(\"../input/dogs-vs-cats/train.zip\", 'r') as zip_ref:\n    zip_ref.extractall(\"./\")","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:59:52.501621Z","iopub.execute_input":"2025-10-23T14:59:52.502424Z","iopub.status.idle":"2025-10-23T14:59:58.238277Z","shell.execute_reply.started":"2025-10-23T14:59:52.502385Z","shell.execute_reply":"2025-10-23T14:59:58.237670Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### List the files in the train directory\nAs we can see, the files are labelled by the file name. ","metadata":{}},{"cell_type":"code","source":"train_path = \"./train/\"\nprint(len(os.listdir(\"./train\")))\nfor file_name in os.listdir(train_path)[:5]:\n    print(file_name)","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:59:58.239726Z","iopub.execute_input":"2025-10-23T14:59:58.240217Z","iopub.status.idle":"2025-10-23T14:59:58.268777Z","shell.execute_reply.started":"2025-10-23T14:59:58.240175Z","shell.execute_reply":"2025-10-23T14:59:58.268131Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\n\n# Read and display\nimg = mpimg.imread(\"./train/cat.0.jpg\")\nplt.imshow(img)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T14:59:58.269595Z","iopub.execute_input":"2025-10-23T14:59:58.269765Z","iopub.status.idle":"2025-10-23T14:59:58.523025Z","shell.execute_reply.started":"2025-10-23T14:59:58.269743Z","shell.execute_reply":"2025-10-23T14:59:58.522301Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"The required directory structure for [image_dataset_from_directory](https://www.tensorflow.org/api_docs/python/tf/keras/utils/image_dataset_from_directory://) requires a main directory, followed by subfolders ","metadata":{}},{"cell_type":"code","source":"\"\"\"\nCreate following directory structure:\ndataset/\n...dog/\n......dog_image_1.jpg\n......dog_image_2.jpg\n...cat/\n......cat_image_1.jpg\n......cat_image_2.jpg\n\"\"\"\n\nos.makedirs(\"./dataset/dog\")\nos.makedirs(\"./dataset/cat\")\n\nfor file_name in os.listdir(train_path):\n    if \"cat\" in file_name:\n        shutil.move(os.path.join(train_path, file_name), os.path.join(\"./dataset/cat/\", file_name))\n    elif \"dog\" in file_name:\n        shutil.move(os.path.join(train_path, file_name), os.path.join(\"./dataset/dog/\", file_name))","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Create dataset","metadata":{}},{"cell_type":"code","source":"train_dataset = tf.keras.utils.image_dataset_from_directory(\n    \"./dataset\", # root directory given as image_dataset_from_directory requires directory \n    image_size=(150,150),\n    label_mode=\"binary\",\n    validation_split=0.2,\n    subset=\"training\",\n    batch_size=32,\n    seed=1\n)\n\nval_dataset = tf.keras.utils.image_dataset_from_directory(\n    \"./dataset\", # root directory given as image_dataset_from_directory requires directory \n    image_size=(150,150),\n    label_mode=\"binary\",\n    validation_split=0.2,\n    subset=\"validation\",\n    batch_size=32,\n    seed=1\n)\n\nclass_names = train_dataset.class_names\nprint(f\"Found class names: {class_names}\")\n\n# Improve performance of data loading; see: https://www.tensorflow.org/guide/data_performance\nAUTOTUNE = tf.data.AUTOTUNE\ntrain_dataset = train_dataset.cache().prefetch(AUTOTUNE)\nval_dataset = val_dataset.cache().prefetch(AUTOTUNE)","metadata":{"execution":{"iopub.status.busy":"2025-10-23T15:02:30.466443Z","iopub.execute_input":"2025-10-23T15:02:30.466721Z","iopub.status.idle":"2025-10-23T15:02:32.296734Z","shell.execute_reply.started":"2025-10-23T15:02:30.466692Z","shell.execute_reply":"2025-10-23T15:02:32.296072Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### CNN Model with Regularization","metadata":{}},{"cell_type":"code","source":"# Data augmentation layers\ndata_augmentation = keras.Sequential(\n    [\n        layers.RandomFlip(\"horizontal\"),\n        layers.RandomRotation(0.2),\n        layers.RandomZoom(0.2),\n        layers.RandomContrast(0.2)\n    ]\n)","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:48:25.035651Z","iopub.execute_input":"2025-10-23T14:48:25.036394Z","iopub.status.idle":"2025-10-23T14:48:25.072991Z","shell.execute_reply.started":"2025-10-23T14:48:25.036359Z","shell.execute_reply":"2025-10-23T14:48:25.072490Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model = keras.Sequential([\n    layers.Input((150, 150, 3)),\n    data_augmentation,\n    layers.Rescaling(scale=1./255), # rescale between 0 and 1\n    \n    layers.Conv2D(32, 5, activation=\"relu\"),\n    layers.MaxPooling2D(),\n    layers.BatchNormalization(),  \n    \n    layers.Conv2D(64, 3, activation=\"relu\"),\n    layers.MaxPooling2D(),\n    layers.BatchNormalization(),  \n    \n    layers.Conv2D(128, 3, activation=\"relu\"),\n    layers.MaxPooling2D(),\n    layers.BatchNormalization(),  \n    \n    layers.Conv2D(256, 3, activation=\"relu\"),\n    layers.MaxPooling2D(),\n    layers.BatchNormalization(),  \n    \n    layers.Flatten(),\n    \n    layers.Dense(256, activation=\"relu\"),\n    layers.BatchNormalization(), \n    layers.Dropout(0.4),\n    \n    layers.Dense(128, activation=\"relu\"),\n    layers.BatchNormalization(), \n    layers.Dropout(0.3),\n    \n    layers.Dense(64, activation=\"relu\"),\n    layers.BatchNormalization(), \n  \n    layers.Dense(1, activation=\"sigmoid\") # sigmoid for binary classification   \n])","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:48:26.787989Z","iopub.execute_input":"2025-10-23T14:48:26.788628Z","iopub.status.idle":"2025-10-23T14:48:27.205491Z","shell.execute_reply.started":"2025-10-23T14:48:26.788582Z","shell.execute_reply":"2025-10-23T14:48:27.204931Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(\n    optimizer = keras.optimizers.Adam(learning_rate=0.01),\n    loss = keras.losses.BinaryCrossentropy(),\n    metrics=[\"accuracy\"]\n)","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:48:28.496843Z","iopub.execute_input":"2025-10-23T14:48:28.497472Z","iopub.status.idle":"2025-10-23T14:48:28.512557Z","shell.execute_reply.started":"2025-10-23T14:48:28.497439Z","shell.execute_reply":"2025-10-23T14:48:28.511958Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Callbacks ","metadata":{}},{"cell_type":"code","source":"# Add callbacks to minimize validation loss and maximize validation accuracy\nfrom tensorflow.keras.callbacks import EarlyStopping\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\nfrom tensorflow.keras.callbacks import ModelCheckpoint\n\ncallbacks = [\n    EarlyStopping(patience=15, monitor='val_loss', restore_best_weights=True),\n\n\tReduceLROnPlateau(monitor='val_loss', min_lr=1e-7, patience=5, mode='min', verbose=1, factor=0.5),\n\n\tModelCheckpoint(monitor='val_loss', filepath='./best_model.h5', save_best_only=True)\n]","metadata":{"execution":{"iopub.status.busy":"2025-10-23T14:48:29.753692Z","iopub.execute_input":"2025-10-23T14:48:29.753919Z","iopub.status.idle":"2025-10-23T14:48:29.760027Z","shell.execute_reply.started":"2025-10-23T14:48:29.753896Z","shell.execute_reply":"2025-10-23T14:48:29.759282Z"},"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.fit(train_dataset, epochs=15, callbacks=callbacks, validation_data=val_dataset)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T14:51:27.391391Z","iopub.execute_input":"2025-10-23T14:51:27.392060Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_path = \"./dataset/cat/cat.0.jpg\"\n# 1. Load the image and resize it to the target size\nimg = tf.keras.utils.load_img(\n    img_path, target_size=(150, 150)\n)\n\n# 2. Convert the image to a NumPy array\nimg_array = tf.keras.utils.img_to_array(img)\n\n# 3. Add a batch dimension to create a \"batch\" of one image\nimg_batch = tf.expand_dims(img_array, 0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T15:00:37.810973Z","iopub.execute_input":"2025-10-23T15:00:37.811504Z","iopub.status.idle":"2025-10-23T15:00:37.818994Z","shell.execute_reply.started":"2025-10-23T15:00:37.811465Z","shell.execute_reply":"2025-10-23T15:00:37.818378Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"predictions = model.predict(img_batch)\nscore = predictions[0]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T15:00:39.816621Z","iopub.execute_input":"2025-10-23T15:00:39.817354Z","iopub.status.idle":"2025-10-23T15:00:40.042925Z","shell.execute_reply.started":"2025-10-23T15:00:39.817321Z","shell.execute_reply":"2025-10-23T15:00:40.042154Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"print(f\"Class 0: {class_names[0]}\") # e.g., 'cat'\nprint(f\"Class 1: {class_names[1]}\") # e.g., 'dog'\n\nif score > 0.5:\n    prediction_class = class_names[1]\n    prediction_label = 1\nelse:\n    prediction_class = class_names[0]\n    prediction_label = 0\n\nprint(f\"\\nRaw score: {score}\")\nprint(f\"Final prediction: {prediction_class} (Label {prediction_label})\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T15:03:59.775909Z","iopub.execute_input":"2025-10-23T15:03:59.776188Z","iopub.status.idle":"2025-10-23T15:03:59.781902Z","shell.execute_reply.started":"2025-10-23T15:03:59.776158Z","shell.execute_reply":"2025-10-23T15:03:59.781148Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!wget -O \"random_dog_test.jpg\" \"https://cdn.britannica.com/16/234216-050-C66F8665/beagle-hound-dog.jpg?w=300\"","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T15:07:49.091211Z","iopub.execute_input":"2025-10-23T15:07:49.091943Z","iopub.status.idle":"2025-10-23T15:07:50.296549Z","shell.execute_reply.started":"2025-10-23T15:07:49.091908Z","shell.execute_reply":"2025-10-23T15:07:50.295783Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"img_path = \"./random_dog_test.jpg\"\n\nimg = mpimg.imread(img_path)\nplt.imshow(img)\n# 1. Load the image and resize it to the target size\nimg = tf.keras.utils.load_img(\n    img_path, target_size=(150, 150)\n)\n\n# 2. Convert the image to a NumPy array\nimg_array = tf.keras.utils.img_to_array(img)\n\n# 3. Add a batch dimension to create a \"batch\" of one image\nimg_batch = tf.expand_dims(img_array, 0)\n\npredictions = model.predict(img_batch)\nscore = predictions[0]\n\nif score > 0.5:\n    prediction_class = class_names[1]\n    prediction_label = 1\nelse:\n    prediction_class = class_names[0]\n    prediction_label = 0\n\nprint(f\"\\nRaw score: {score}\")\nprint(f\"Final prediction: {prediction_class} (Label {prediction_label})\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-10-23T15:07:50.496354Z","iopub.execute_input":"2025-10-23T15:07:50.497181Z","iopub.status.idle":"2025-10-23T15:07:50.808157Z","shell.execute_reply.started":"2025-10-23T15:07:50.497134Z","shell.execute_reply":"2025-10-23T15:07:50.807394Z"}},"outputs":[],"execution_count":null}]}