{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"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","execution":{"iopub.status.busy":"2023-10-05T12:08:08.026725Z","iopub.execute_input":"2023-10-05T12:08:08.027238Z","iopub.status.idle":"2023-10-05T12:08:08.426985Z","shell.execute_reply.started":"2023-10-05T12:08:08.027204Z","shell.execute_reply":"2023-10-05T12:08:08.425872Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Introduction 💥\n**Background 🖼️**\nFor ages, the debate has raged on: Cats or dogs? Which pet reigns supreme in the hearts and homes of people worldwide? Beyond personal preferences, there lies an interesting challenge in the world of computer vision - can we teach a machine to differentiate between pictures of cats and dogs?\n\n> This **notebook that is profoundly explained for beginners starting on Kaggle**.\n\n**Why is this important? 🤔**\nYou might wonder, \"Why teach a machine to distinguish cats from dogs? It's not rocket science for humans!\" While the task may seem trivial, the underlying concepts are foundational in the world of machine learning and AI. Recognizing patterns in images, discerning between categories, and making accurate predictions are tasks AI is increasingly being asked to perform in far more complex scenarios, from medical imaging to satellite photo analysis.\n\n**The Dataset 📁**\nOur battleground is a dataset containing thousands of images of cats and dogs. Some are easy to classify, featuring clear shots of our furry friends. Others might be a bit trickier, with our subjects hiding, playing, or even dressed up in costumes!\n\n**Your Mission 🚀**\nYour challenge, should you choose to accept it, is to build a model that can accurately classify these images into their respective categories: cat or dog. You'll get hands-on experience with data preprocessing, model building, and performance evaluation. By the end, not only will you have contributed to resolving an age-old debate, but you'll also have sharpened your skills in image classification using machine learning!\n\n**Let the Games Begin! 🏆**\nWhether you're #TeamCat or #TeamDog, it's time to dive in, explore the data, and make your predictions. Who knows? By the end of this, you might have a newfound appreciation for the other side. Either way, it's going to be a purr-fectly bark-tastic journey!","metadata":{}},{"cell_type":"markdown","source":"![](https://storage.googleapis.com/petbacker/images/blog/2018/cat-vs-dog.jpg)","metadata":{}},{"cell_type":"markdown","source":"# Libraries 📖\n***","metadata":{}},{"cell_type":"code","source":"# Holy grail\nimport pandas as pd\nimport numpy as np\n\n# Sklearn\nfrom sklearn.preprocessing import StandardScaler, QuantileTransformer, OrdinalEncoder\nfrom sklearn.compose import make_column_transformer, make_column_selector\nfrom sklearn.model_selection import train_test_split, cross_val_score\nfrom sklearn.ensemble import StackingClassifier\nfrom sklearn.pipeline import make_pipeline\nfrom sklearn.impute import SimpleImputer\nfrom sklearn.metrics import f1_score # evaluation metric used for leaderboard scoring in this competition\n\n# Statistics\nimport scipy.stats as stats\n\n# Visualization\nfrom matplotlib import pyplot as plt # pyplot is an easy to use scripting interface for plotting as oppose to more advanced artistic interface\nimport seaborn as sns # seaborn is even higher level graphing library built on top of matplotlib\n\n# Machine learning\nimport optuna # used for finding good hyperparameters for a model\nfrom xgboost import XGBClassifier\nfrom lightgbm import LGBMClassifier\nfrom catboost import CatBoostClassifier\n\n# Tensorflow\nimport tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nfrom tensorflow.keras.layers import Dense,MaxPooling2D,Dropout,Flatten,BatchNormalization,Conv2D\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau,EarlyStopping","metadata":{"execution":{"iopub.status.busy":"2023-10-05T13:18:16.650909Z","iopub.execute_input":"2023-10-05T13:18:16.651254Z","iopub.status.idle":"2023-10-05T13:18:32.297702Z","shell.execute_reply.started":"2023-10-05T13:18:16.651227Z","shell.execute_reply":"2023-10-05T13:18:32.296626Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Extraction 📁\n***","metadata":{}},{"cell_type":"code","source":"import zipfile\n#Setting Paths\ntrain_path = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip\"\ntest_path = \"/kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip\"\n\n# path for extraction\nfiles = \"/kaggle/working/\"\n\n# Extracting Training Data\nwith zipfile.ZipFile(train_path, 'r') as zipp:\n    zipp.extractall(files)\n\n# Extracting Test Data\n\nwith zipfile.ZipFile(test_path, 'r') as zipp:\n    zipp.extractall(files)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:09:42.359386Z","iopub.execute_input":"2023-10-05T14:09:42.359681Z","iopub.status.idle":"2023-10-05T14:09:52.696618Z","shell.execute_reply.started":"2023-10-05T14:09:42.359659Z","shell.execute_reply":"2023-10-05T14:09:52.695678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"**What's Going On Here? 🤷‍♂️**\n\nAt the start, we specify the locations (paths) of two zip files. Think of these as two packed suitcases: one named train_path and the other test_path. Inside these suitcases are our pictures of cats and dogs, but they're all zipped up, meaning they're compressed to save space.\n\nNext, we declare a place, /kaggle/working/, where we want to unpack and lay out all these pictures once we unzip them. Imagine it as setting up a room where you want to spread out the contents of your suitcases.\n\nWe then bring in a special tool called zipfile. This is like having a unique key designed to open zipped suitcases.\n\nFinally, with our key in hand, we unzip both the suitcases. The lines of code that begin with with zipfile.ZipFile are us essentially saying, \"Hey, let's use our key to open up this suitcase and lay out all its contents in our room.\"\n\nBy the end of this, our room (/kaggle/working/) has all the pictures spread out, ready for us to view, analyze, or use in any other way!","metadata":{}},{"cell_type":"markdown","source":"# Data Exploration for Cats vs Dogs 🐱🐶\n\nIn this section, we'll dive deep into our dataset. We'll visualize some sample images and see the distribution of our two classes - Cats and Dogs. Let's get started!\n\n## Visualizing Sample Images 🖼️\n\nFirst, let's take a look at some random images of cats and dogs to familiarize ourselves with our dataset.","metadata":{}},{"cell_type":"code","source":"import os\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\ntrain_directory = \"/kaggle/working/train\"\n# Splitting filenames based on class\ncat_files = [img for img in os.listdir(train_directory) if 'cat' in img]\ndog_files = [img for img in os.listdir(train_directory) if 'dog' in img]\n\n# Randomly select a few images of cats and dogs\nrandom_cats = np.random.choice(cat_files, 5)\nrandom_dogs = np.random.choice(dog_files, 5)\n\n# Combining the selected images\nselected_images = np.concatenate([random_cats, random_dogs])\n# Set up a figure and axis for the subplots\nfig, axes = plt.subplots(1, len(selected_images), figsize=(15, 5))\n\nfor ax, image_file in zip(axes, selected_images):\n    # Load the image\n    img_path = os.path.join(train_directory, image_file)\n    img = cv2.imread(img_path)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)  # Convert from BGR to RGB\n    \n    # Display the image\n    ax.imshow(img)\n    ax.set_title(image_file.split('.')[0])  # Extract the label (cat or dog) from the filename\n    ax.axis('off')\n\nplt.tight_layout()  # Adjust the layout so images do not overlap\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-10-05T13:42:40.283082Z","iopub.execute_input":"2023-10-05T13:42:40.283469Z","iopub.status.idle":"2023-10-05T13:42:41.217686Z","shell.execute_reply.started":"2023-10-05T13:42:40.283445Z","shell.execute_reply":"2023-10-05T13:42:41.216678Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Class Distribution 📊\n\nLet's visualize the distribution of our two classes using a horizontal bar chart.\n","metadata":{}},{"cell_type":"code","source":"# Counting cats and dogs\ncats_count = len(cat_files)\ndogs_count = len(dog_files)\n\nprint(f\"Cats: {cats_count}\")\nprint(f\"Dogs: {dogs_count}\")\n\n# Displaying a horizontal bar chart\nlabels = ['Cats', 'Dogs']\ncounts = [cats_count, dogs_count]\n\nplt.bar(labels, counts, color=['blue', 'green'])\nplt.xlabel('Number of Images')\nplt.title('Distribution of Cats and Dogs in Training Data')\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T13:40:44.071003Z","iopub.execute_input":"2023-10-05T13:40:44.071338Z","iopub.status.idle":"2023-10-05T13:40:44.224637Z","shell.execute_reply.started":"2023-10-05T13:40:44.071313Z","shell.execute_reply":"2023-10-05T13:40:44.223411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Preprocessing ⚙️\n### Data Processing for Cats vs Dogs 🐱🐶\n\nOur primary objective in this step is to prepare our dataset for model training. This involves:\n1. Organizing our images into respective `Cats` and `Dogs` folders for clarity.\n2. Using an Image Data Generator to facilitate on-the-fly data augmentation, which helps the model generalize better.\n\nLet's get started!\n\n***","metadata":{"execution":{"iopub.status.busy":"2023-10-05T13:46:53.942008Z","iopub.execute_input":"2023-10-05T13:46:53.943270Z","iopub.status.idle":"2023-10-05T13:46:53.949901Z","shell.execute_reply.started":"2023-10-05T13:46:53.943220Z","shell.execute_reply":"2023-10-05T13:46:53.948066Z"}}},{"cell_type":"markdown","source":"## 1. Organizing Images 📂\n\nWe'll first move our images into two separate folders: `Cats` for cat images and `Dogs` for dog images.\n\n### Splitting Data: Train, Validation, and Test Sets 📊\n\nTo train a model effectively, we divide our dataset into:\n1. **Training Set:** Used to train the model.\n2. **Validation Set:** Used to fine-tune the model and prevent overfitting.\n3. **Test Set:** Used to evaluate the model's performance.\n\nLet's perform this split now!\n","metadata":{}},{"cell_type":"code","source":"import os\nimport shutil\n\n# Base directory\nbase_directory = \"/kaggle/working/train/\"\n\n# Get all image files from base directory\nall_files = np.array(os.listdir(base_directory))\n\n# Filter out cat and dog images using case-insensitive check\ncat_files = [file for file in all_files if file.lower().startswith('cat')]\ndog_files = [file for file in all_files if file.lower().startswith('dog')]\n\n# Define the new directory structure\ntrain_cats_dir = os.path.join(base_directory, 'train', 'Cats')\ntrain_dogs_dir = os.path.join(base_directory, 'train', 'Dogs')\n\nval_cats_dir = os.path.join(base_directory, 'validation', 'Cats')\nval_dogs_dir = os.path.join(base_directory, 'validation', 'Dogs')\n\ntest_cats_dir = os.path.join(base_directory, 'test', 'Cats')\ntest_dogs_dir = os.path.join(base_directory, 'test', 'Dogs')\n\n# Making the directories\nfor directory in [train_cats_dir, train_dogs_dir, val_cats_dir, val_dogs_dir, test_cats_dir, test_dogs_dir]:\n    os.makedirs(directory, exist_ok=True)\n\n# Splitting and moving the cat images\nnp.random.shuffle(cat_files)\n\ncat_train_files = cat_files[:int(0.7 * len(cat_files))]\ncat_val_files = cat_files[int(0.7 * len(cat_files)):int(0.85 * len(cat_files))]\ncat_test_files = cat_files[int(0.85 * len(cat_files)):]\n\nfor file in cat_train_files:\n    shutil.move(os.path.join(base_directory, file), train_cats_dir)\nfor file in cat_val_files:\n    shutil.move(os.path.join(base_directory, file), val_cats_dir)\nfor file in cat_test_files:\n    shutil.move(os.path.join(base_directory, file), test_cats_dir)\n\n# Splitting and moving the dog images\nnp.random.shuffle(dog_files)\n\ndog_train_files = dog_files[:int(0.7 * len(dog_files))]\ndog_val_files = dog_files[int(0.7 * len(dog_files)):int(0.85 * len(dog_files))]\ndog_test_files = dog_files[int(0.85 * len(dog_files)):]\n\nfor file in dog_train_files:\n    shutil.move(os.path.join(base_directory, file), train_dogs_dir)\nfor file in dog_val_files:\n    shutil.move(os.path.join(base_directory, file), val_dogs_dir)\nfor file in dog_test_files:\n    shutil.move(os.path.join(base_directory, file), test_dogs_dir)\n\n\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:20:23.749882Z","iopub.execute_input":"2023-10-05T14:20:23.750248Z","iopub.status.idle":"2023-10-05T14:20:24.630624Z","shell.execute_reply.started":"2023-10-05T14:20:23.750222Z","shell.execute_reply":"2023-10-05T14:20:24.629264Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# List of all directories to count files in\ndirectories = [train_cats_dir, train_dogs_dir, val_cats_dir, val_dogs_dir, test_cats_dir, test_dogs_dir]\n\n# Print number of files in each directory\nfor directory in directories:\n    num_files = len(os.listdir(directory))\n    print(f\"Number of files in {directory}: {num_files}\")\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:21:41.326724Z","iopub.execute_input":"2023-10-05T14:21:41.327078Z","iopub.status.idle":"2023-10-05T14:21:41.343199Z","shell.execute_reply.started":"2023-10-05T14:21:41.327048Z","shell.execute_reply":"2023-10-05T14:21:41.341611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Data Augmentation and Preparation 🔄\n\nNow, we'll use the Keras `ImageDataGenerator` to perform on-the-fly data augmentation. This process introduces variability in our training data, simulating different conditions our model might encounter in the real world, thereby improving its ability to generalize.\n","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.preprocessing.image import ImageDataGenerator\n\n# Directories\ntrain_directory = os.path.join(base_directory, 'train')\nval_directory = os.path.join(base_directory, 'validation')\ntest_directory = os.path.join(base_directory, 'test')  # If you have a test directory\n\n# For training, apply data augmentation and rescaling\ntrain_datagen = ImageDataGenerator(\n    rescale=1./255,\n    rotation_range=40,\n    width_shift_range=0.2,\n    height_shift_range=0.2,\n    shear_range=0.2,\n    zoom_range=0.2,\n    horizontal_flip=True,\n    fill_mode='nearest'\n)\n\n# For validation/test, only rescale the images\nval_datagen = ImageDataGenerator(rescale=1./255)\ntest_datagen = ImageDataGenerator(rescale=1./255)  # If you have a test set\n\n# Load images from the directories\ntrain_data = train_datagen.flow_from_directory(\n    train_directory,\n    target_size=(150, 150),\n    batch_size=32,\n    class_mode='binary'\n)\n\nval_data = val_datagen.flow_from_directory(\n    val_directory,\n    target_size=(150, 150),\n    batch_size=32,\n    class_mode='binary',\n    shuffle=False  # Generally, we don't shuffle validation data\n)\n\n# If you have a test set\ntest_data = test_datagen.flow_from_directory(\n    test_directory,\n    target_size=(150, 150),\n    batch_size=32,\n    class_mode='binary',\n    shuffle=False  # No shuffling for test data\n)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:23:28.840186Z","iopub.execute_input":"2023-10-05T14:23:28.840520Z","iopub.status.idle":"2023-10-05T14:23:29.110741Z","shell.execute_reply.started":"2023-10-05T14:23:28.840498Z","shell.execute_reply":"2023-10-05T14:23:29.109268Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Modeling 🪄\n***","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:26:54.734036Z","iopub.execute_input":"2023-10-05T14:26:54.734364Z","iopub.status.idle":"2023-10-05T14:26:54.741870Z","shell.execute_reply.started":"2023-10-05T14:26:54.734343Z","shell.execute_reply":"2023-10-05T14:26:54.739987Z"}}},{"cell_type":"markdown","source":"## 1. Model Architecture Design 🛠️\nWe're going to construct our CNN using a series of convolutional layers followed by max-pooling layers. The convolutional layers will help in detecting features, while the pooling layers will reduce the spatial dimensions, making the model computationally efficient. Finally, we'll flatten the output and pass it through fully connected layers (dense layers) to get our classification.","metadata":{}},{"cell_type":"code","source":"import tensorflow as tf\nfrom tensorflow.keras.models import Sequential\nfrom tensorflow.keras.layers import Conv2D, MaxPooling2D\nfrom tensorflow.keras.layers import Activation, Dropout, Flatten, Dense\nmodel = Sequential()\n\n# First convolution layer with max pooling\nmodel.add(Conv2D(32, (3, 3), input_shape=(150, 150, 3)))\nmodel.add(Activation('relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Second convolution layer with max pooling\nmodel.add(Conv2D(64, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Third convolution layer with max pooling\nmodel.add(Conv2D(128, (3, 3)))\nmodel.add(Activation('relu'))\nmodel.add(MaxPooling2D(pool_size=(2, 2)))\n\n# Flatten the results to feed into a dense layer\nmodel.add(Flatten())\n\n# Dense layer\nmodel.add(Dense(512))\nmodel.add(Activation('relu'))\n\n# Dropout to avoid overfitting\nmodel.add(Dropout(0.5))\n\n# Output layer\nmodel.add(Dense(1))\nmodel.add(Activation('sigmoid'))\n\n# Compile the model\nmodel.compile(loss='binary_crossentropy',\n              optimizer='adam',\n              metrics=['accuracy'])\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:28:55.476371Z","iopub.execute_input":"2023-10-05T14:28:55.476694Z","iopub.status.idle":"2023-10-05T14:28:55.704217Z","shell.execute_reply.started":"2023-10-05T14:28:55.476670Z","shell.execute_reply":"2023-10-05T14:28:55.702815Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 2. Overview of the Model Structure 🔍\nA good practice before training is to look at the model's summary. It gives us a bird's eye view of the layers and parameters in our neural network. It's a quick way to verify if our model structure aligns with our design intentions.","metadata":{}},{"cell_type":"code","source":"model.summary()","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:29:02.691487Z","iopub.execute_input":"2023-10-05T14:29:02.691828Z","iopub.status.idle":"2023-10-05T14:29:02.735301Z","shell.execute_reply.started":"2023-10-05T14:29:02.691802Z","shell.execute_reply":"2023-10-05T14:29:02.733807Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3. Graphical Representation of the Model 📊\nA picture is worth a thousand words! Visualizing our model's architecture can give us a more intuitive understanding of its structure. It aids in visually grasping how data flows between layers and how different components of our model interact.","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.utils import plot_model\nimport IPython.display as display\n\n# Plot the model architecture\nplot_model(model, to_file='model_plot.png', show_shapes=True, show_layer_names=True)\n\n# Display the image\ndisplay.Image(filename='model_plot.png')\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:30:06.551281Z","iopub.execute_input":"2023-10-05T14:30:06.551652Z","iopub.status.idle":"2023-10-05T14:30:06.949792Z","shell.execute_reply.started":"2023-10-05T14:30:06.551626Z","shell.execute_reply":"2023-10-05T14:30:06.948539Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 4. Setting Up Callbacks for Efficient Training ⏳\nTraining a neural network can be time-consuming and might lead to overfitting if we're not careful. By using callbacks, we can monitor our model during training and take action (like stopping the training or saving the best model) based on its performance.\n\n### 1. Early Stopping 🛑\nTo prevent overfitting, we can use the EarlyStopping callback. This stops the training process when a monitored metric (like validation loss) stops improving for a specified number of epochs. By doing so, we ensure that our model doesn't waste computational resources and that we don't overtrain on our dataset.\n\n### 2. Model Checkpoint 💾\nIt's essential to save the best version of our model during training, especially when the training process is lengthy. The ModelCheckpoint callback allows us to save our model at regular intervals or whenever it surpasses its previous best performance on a specific metric (like validation accuracy).","metadata":{}},{"cell_type":"code","source":"from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n\n# Define EarlyStopping callback\nearly_stopping = EarlyStopping(monitor='val_loss', patience=10, verbose=1, restore_best_weights=True)\n\n# Define ModelCheckpoint callback to save the best model during training\nmodel_checkpoint = ModelCheckpoint('best_model.h5', monitor='val_accuracy', save_best_only=True, verbose=1)\n\n# List of callbacks\ncallbacks = [early_stopping, model_checkpoint]\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:36:38.010807Z","iopub.execute_input":"2023-10-05T14:36:38.011148Z","iopub.status.idle":"2023-10-05T14:36:38.016731Z","shell.execute_reply.started":"2023-10-05T14:36:38.011117Z","shell.execute_reply":"2023-10-05T14:36:38.015387Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"history = model.fit(train_data, epochs=10, validation_data=val_data, callbacks=callbacks)","metadata":{"execution":{"iopub.status.busy":"2023-10-05T14:40:59.123702Z","iopub.execute_input":"2023-10-05T14:40:59.124043Z","iopub.status.idle":"2023-10-05T15:51:23.068915Z","shell.execute_reply.started":"2023-10-05T14:40:59.124016Z","shell.execute_reply":"2023-10-05T15:51:23.066997Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_loss, test_accuracy = model.evaluate(test_data)\nprint(f\"Test Accuracy: {test_accuracy*100:.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2023-10-05T15:55:52.550779Z","iopub.execute_input":"2023-10-05T15:55:52.551205Z","iopub.status.idle":"2023-10-05T15:56:13.228680Z","shell.execute_reply.started":"2023-10-05T15:55:52.551136Z","shell.execute_reply":"2023-10-05T15:56:13.227603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\n# Extract training and validation loss and accuracy from the history object\ntrain_acc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\ntrain_loss = history.history['loss']\nval_loss = history.history['val_loss']\n\nepochs = range(len(train_acc))\n\n# Plot training and validation accuracy\nplt.figure(figsize=(12, 5))\nplt.subplot(1, 2, 1)\nplt.plot(epochs, train_acc, label='Training Accuracy')\nplt.plot(epochs, val_acc, label='Validation Accuracy')\nplt.axhline(y=test_accuracy, color='r', linestyle='--', label='Test Accuracy')\nplt.title('Training and Validation Accuracy')\nplt.legend()\n\n# Plot training and validation loss\nplt.subplot(1, 2, 2)\nplt.plot(epochs, train_loss, label='Training Loss')\nplt.plot(epochs, val_loss, label='Validation Loss')\nplt.axhline(y=test_loss, color='r', linestyle='--', label='Test Loss')\nplt.title('Training and Validation Loss')\nplt.legend()\n\nplt.tight_layout()\nplt.show()\n","metadata":{"execution":{"iopub.status.busy":"2023-10-05T15:56:17.496045Z","iopub.execute_input":"2023-10-05T15:56:17.497154Z","iopub.status.idle":"2023-10-05T15:56:17.929829Z","shell.execute_reply.started":"2023-10-05T15:56:17.497071Z","shell.execute_reply":"2023-10-05T15:56:17.928184Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}