{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","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":30646,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Importing Libraries","metadata":{}},{"cell_type":"markdown","source":"This code cell is responsible for importing the required libraries and setting the random seed for both NumPy and TensorFlow to ensure reproducibility. The imported libraries include TensorFlow for deep learning tasks, pandas for data manipulation, and various image processing libraries such as Matplotlib, PIL, and scikit-learn.\n\n**Key Components and Actions:**\n- Importing essential libraries for machine learning and image processing.\n- Setting random seeds to achieve reproducibility.\n- Exploring the Kaggle input directory structure.\n\nThe random seed setting ensures that the randomness in the model training process remains consistent across different runs, facilitating reproducibility.\n","metadata":{}},{"cell_type":"code","source":"import numpy as np\nimport tensorflow as tf\n\n# Set random seed for NumPy\nnp.random.seed(42)\n\n# Set random seed for TensorFlow\ntf.random.set_seed(42)\n\nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nfrom PIL import Image\nimport random\nimport shutil\nimport seaborn as sns\nsns.set()\n\nfrom sklearn.metrics import classification_report, confusion_matrix\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.utils import image_dataset_from_directory\nfrom tensorflow.keras.layers import Dense, Conv2D, MaxPooling2D, Flatten, BatchNormalization, Dropout\nfrom tensorflow.keras.layers import RandomFlip, RandomRotation, RandomZoom, RandomBrightness, Rescaling, RandomTranslation, RandomWidth, RandomHeight\nfrom tensorflow.keras.models import Sequential, Model\nfrom tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\nfrom tensorflow.keras.regularizers import L2\nfrom tensorflow.keras.applications import VGG16\nfrom tensorflow.keras.applications.vgg16 import preprocess_input\nfrom tensorflow.keras.preprocessing import image\nfrom tensorflow.keras.optimizers import Adamax\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:16:52.981696Z","iopub.execute_input":"2024-03-09T10:16:52.982037Z","iopub.status.idle":"2024-03-09T10:17:06.088300Z","shell.execute_reply.started":"2024-03-09T10:16:52.982008Z","shell.execute_reply":"2024-03-09T10:17:06.087275Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This function, `plot_history`, visualizes the training and validation performance over epochs. It takes the `history` object containing metrics like accuracy and loss.\n\n**Purpose:**\n- **Input:** `history` - The training history object returned by the `fit` function in TensorFlow.\n- **Output:** Displays two subplots, one for accuracy and one for loss, illustrating the training and validation trends over epochs.","metadata":{}},{"cell_type":"code","source":"def plot_history(history):\n    \n    epochs_range = range(1, len(history.history['loss'])+1)\n    \n    # plot accuracy curves\n    plt.figure(figsize=(12, 5))\n    plt.subplot(1, 2, 1)\n    plt.plot(epochs_range, history.history['accuracy'], label='Training Accuracy')\n    plt.plot(epochs_range, history.history['val_accuracy'], label='Validation Accuracy')\n    plt.legend(loc='lower right')\n    plt.title('Training and Validation Accuracy')\n\n    # plot loss curves\n    plt.subplot(1, 2, 2)\n    plt.plot(epochs_range, history.history['loss'], label='Training Loss')\n    plt.plot(epochs_range, history.history['val_loss'], label='Validation Loss')\n    plt.legend(loc='upper right')\n    plt.title('Training and Validation Loss')\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:06.090347Z","iopub.execute_input":"2024-03-09T10:17:06.091658Z","iopub.status.idle":"2024-03-09T10:17:06.099440Z","shell.execute_reply.started":"2024-03-09T10:17:06.091624Z","shell.execute_reply":"2024-03-09T10:17:06.098593Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset Organization","metadata":{}},{"cell_type":"markdown","source":"**Key Components and Actions:**\n- `unzip_path`: The destination path for extracting the dataset.\n- Checks if the destination folder exists. If not:\n  - Uses the `!unzip` command to extract the contents of 'train.zip' to '/kaggle/working/train'.\n  - Prints 'File Unzipped Successfully' upon successful extraction.\n","metadata":{}},{"cell_type":"code","source":"unzip_path = '/kaggle/working/train'\n\nif not os.path.exists(unzip_path):\n    !unzip -q /kaggle/input/dogs-vs-cats/train.zip\n    print('File Unzipped Successfully')","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:06.105191Z","iopub.execute_input":"2024-03-09T10:17:06.105612Z","iopub.status.idle":"2024-03-09T10:17:21.127743Z","shell.execute_reply.started":"2024-03-09T10:17:06.105576Z","shell.execute_reply":"2024-03-09T10:17:21.126465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img_list = os.listdir(unzip_path)\nlen(img_list)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:21.129252Z","iopub.execute_input":"2024-03-09T10:17:21.129565Z","iopub.status.idle":"2024-03-09T10:17:21.155352Z","shell.execute_reply.started":"2024-03-09T10:17:21.129524Z","shell.execute_reply":"2024-03-09T10:17:21.154301Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Alright, let's get our dataset organized! This code cell creates a directory structure to neatly arrange our training and validation sets with categories for 'cats' and 'dogs.' The root directory is '/kaggle/working/parent,' and if it doesn't exist, we'll make it.\n\n**Key Components and Actions:**\n- `parent_path`: The root directory for our organized dataset.\n- Attempts to create the 'parent' directory and its subdirectories ('training', 'validation').\n- Prints messages to let us know when each directory is successfully created.\n- We then have nested loops to create subdirectories for 'cats' and 'dogs' within both training and validation sets.\n","metadata":{}},{"cell_type":"code","source":"parent_path = '/kaggle/working/parent'\ntry:\n    os.mkdir(parent_path)\n    for path in ['training', 'validation']:\n        path = os.path.join(parent_path,path)\n        os.mkdir(path)\n        print(path,'is created')\n        for category in ['cats','dogs']:\n            new_path = os.path.join(path, category)\n            os.mkdir(new_path)\n            print(new_path,'is created')\nexcept OSError:\n    print('The Folder exists already')","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:21.156701Z","iopub.execute_input":"2024-03-09T10:17:21.157069Z","iopub.status.idle":"2024-03-09T10:17:21.164398Z","shell.execute_reply.started":"2024-03-09T10:17:21.157032Z","shell.execute_reply":"2024-03-09T10:17:21.163557Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cats_images = [img for img in img_list if img.startswith('cat')]\ndogs_images = [img for img in img_list if img.startswith('dog')]\nlen(cats_images), len(dogs_images)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:21.165730Z","iopub.execute_input":"2024-03-09T10:17:21.166065Z","iopub.status.idle":"2024-03-09T10:17:21.182807Z","shell.execute_reply.started":"2024-03-09T10:17:21.166036Z","shell.execute_reply":"2024-03-09T10:17:21.181831Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Time to split our dataset into training and validation sets for both cats and dogs. Let's shuffle the lists of cat and dog images and then split them. We'll also move the images to their designated training and validation directories.\n\n**Key Components and Actions:**\n- `cats_images` and `dogs_images`: Lists of cat and dog images from the dataset.\n- Shuffling the lists to introduce randomness.\n- Splitting the lists into training and validation sets based on a threshold.\n- Defining destination folders for training and validation images.\n- Using `shutil.move` to relocate images to their respective directories.","metadata":{}},{"cell_type":"code","source":"# shuffle the lists of images\nnp.random.shuffle(cats_images)\nnp.random.shuffle(dogs_images)\n\n# split the lists into train and validation\nthreshold = int(0.9 * len(cats_images))\ntrain_cats, validation_cats = np.split(cats_images, [threshold])\ntrain_dogs, validation_dogs = np.split(dogs_images, [threshold])\n\n# define images destination folders\ntrain_cats_path = '/kaggle/working/parent/training/cats'\ntrain_dogs_path = '/kaggle/working/parent/training/dogs'\nvalidation_cats_path = '/kaggle/working/parent/validation/cats'\nvalidation_dogs_path = '/kaggle/working/parent/validation/dogs'\n\n# Move images to training directories\nfor i in range(threshold):\n    \n    src_path_cats = os.path.join(unzip_path, train_cats[i])\n    src_path_dogs = os.path.join(unzip_path, train_dogs[i])\n    \n    dest_path_cats = os.path.join(train_cats_path, train_cats[i])\n    dest_path_dogs = os.path.join(train_dogs_path, train_dogs[i])\n    \n    shutil.move(src_path_cats, dest_path_cats)\n    shutil.move(src_path_dogs, dest_path_dogs)\n    \n# Move images to validation directories\nfor i in range(threshold, len(cats_images)):\n    src_path_cats = os.path.join(unzip_path, validation_cats[i - threshold])\n    src_path_dogs = os.path.join(unzip_path, validation_dogs[i - threshold])\n    \n    dest_path_cats = os.path.join(validation_cats_path, validation_cats[i - threshold])\n    dest_path_dogs = os.path.join(validation_dogs_path, validation_dogs[i - threshold])\n    \n    shutil.move(src_path_cats, dest_path_cats)\n    shutil.move(src_path_dogs, dest_path_dogs)\n\nprint('Number of cats in training directory: ', len(os.listdir(train_cats_path)))\nprint('Number of cats in validation directory: ', len(os.listdir(validation_cats_path)))\nprint('Number of dogs in training directory: ', len(os.listdir(train_dogs_path)))\nprint('Number of dogs in validation directory: ', len(os.listdir(validation_dogs_path)))","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:21.186216Z","iopub.execute_input":"2024-03-09T10:17:21.186700Z","iopub.status.idle":"2024-03-09T10:17:22.127786Z","shell.execute_reply.started":"2024-03-09T10:17:21.186676Z","shell.execute_reply":"2024-03-09T10:17:22.126838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Visualization","metadata":{}},{"cell_type":"markdown","source":"Let's take a sneak peek at some training images. \n\n**Key Components and Actions:**\n- `fig, ax`: Matplotlib objects for creating subplots.\n- Looping to display eight randomly chosen images.\n- Randomly selecting images from the training dataset and using `Image.open` to open and display them.\n- Turning off axis for a cleaner presentation.","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(2,4,figsize=(20,12))\nfor i in range(8):\n    img_filename = random.choice(train_cats)\n    img_path = os.path.join(train_cats_path, img_filename)\n    img = Image.open(img_path)\n    ax[i//4, i%4].imshow(img)\n    ax[i//4, i%4].axis('off')","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:22.129217Z","iopub.execute_input":"2024-03-09T10:17:22.129610Z","iopub.status.idle":"2024-03-09T10:17:23.861454Z","shell.execute_reply.started":"2024-03-09T10:17:22.129577Z","shell.execute_reply":"2024-03-09T10:17:23.860209Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"fig, ax = plt.subplots(2,4,figsize=(20,12))\nfor i in range(8):\n    img_filename = random.choice(train_dogs)\n    img_path = os.path.join(train_dogs_path, img_filename)\n    img = Image.open(img_path)\n    ax[i//4, i%4].imshow(img)\n    ax[i//4, i%4].axis('off')","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:23.865199Z","iopub.execute_input":"2024-03-09T10:17:23.865897Z","iopub.status.idle":"2024-03-09T10:17:25.531377Z","shell.execute_reply.started":"2024-03-09T10:17:23.865863Z","shell.execute_reply":"2024-03-09T10:17:25.530101Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Setting Up Image Data Generators","metadata":{}},{"cell_type":"code","source":"BATCH_SIZE = 64\nWIDTH = 150\nHEIGHT = 150\nCHANNELS = 3","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:25.532870Z","iopub.execute_input":"2024-03-09T10:17:25.533164Z","iopub.status.idle":"2024-03-09T10:17:25.537585Z","shell.execute_reply.started":"2024-03-09T10:17:25.533140Z","shell.execute_reply":"2024-03-09T10:17:25.536571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This code cell defines paths to the training and validation directories and initializes image data generators using TensorFlow's `image_dataset_from_directory` function.\n\n**Key Components and Actions:**\n- `train_dir` and `validation_dir`: Paths to the training and validation directories.\n- The function creates data generators for training and validation datasets.\n- Parameters include:\n  - `labels='inferred'`: Inferring labels from the directory structure.\n  - `label_mode='binary'`: Binary classification labels.\n  - `color_mode='rgb'`: Using RGB color mode for images.\n  - `image_size=(HEIGHT, WIDTH)`: Specifying image dimensions.\n  - `batch_size=BATCH_SIZE`: Setting batch size for training and validation.\n","metadata":{}},{"cell_type":"code","source":"# Define paths to training and validation directories\ntrain_dir = '/kaggle/working/parent/training'\nvalidation_dir = '/kaggle/working/parent/validation'\n\n# training data generator\ntrain_ds = image_dataset_from_directory(\n    train_dir,\n    labels='inferred',\n    label_mode='binary',\n    color_mode='rgb',\n    image_size=(HEIGHT,WIDTH),\n    batch_size=BATCH_SIZE\n)\n\n# validation data generator\nvalidation_ds = image_dataset_from_directory(\n    validation_dir,\n    labels='inferred',\n    label_mode='binary',\n    color_mode='rgb',\n    image_size=(HEIGHT,WIDTH),\n    batch_size=BATCH_SIZE\n)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:25.538759Z","iopub.execute_input":"2024-03-09T10:17:25.539040Z","iopub.status.idle":"2024-03-09T10:17:29.346635Z","shell.execute_reply.started":"2024-03-09T10:17:25.539007Z","shell.execute_reply":"2024-03-09T10:17:29.345875Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = train_ds.class_names\n\nplt.figure(figsize=(20, 8))\nfor images, labels in train_ds.take(1):\n    for i in range(8):\n        ax = plt.subplot(2, 4, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"))\n        plt.title(class_names[int(labels[i])][:3])\n        plt.axis(\"off\")       ","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:29.348144Z","iopub.execute_input":"2024-03-09T10:17:29.348544Z","iopub.status.idle":"2024-03-09T10:17:31.645149Z","shell.execute_reply.started":"2024-03-09T10:17:29.348497Z","shell.execute_reply":"2024-03-09T10:17:31.644017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_names = validation_ds.class_names\n\nplt.figure(figsize=(20, 8))\nfor images, labels in validation_ds.take(1):\n    for i in range(8):\n        ax = plt.subplot(2, 4, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"))\n        plt.title(class_names[int(labels[i])][:3])\n        plt.axis(\"off\")       ","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:17:31.646338Z","iopub.execute_input":"2024-03-09T10:17:31.646667Z","iopub.status.idle":"2024-03-09T10:17:33.871131Z","shell.execute_reply.started":"2024-03-09T10:17:31.646639Z","shell.execute_reply":"2024-03-09T10:17:33.870150Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Using `prefetch()` prevents a memory bottleneck that can occur when reading from disk. It sets aside some data and keeps it ready for when it's needed, by creating a source dataset from your input data, applying a transformation to preprocess it, then iterating over the dataset one element at a time. Because the iteration is streaming, the data doesn't need to fit into memory.\n\nYou can set the number of elements to prefetch manually, or you can use `tf.data.experimental.AUTOTUNE` to choose the parameters automatically. Autotune prompts `tf.data` to tune that value dynamically at runtime, by tracking the time spent in each operation and feeding those times into an optimization algorithm. The optimization algorithm tries to find the best allocation of its CPU budget across all tunable operations. \n\n**Source:** Convolutional Neural Network at coursera by andrew ng - Week 2 (Assignment 2)","metadata":{}},{"cell_type":"code","source":"AUTOTUNE = tf.data.experimental.AUTOTUNE\ntrain_ds = train_ds.prefetch(buffer_size=AUTOTUNE)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:25:34.647478Z","iopub.execute_input":"2024-03-09T10:25:34.647923Z","iopub.status.idle":"2024-03-09T10:25:34.657057Z","shell.execute_reply.started":"2024-03-09T10:25:34.647884Z","shell.execute_reply":"2024-03-09T10:25:34.653974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Defining Callbacks","metadata":{}},{"cell_type":"markdown","source":"Here, we define a callback using TensorFlow's `EarlyStopping` to help monitor the model during training.\n\n**Key Components and Actions:**\n- `early_stopping`: Early stopping callback to halt training if a monitored metric (in this case, 'val_loss') stops improving.\n  - `monitor='val_loss'`: The metric to monitor.\n  - `patience=5`: Number of epochs with no improvement before stopping.\n  - `min_delta=0.001`: Minimum change to qualify as an improvement.\n  - `restore_best_weights=True`: Restores the model weights from the epoch with the best value of the monitored metric.","metadata":{}},{"cell_type":"code","source":"# define callbacks\nearly_stopping = EarlyStopping(monitor='val_loss', patience=5, min_delta=0.001, restore_best_weights=True)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:28:44.251142Z","iopub.execute_input":"2024-03-09T10:28:44.251899Z","iopub.status.idle":"2024-03-09T10:28:44.256438Z","shell.execute_reply.started":"2024-03-09T10:28:44.251857Z","shell.execute_reply":"2024-03-09T10:28:44.255413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Convolutional Neural Network","metadata":{}},{"cell_type":"markdown","source":"Here, we define the architecture of a Convolutional Neural Network (CNN) using TensorFlow's Sequential API.\n\n**Key Components and Actions:**\n- `Rescaling`: Normalizes pixel values to the range [0,1].\n- Three convolutional layers with max-pooling for feature extraction:\n  - 32 filters with a 3x3 kernel, followed by max-pooling.\n  - 64 filters with a 3x3 kernel, followed by max-pooling.\n  - 128 filters with a 3x3 kernel, followed by max-pooling.\n- Flatten layer to transform the 3D output to 1D.\n- Dense layers for classification:\n  - Two hidden layers with 128 and 64 neurons, using ReLU activation.\n  - Output layer with 1 neuron and sigmoid activation for binary classification.\n","metadata":{}},{"cell_type":"code","source":"# CNN architecture\ncnn = Sequential(\n    [\n        Rescaling(1./255, input_shape=(HEIGHT, WIDTH, CHANNELS)),\n        \n        Conv2D(32, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Conv2D(64, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Conv2D(128, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Flatten(),\n        Dense(128, activation='relu'),\n        Dense(64, activation='relu'),\n        Dense(1, activation='sigmoid')\n    ]\n)\n\n# compile the model \ncnn.compile(optimizer='adamax', loss='binary_crossentropy', metrics=['accuracy'])\n\n# model summary\ncnn.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-04T09:05:18.411739Z","iopub.execute_input":"2024-03-04T09:05:18.412013Z","iopub.status.idle":"2024-03-04T09:05:18.606333Z","shell.execute_reply.started":"2024-03-04T09:05:18.411990Z","shell.execute_reply":"2024-03-04T09:05:18.605441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = cnn.fit(train_ds, validation_data=validation_ds, epochs=30, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2024-03-04T09:05:18.607461Z","iopub.execute_input":"2024-03-04T09:05:18.607771Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Training Accuracy: \", cnn.evaluate(train_ds, verbose=None)[1])\nprint(\"Validation Accuracy: \", cnn.evaluate(validation_ds, verbose=None)[1])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The current CNN model demonstrates promising performance. Here's a brief analysis:\n\n**Observations:**\n- The model shows good generalization to unseen data, as the validation accuracy is relatively close to the training accuracy.\n- However, there is a noticeable accuracy gap between training and validation, indicating potential overfitting.\n\n**Next Steps:**\n- Consider building a more complex model to address underfitting.\n- Possible strategies include adding dropout layers, introducing regularization, or exploring more advanced architectures such as transfer learning with pre-trained models.","metadata":{}},{"cell_type":"markdown","source":"# Enhanced CNN Architecture","metadata":{}},{"cell_type":"markdown","source":"To address overfitting and further improve model generalization, we've enhanced the CNN architecture by incorporating regularization techniques. Here's a breakdown of the updated model:\n\n**Key Modifications:**\n- **Batch Normalization:** Applied after each convolutional layer to stabilize and accelerate training.\n- **L2 Regularization:** Added to dense layers for weight regularization (reducing overfitting).\n- **Dropout Layers:** Introduced after dense layers to randomly deactivate neurons during training, preventing co-adaptation.\n\n**Enhanced Layers:**\n- Four convolutional layers with batch normalization and max-pooling for feature extraction.\n- Three dense layers with L2 regularization, dropout, and batch normalization for classification.\n- Output layer with sigmoid activation for binary classification.\n\n**Note:**\n- Batch normalization, L2 regularization, and dropout collectively contribute to improved model robustness and generalization.\n- Adjust hyperparameters like dropout rate, regularization strength, and layer units based on experimentation.","metadata":{}},{"cell_type":"code","source":"# CNN architecture\ncnn_reg = Sequential(\n    [\n        Rescaling(1./255, input_shape=(HEIGHT, WIDTH, CHANNELS)),\n        \n        Conv2D(32, (3,3), activation='relu'),\n        BatchNormalization(),\n        MaxPooling2D(2,2),\n        \n        Conv2D(64, (3,3), activation='relu'),\n        BatchNormalization(),\n        MaxPooling2D(2,2),\n        \n        Conv2D(128, (3,3), activation='relu'),\n        BatchNormalization(),\n        MaxPooling2D(2,2),\n        \n        Conv2D(128, (3,3), activation='relu'),\n        BatchNormalization(),\n        MaxPooling2D(2,2),\n        \n        Flatten(),\n        \n        Dense(256, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(128, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(64, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(1, activation='sigmoid')\n    ]\n)\n\n# compile the model \ncnn_reg.compile(optimizer='adamax', loss='binary_crossentropy', metrics=['accuracy'])\n\n# model summary\ncnn_reg.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-03T12:41:22.845532Z","iopub.execute_input":"2024-03-03T12:41:22.845907Z","iopub.status.idle":"2024-03-03T12:41:23.178070Z","shell.execute_reply.started":"2024-03-03T12:41:22.845872Z","shell.execute_reply":"2024-03-03T12:41:23.177133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_reg = cnn_reg.fit(train_ds, validation_data=validation_ds, epochs=30, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2024-03-03T12:41:26.551517Z","iopub.execute_input":"2024-03-03T12:41:26.552333Z","iopub.status.idle":"2024-03-03T12:45:19.823433Z","shell.execute_reply.started":"2024-03-03T12:41:26.552304Z","shell.execute_reply":"2024-03-03T12:45:19.822397Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history_reg)","metadata":{"execution":{"iopub.status.busy":"2024-03-03T12:45:31.044641Z","iopub.execute_input":"2024-03-03T12:45:31.048112Z","iopub.status.idle":"2024-03-03T12:45:31.620174Z","shell.execute_reply.started":"2024-03-03T12:45:31.048079Z","shell.execute_reply":"2024-03-03T12:45:31.619201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Training Accuracy: \", cnn_reg.evaluate(train_ds, verbose=None)[1])\nprint(\"Validation Accuracy: \", cnn_reg.evaluate(validation_ds, verbose=None)[1])","metadata":{"execution":{"iopub.status.busy":"2024-03-03T12:45:39.839568Z","iopub.execute_input":"2024-03-03T12:45:39.840312Z","iopub.status.idle":"2024-03-03T12:45:51.297430Z","shell.execute_reply.started":"2024-03-03T12:45:39.840283Z","shell.execute_reply":"2024-03-03T12:45:51.296309Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The enhancements to the CNN architecture have yielded notable improvements in model performance:\n\n**Observations:**\n- The model exhibits enhanced training accuracy.\n- Validation accuracy has also improved significantly.\n- The performance gap between training and validation has narrowed, indicating reduced overfitting.\n\n**Next Steps:**\n- To further enhance the model's robustness and improve its ability to generalize, we consider incorporating data augmentation into the training pipeline. Data augmentation involves applying random transformations to existing training images, creating diverse variations for the model to learn from.\n","metadata":{}},{"cell_type":"markdown","source":"# Data Augmentation","metadata":{}},{"cell_type":"markdown","source":"In this iteration, we've incorporated data augmentation directly into the model architecture to augment the training dataset on-the-fly. Here's a summary of the updated model:\n\n**Key Components and Actions:**\n- `data_augmentation`: Sequential layer integrating various data augmentation techniques.\n  - Horizontal flipping, random rotation, random zoom, random brightness adjustments.\n  - Rescaling to normalize pixel values.\n- CNN architecture includes the data augmentation layer at the beginning.\n- Convolutional layers, dense layers, and regularization techniques remain consistent.\n\n**Benefits of Data Augmentation in Model:**\n- Augmentation is applied dynamically during training, providing a broader set of training examples.\n- Enhances model generalization by exposing it to various augmented image variations.\n- Mitigates overfitting by presenting diverse perspectives of the data to the model.","metadata":{}},{"cell_type":"code","source":"# data augmentation layers\ndata_augmentation = Sequential(\n    [\n        RandomFlip(\"horizontal\", seed=42),\n        RandomRotation(0.2, seed=42),\n        RandomZoom(0.2, seed=42),\n        RandomBrightness(0.2, seed=42),\n        Rescaling(1./255, input_shape=(HEIGHT, WIDTH, CHANNELS))\n    ]\n)\n\n# CNN architecture\ncnn_aug = Sequential(\n    [\n        data_augmentation,\n        \n        Conv2D(32, (3,3), activation='relu'),\n        MaxPooling2D(2, 2),\n        \n        Conv2D(64, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Conv2D(128, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Conv2D(128, (3,3), activation='relu'),\n        MaxPooling2D(2,2),\n        \n        Flatten(),\n        \n        Dense(256, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(128, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(64, activation='relu', kernel_regularizer=L2(0.15)),\n        Dropout(rate=0.4, seed=42),\n        BatchNormalization(),\n        \n        Dense(1, activation='sigmoid')\n    ]\n)\n\n# Explicitly build the model and specify input shape\ncnn_aug.build((None, HEIGHT, WIDTH, CHANNELS))\n\n# compile the model \ncnn_aug.compile(optimizer='adamax', loss='binary_crossentropy', metrics=['accuracy'])\n\n# model summary\ncnn_aug.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-03T18:55:11.720980Z","iopub.execute_input":"2024-03-03T18:55:11.721722Z","iopub.status.idle":"2024-03-03T18:55:12.396803Z","shell.execute_reply.started":"2024-03-03T18:55:11.721689Z","shell.execute_reply":"2024-03-03T18:55:12.395880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_aug = cnn_aug.fit(train_ds, validation_data=validation_ds, epochs=50, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2024-03-03T13:30:00.442669Z","iopub.execute_input":"2024-03-03T13:30:00.443566Z","iopub.status.idle":"2024-03-03T13:36:18.166294Z","shell.execute_reply.started":"2024-03-03T13:30:00.443529Z","shell.execute_reply":"2024-03-03T13:36:18.165446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history_aug)","metadata":{"execution":{"iopub.status.busy":"2024-03-03T13:38:02.933621Z","iopub.execute_input":"2024-03-03T13:38:02.933963Z","iopub.status.idle":"2024-03-03T13:38:03.493024Z","shell.execute_reply.started":"2024-03-03T13:38:02.933940Z","shell.execute_reply":"2024-03-03T13:38:03.492075Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Training Accuracy: \", cnn_aug.evaluate(train_ds, verbose=None)[1])\nprint(\"Validation Accuracy: \", cnn_aug.evaluate(validation_ds, verbose=None)[1])","metadata":{"execution":{"iopub.status.busy":"2024-03-03T15:14:24.364588Z","iopub.execute_input":"2024-03-03T15:14:24.365503Z","iopub.status.idle":"2024-03-03T15:14:24.702032Z","shell.execute_reply.started":"2024-03-03T15:14:24.365465Z","shell.execute_reply":"2024-03-03T15:14:24.700741Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The model trained with data augmentation has demonstrated commendable performance, with the following results:\n\n**Observations:**\n- The model exhibits improved generalization with a reduced performance gap between training and validation sets.\n- Both training and validation accuracies are solid, indicating that data augmentation has contributed to a more robust model.\n\n**Benefits of Data Augmentation:**\n- **Improved Generalization:** Augmenting the dataset with variations has helped the model handle diverse scenarios.\n- **Reduced Overfitting:** The smaller gap between training and validation accuracies indicates better generalization.\n","metadata":{}},{"cell_type":"markdown","source":"# Transfer Learning with VGG-16","metadata":{}},{"cell_type":"markdown","source":"In the pursuit of achieving even higher performance, we've incorporated transfer learning using the VGG16 architecture. Here are the key steps and details:\n\n**Transfer Learning Process:**\n1. **Instantiation of the Base Model:** We utilize the pre-trained VGG16 model with weights from ImageNet and exclude the top classification layers.\n2. **Freezing CNN Layers:** The layers of the VGG16 base model are frozen, preventing them from being updated during training.\n3. **Model Architecture:** A new Sequential model is constructed on top of the frozen VGG16 base. This includes flattening the output and adding densely connected layers.\n4. **Compilation:** The model is compiled using the 'adamax' optimizer and binary crossentropy loss for binary classification.\n\n**Model Architecture:**\n- The VGG16 base model followed by three dense layers with dropout for classification.\n- The dense layers facilitate the model in learning task-specific patterns while leveraging pre-trained features from VGG16.\n\n**Benefits of Transfer Learning:**\n- **Knowledge Transfer:** Leveraging pre-trained features from VGG16 can benefit the model in recognizing complex patterns.\n- **Reduced Training Time:** Utilizing pre-trained weights reduces the need for extensive training on the new dataset.\n","metadata":{}},{"cell_type":"code","source":"# instantiate the base model\nbase_model = VGG16(weights='imagenet', include_top=False, input_shape=(WIDTH, HEIGHT, CHANNELS))\n\n# Freezing the CNN layers\nfor layer in base_model.layers:\n    layer.trainable = False\n    \n# Base model summary\nbase_model.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:31:15.639723Z","iopub.execute_input":"2024-03-09T10:31:15.640159Z","iopub.status.idle":"2024-03-09T10:31:19.674077Z","shell.execute_reply.started":"2024-03-09T10:31:15.640124Z","shell.execute_reply":"2024-03-09T10:31:19.672752Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# CNN architecture\nmodel_vgg = Sequential(\n    [\n        base_model,\n        Flatten(),\n        Dense(512, activation='relu'),\n        Dropout(0.3),\n        Dense(256, activation='relu'),\n        Dropout(0.3),\n        Dense(1, activation='sigmoid')\n    ]\n)\n\n# compile the model \nmodel_vgg.compile(optimizer='adamax', loss='binary_crossentropy', metrics=['accuracy'])\n\n# model summary\nmodel_vgg.summary()","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:31:19.676235Z","iopub.execute_input":"2024-03-09T10:31:19.676626Z","iopub.status.idle":"2024-03-09T10:31:19.853351Z","shell.execute_reply.started":"2024-03-09T10:31:19.676593Z","shell.execute_reply":"2024-03-09T10:31:19.852441Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_vgg = model_vgg.fit(train_ds, validation_data=validation_ds, epochs=50, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:31:20.090590Z","iopub.execute_input":"2024-03-09T10:31:20.090945Z","iopub.status.idle":"2024-03-09T10:36:19.563656Z","shell.execute_reply.started":"2024-03-09T10:31:20.090916Z","shell.execute_reply":"2024-03-09T10:36:19.562595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history_vgg)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:36:19.565313Z","iopub.execute_input":"2024-03-09T10:36:19.565649Z","iopub.status.idle":"2024-03-09T10:36:20.101320Z","shell.execute_reply.started":"2024-03-09T10:36:19.565622Z","shell.execute_reply":"2024-03-09T10:36:20.100316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Training Accuracy: \", model_vgg.evaluate(train_ds, verbose=None)[1])\nprint(\"Validation Accuracy: \", model_vgg.evaluate(validation_ds, verbose=None)[1])","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:36:20.102583Z","iopub.execute_input":"2024-03-09T10:36:20.102906Z","iopub.status.idle":"2024-03-09T10:36:46.305289Z","shell.execute_reply.started":"2024-03-09T10:36:20.102878Z","shell.execute_reply":"2024-03-09T10:36:46.304129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"The model trained using transfer learning with the VGG16 architecture has showcased exceptional performance.\n\n**Observations:**\n- The model exhibits significantly improved accuracy, with both training and validation accuracies surpassing previous models.\n- Transfer learning with VGG16 has effectively leveraged pre-trained features, allowing the model to excel in recognizing intricate patterns.\n\n**Benefits of Transfer Learning:**\n- **Enhanced Generalization:** Transfer learning facilitated the model in understanding complex image features.\n- **High Accuracy:** The model achieved remarkable accuracies, indicating robust learning.","metadata":{}},{"cell_type":"markdown","source":"You could try fine-tuning the model by re-running the optimizer in the last layers to improve accuracy. When you use a smaller learning rate, you take smaller steps to adapt it a little more closely to the new data. In transfer learning, the way you achieve this is by unfreezing the layers at the end of the network, and then re-training your model on the final layers with a very low learning rate. Adapting your learning rate to go over these layers in smaller steps can yield more fine details - and higher accuracy.\n\nThe intuition for what's happening: when the network is in its earlier stages, it trains on low-level features, like edges. In the later layers, more complex, high-level features like wispy hair or pointy ears begin to emerge. For transfer learning, the low-level features can be kept the same, as they have common features for most images. When you add new data, you generally want the high-level features to adapt to it, which is rather like letting the network learn to detect features more related to your data. \n\nTo achieve this, just unfreeze the final layers and re-run the optimizer with a smaller learning rate, while keeping all the other layers frozen.\n\nWhere the final layers actually begin is a bit arbitrary. The important takeaway is that the later layers are the part of your network that contain the fine details (pointy ears, hairy tails) that are more specific to your problem.\n\n**Source:** Convolutional Neural Network at coursera by andrew ng - Week 2 (Assignment 2)","metadata":{}},{"cell_type":"markdown","source":"## Fine-tuning the Model","metadata":{}},{"cell_type":"code","source":"# Freezing the CNN layers\nfor layer in base_model.layers[-10:]:\n    layer.trainable = True\n\n# compile the model \nmodel_vgg.compile(optimizer=Adamax(learning_rate=0.0001), loss='binary_crossentropy', metrics=['accuracy'])","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:38:09.117879Z","iopub.execute_input":"2024-03-09T10:38:09.118254Z","iopub.status.idle":"2024-03-09T10:38:09.133668Z","shell.execute_reply.started":"2024-03-09T10:38:09.118224Z","shell.execute_reply":"2024-03-09T10:38:09.132760Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history_vgg_fine_tuned = model_vgg.fit(train_ds, validation_data=validation_ds, epochs=10, callbacks=[early_stopping])","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:39:41.674288Z","iopub.execute_input":"2024-03-09T10:39:41.675045Z","iopub.status.idle":"2024-03-09T10:47:06.668889Z","shell.execute_reply.started":"2024-03-09T10:39:41.675009Z","shell.execute_reply":"2024-03-09T10:47:06.667872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_history(history_vgg_fine_tuned)","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:47:09.930594Z","iopub.execute_input":"2024-03-09T10:47:09.931418Z","iopub.status.idle":"2024-03-09T10:47:10.454289Z","shell.execute_reply.started":"2024-03-09T10:47:09.931385Z","shell.execute_reply":"2024-03-09T10:47:10.453316Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Training Accuracy: \", model_vgg.evaluate(train_ds, verbose=None)[1])\nprint(\"Validation Accuracy: \", model_vgg.evaluate(validation_ds, verbose=None)[1])","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:47:26.273308Z","iopub.execute_input":"2024-03-09T10:47:26.273708Z","iopub.status.idle":"2024-03-09T10:47:52.521846Z","shell.execute_reply.started":"2024-03-09T10:47:26.273679Z","shell.execute_reply":"2024-03-09T10:47:52.520868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"* We get impressive accuracy after fine tunning the model!\n* After training the VGG16 transfer learning model, let's evaluate its performance on the validation dataset and visualize the results using a confusion matrix and classification report.\n","metadata":{}},{"cell_type":"code","source":"actual_labels = np.array([])\npredicted_labels = np.array([])\n\n# extract labels and model predictions\nfor images, labels in validation_ds:\n        labels = labels.numpy().reshape(-1).astype(int)\n        actual_labels = np.concatenate([actual_labels, labels])\n        predictions = model_vgg.predict(images, verbose=False).reshape(-1)\n        binary_predictions = (predictions > 0.5).astype(int)\n        predicted_labels = np.concatenate([predicted_labels, binary_predictions])\n        \n#classification report\nprint(classification_report(actual_labels, predicted_labels))\n\n#confusion matrix\nconf_mat = confusion_matrix(actual_labels, predicted_labels)\nplt.figure(figsize=(5,4))\nsns.heatmap(conf_mat, annot=True, fmt='d', cmap='Blues', xticklabels=['Cats', 'Dogs'], yticklabels=['Cats', 'Dogs']) # \nplt.xlabel('Predicted'), plt.ylabel('Actual');","metadata":{"execution":{"iopub.status.busy":"2024-03-09T10:49:53.502039Z","iopub.execute_input":"2024-03-09T10:49:53.502912Z","iopub.status.idle":"2024-03-09T10:50:02.097639Z","shell.execute_reply.started":"2024-03-09T10:49:53.502878Z","shell.execute_reply":"2024-03-09T10:50:02.096700Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now let's save our best model.","metadata":{}},{"cell_type":"code","source":"# save the model\nmodel_vgg.save('/kaggle/working/vgg_model.h5')","metadata":{"execution":{"iopub.status.busy":"2024-03-09T11:47:37.095536Z","iopub.execute_input":"2024-03-09T11:47:37.096380Z","iopub.status.idle":"2024-03-09T11:47:37.430138Z","shell.execute_reply.started":"2024-03-09T11:47:37.096340Z","shell.execute_reply":"2024-03-09T11:47:37.428909Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**To view the model deployment with gradio, please refer to the https://huggingface.co/spaces/Omar-Mostafa/Cats-vs-Dogs-Classification.**","metadata":{}},{"cell_type":"markdown","source":"# Predictions on Test Data","metadata":{}},{"cell_type":"code","source":"test_dir = '/kaggle/working/test1'\n\nif not os.path.exists(test_dir):\n    !unzip -q /kaggle/input/dogs-vs-cats/test1.zip\n    print('File Unzipped Successfully')","metadata":{"execution":{"iopub.status.busy":"2024-03-03T20:46:46.029514Z","iopub.execute_input":"2024-03-03T20:46:46.030156Z","iopub.status.idle":"2024-03-03T20:46:46.035814Z","shell.execute_reply.started":"2024-03-03T20:46:46.030124Z","shell.execute_reply":"2024-03-03T20:46:46.034866Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# define images and ids lists\ntest_images = []\ntest_ids = []\nfile_names = os.listdir(test_dir)\n\n# this loop convert the images to tensors and extract images ids\nfor file_name in file_names:\n    img_path = os.path.join(test_dir, file_name)\n    img_id = file_name.replace('.jpg','')\n    img = image.load_img(img_path, target_size=(WIDTH, HEIGHT))\n    img_array = image.img_to_array(img)\n    img_array = np.expand_dims(img_array, axis=0)\n    img_array = preprocess_input(img_array)\n    test_images.append(img_array)\n    test_ids.append(img_id)\n\ntest_images = np.vstack(test_images)","metadata":{"execution":{"iopub.status.busy":"2024-03-03T22:21:38.138598Z","iopub.execute_input":"2024-03-03T22:21:38.139209Z","iopub.status.idle":"2024-03-03T22:21:57.612145Z","shell.execute_reply.started":"2024-03-03T22:21:38.139174Z","shell.execute_reply":"2024-03-03T22:21:57.611204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_predictions = model_vgg.predict(test_images)\ntest_predictions = (test_predictions > 0.5).astype(int)\n\nresults = pd.DataFrame({'id': test_ids, 'label': test_predictions.reshape(-1)})\nresults.head()","metadata":{"execution":{"iopub.status.busy":"2024-03-03T22:25:48.985214Z","iopub.execute_input":"2024-03-03T22:25:48.985892Z","iopub.status.idle":"2024-03-03T22:26:09.785758Z","shell.execute_reply.started":"2024-03-03T22:25:48.985858Z","shell.execute_reply":"2024-03-03T22:26:09.784997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results.to_csv('/kaggle/working/test_pred.csv')","metadata":{"execution":{"iopub.status.busy":"2024-03-03T22:32:13.632401Z","iopub.execute_input":"2024-03-03T22:32:13.632807Z","iopub.status.idle":"2024-03-03T22:32:13.657973Z","shell.execute_reply.started":"2024-03-03T22:32:13.632764Z","shell.execute_reply":"2024-03-03T22:32:13.657082Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**If you found this notebook helpful or interesting, consider giving it an upvote! Your support is immensely appreciated. Happy coding! 😊🚀**","metadata":{}}]}