{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"sourceType":"competition"}],"dockerImageVersionId":31089,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# 📸 Image Classification: Recognizing Cats vs Dogs with CNNs\n\nWelcome! In this notebook, we'll build a **Convolutional Neural Network (CNN)** to solve a classic computer vision problem: telling the difference between a cat and a dog.\n\nWe'll make this journey as intuitive as possible by using a single, powerful analogy from start to finish.\n\n### The Big Idea: The \"Teaching a Child\" Analogy\n\nImagine your task is to teach a very young child, who has never seen an animal before, how to tell the difference between a cat and a dog. You can't just give them a list of rules. Instead, you'd show them hundreds of pictures.\n\n*   **The Pictures:** This is our dataset of cat and dog images.\n*   **The Child's Brain:** This is our **Convolutional Neural Network (CNN)**.\n*   **The Learning Process:** This is the **training** of our model.\n*   **Pointing and Saying \"Cat\" or \"Dog\":** This is providing the **labels** for our images.\n*   **Showing a New Picture and Asking \"What is this?\":** This is **making a prediction**.\n\nOur goal is to simulate this entire learning process, teaching our digital \"child's brain\" to recognize the fundamental patterns that define \"cat-ness\" and \"dog-ness.\"\n\n### The Team Behind the Lesson Plan\n\nBefore we even get the photos, a **Business Analyst** would define the project's goal. They might work with an animal shelter app and say, \"We need a feature that automatically tags uploaded pet photos as 'cat' or 'dog' with over 90% accuracy to help users filter searches.\" This gives our technical work a clear business purpose.","metadata":{"_uuid":"3cba3900-ed0a-4caa-b8b8-00ce1b09899f","_cell_guid":"9138613c-0dd6-4631-8bcd-b79919089628","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"markdown","source":"## 1. Setting Up the Classroom (Importing Libraries)\n\nBefore the lesson starts, we need to get our supplies ready. We'll import our libraries:\n\n*   **TensorFlow & Keras:** This is the \"blackboard and chalk\" we'll use to design and build the child's brain (our CNN).\n*   **Matplotlib:** These are our \"crayons and paper\" for drawing and looking at the pictures.\n*   **OS, shutil, zipfile:** These are our \"organizing tools\" for setting up our photo albums correctly.","metadata":{"_uuid":"cdf7f941-2b49-48cc-ba5a-73c97cf9fc90","_cell_guid":"850d4798-5841-4285-b9f0-55d6c9d8287c","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Import the main library for building and training neural networks.\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\n\n# Import our visualization library.\nimport matplotlib.pyplot as plt\n\n# Import utilities for file and directory management.\nimport os\nimport shutil\nimport zipfile\nimport random","metadata":{"_uuid":"68ac6ee9-26f7-48a9-a274-ed7fb2014338","_cell_guid":"b9cd27d3-ab37-44c6-9901-8de6a3d6fb4e","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 2. Organizing the Flashcards (Data Preparation)\n\nThe \"Dogs vs. Cats\" dataset comes as a `.zip` file with all 25,000 training images mixed together in one folder. The filenames tell us if it's a cat or dog (e.g., `cat.1.jpg` or `dog.1.jpg`).\n\nOur Keras tools work best when the flashcards are organized into neat piles. We need a folder structure like this:\n```\ntrain/\n|-- cats/\n|   |-- cat.1.jpg ...\n|-- dogs/\n    |-- dog.1.jpg ...\nvalidation/\n|-- cats/\n|   |-- cat.10001.jpg ...\n|-- dogs/\n    |-- dog.10001.jpg ...\n```\n### The Data Scientist as an Organizer\n\nThis is a realistic task for a **Data Scientist** or **Data Engineer**. Raw data is rarely in the perfect format. Our first job is to write code to prepare and organize it. We'll create the folders, unzip the images, and copy them into the correct \"piles\" for our training and validation (quiz) sessions.","metadata":{"_uuid":"52975f62-092f-4e3a-9450-34b04d21e50a","_cell_guid":"f51f20bc-bbab-4aa8-ab0d-912f201b1209","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# --- Step 1: Unzip the main training file ---\n# The original data is in /kaggle/input/dogs-vs-cats/train.zip\nprint(\"Unzipping the training data...\")\nwith zipfile.ZipFile('/kaggle/input/dogs-vs-cats/train.zip', 'r') as zip_ref:\n    zip_ref.extractall('.') # Extract to the current working directory\nprint(\"Unzipping complete.\")\n\n# --- Step 2: Get all image filenames and shuffle them ---\nall_filenames = os.listdir('train')\n# We shuffle the filenames to ensure a random mix for our training and validation sets.\nrandom.shuffle(all_filenames)\n\n# --- Step 3: Define directories and create them ---\n# We'll create a main 'data' directory to hold everything.\nif os.path.exists('data'):\n    shutil.rmtree('data') # Remove old directory if it exists\n\n# Create the folder structure\ntrain_cat_dir = 'data/train/cats'\ntrain_dog_dir = 'data/train/dogs'\nval_cat_dir = 'data/validation/cats'\nval_dog_dir = 'data/validation/dogs'\n\nos.makedirs(train_cat_dir, exist_ok=True)\nos.makedirs(train_dog_dir, exist_ok=True)\nos.makedirs(val_cat_dir, exist_ok=True)\nos.makedirs(val_dog_dir, exist_ok=True)\n\n# --- Step 4: Split filenames and copy files ---\n# We'll use 10,000 images per class for training, and the rest for validation.\nTRAIN_SIZE = 10000\nVAL_SIZE = 2500 # 12500 total images per class\n\ntrain_cat_count, train_dog_count = 0, 0\nval_cat_count, val_dog_count = 0, 0\n\nfor filename in all_filenames:\n    source_path = os.path.join('train', filename)\n    \n    # Check if the file is a cat image\n    if filename.startswith('cat'):\n        if train_cat_count < TRAIN_SIZE:\n            shutil.copy(source_path, os.path.join(train_cat_dir, filename))\n            train_cat_count += 1\n        elif val_cat_count < VAL_SIZE:\n            shutil.copy(source_path, os.path.join(val_cat_dir, filename))\n            val_cat_count += 1\n            \n    # Check if the file is a dog image\n    elif filename.startswith('dog'):\n        if train_dog_count < TRAIN_SIZE:\n            shutil.copy(source_path, os.path.join(train_dog_dir, filename))\n            train_dog_count += 1\n        elif val_dog_count < VAL_SIZE:\n            shutil.copy(source_path, os.path.join(val_dog_dir, filename))\n            val_dog_count += 1\n\nprint(\"\\nData organization complete.\")\nprint(f\"Total training cat images: {train_cat_count}\")\nprint(f\"Total training dog images: {train_dog_count}\")\nprint(f\"Total validation cat images: {val_cat_count}\")\nprint(f\"Total validation dog images: {val_dog_count}\")","metadata":{"_uuid":"b9523e93-e876-43af-baf5-ec52daa149ba","_cell_guid":"f62035b4-41df-43e7-ac7c-31ed7c78b3c9","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 3. Gathering the Now-Organized Flashcards\n\nWith our data neatly organized, we can now use Keras's powerful utility to load it. It will automatically find the `cats` and `dogs` folders and label the images for us.","metadata":{"_uuid":"78c62b49-52b8-4912-92b5-ffce4f3be490","_cell_guid":"697c0541-287c-4c46-9a88-8b48bfd3f093","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Define some key parameters for our project.\nIMAGE_SIZE = (128, 128) # We'll make all images a standard 128x128 size.\nBATCH_SIZE = 32         # We'll show the child 32 pictures at a time.\nDATA_DIR = 'data'      # The path to our newly created data directory.\n\n# Create the training and validation datasets from our organized folders.\ntrain_dataset = tf.keras.utils.image_dataset_from_directory(\n    os.path.join(DATA_DIR, 'train'),\n    seed=1337,\n    image_size=IMAGE_SIZE,\n    batch_size=BATCH_SIZE,\n)\n\nvalidation_dataset = tf.keras.utils.image_dataset_from_directory(\n    os.path.join(DATA_DIR, 'validation'),\n    seed=1337,\n    image_size=IMAGE_SIZE,\n    batch_size=BATCH_SIZE,\n)\n\n# Let's see the class names it found from the folder names.\nclass_names = train_dataset.class_names\nprint(f\"The classes are: {class_names}\")\n\n# Let's visualize a few images to confirm everything loaded correctly.\nplt.figure(figsize=(10, 10))\nfor images, labels in train_dataset.take(1):\n    for i in range(9):\n        ax = plt.subplot(3, 3, i + 1)\n        plt.imshow(images[i].numpy().astype(\"uint8\"))\n        plt.title(class_names[labels[i]])\n        plt.axis(\"off\")\nplt.show()","metadata":{"_uuid":"f8e99395-d34b-4d29-83db-8e1bb9d9b7ff","_cell_guid":"598e7088-7d49-4d85-b0e4-a82af3f31609","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 4. Smart Study Habits (Image Preprocessing & Augmentation)\n\nJust showing a child the same few pictures over and over isn't the best way to teach. They might just memorize those specific photos. A better way is to teach them to recognize a cat or dog from any angle.\n\nThis is where a **Data Scientist** adds immense value through **Data Augmentation**.\n\n1.  **Rescaling (Normalization):** First, we'll standardize the \"brightness\" of all photos from 0-255 to 0-1. This is like adjusting all photos to have similar lighting, making it easier for the child to focus on the shapes.\n\n2.  **Data Augmentation (Creating New Flashcards):** We'll create a \"magic photocopier\" that takes an image and creates slightly different versions of it by flipping, rotating, or zooming. By showing the child these varied versions, we teach them the concept of \"cat-ness\" is independent of orientation. This makes our model much more robust.","metadata":{"_uuid":"67407ebc-1a2a-4a82-8530-b1ce259aa52b","_cell_guid":"faa89207-a74c-45e9-9daa-a87025339d15","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Let's create our \"magic photocopier\" as a sequence of layers.\ndata_augmentation = keras.Sequential(\n    [\n        layers.RandomFlip(\"horizontal\"),\n        layers.RandomRotation(0.1),\n        layers.RandomZoom(0.1),\n    ]\n)","metadata":{"_uuid":"5bb96e0e-c62a-42ab-a648-6082e48d506f","_cell_guid":"f75826c4-1167-4663-bd60-41407c10ba1a","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 5. Building the Brain (Creating the CNN Model)\n\nNow, we build the child's brain (our CNN). A CNN is specifically designed to \"see\" patterns in images. It's a series of specialized layers.\n\n#### Analogy: How a Child's Vision Works\n\n1.  **Convolutional Layers (`Conv2D`) - The Eyes:** The child's eyes scan the image for tiny, simple features like **edges**, **curves**, and **textures** (like fur). These are called **filters**. A `Conv2D` layer is a set of these learnable filters.\n\n2.  **Pooling Layers (`MaxPooling2D`) - Summarizing:** The brain summarizes, \"pointy ears and whiskers were seen in the top half.\" `MaxPooling2D` does this by looking at a small window and keeping only the most important feature it saw. This makes the model more robust.\n\n3.  **Flatten Layer - Gathering All the Clues:** The brain gathers all the clues it has found (\"saw pointy ears,\" \"saw a wet nose,\" \"saw fluffy fur\"). `Flatten` unrolls these clues into one long list.\n\n4.  **Dense Layers (`Dense`) - The Reasoning Center:** This is the final part that takes the list of clues and makes a decision. It learns that `(pointy ears + whiskers)` is likely a **cat**.","metadata":{"_uuid":"61f6e31a-bb55-4017-ae5c-efa6b284f000","_cell_guid":"388d498c-eb4b-4c34-af3c-4d7c8b886abc","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# We build our model as a sequence of layers.\nmodel = keras.Sequential([\n    # --- Input and Preprocessing ---\n    layers.Input(shape=IMAGE_SIZE + (3,)),\n    layers.Rescaling(1./255),\n    data_augmentation,\n    \n    # --- The \"Seeing\" Part of the Brain ---\n    # First Conv/Pool Block: Learn 32 simple filters.\n    layers.Conv2D(filters=32, kernel_size=3, activation=\"relu\"),\n    layers.MaxPooling2D(pool_size=2),\n    \n    # Second Conv/Pool Block: Learn 64 more complex filters.\n    layers.Conv2D(filters=64, kernel_size=3, activation=\"relu\"),\n    layers.MaxPooling2D(pool_size=2),\n    \n    # Third Conv/Pool Block: Learn 128 even more complex filters.\n    layers.Conv2D(filters=128, kernel_size=3, activation=\"relu\"),\n    layers.MaxPooling2D(pool_size=2),\n    \n    # --- The \"Reasoning\" Part of the Brain ---\n    layers.Flatten(),\n    # A Dense layer to learn complex combinations of clues.\n    layers.Dense(512, activation=\"relu\"),\n    # The final output neuron. We use 'sigmoid' because this is a yes/no (binary) question.\n    # It will output a single number between 0 (cat) and 1 (dog).\n    layers.Dense(1, activation=\"sigmoid\"),\n])\n\nmodel.summary()","metadata":{"_uuid":"1be5ec7b-9c62-4705-ae6d-4e6fbe8eafec","_cell_guid":"7ee328c5-1f75-4506-a6f5-23d5f4b53c2f","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 6. Creating the Lesson Plan (Compiling the Model)\n\nWe've built the brain, now we need to give it a learning strategy.\n\n*   **Loss Function (`binary_crossentropy`):** The \"mistake-o-meter\" for our yes/no question (Is it a dog? 0=No/cat, 1=Yes/dog).\n*   **Optimizer (`adam`):** The \"teacher\" that adjusts the brain's connections based on the mistakes.","metadata":{"_uuid":"7ce0b07d-c636-4d71-89f1-945926a9a4b6","_cell_guid":"9605cc87-7d4f-4ff8-b6f2-a0b64fe979db","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"model.compile(\n    optimizer=\"adam\",\n    loss=\"binary_crossentropy\",\n    metrics=[\"accuracy\"],\n)","metadata":{"_uuid":"09cc0065-46bf-49c2-8373-b3a5c11c8062","_cell_guid":"2358586f-aa7f-43ff-9410-1f009d9696d9","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 7. The Study Session (Training the Model)\n\nNow it's time for the main study session. We'll show the child all the training flashcards and use the validation set for periodic quizzes.\n\n*   **Epochs:** An epoch is one full look through the entire set of flashcards. We'll do this 5 times.","metadata":{"_uuid":"2fcec0cf-4335-4c88-b035-08b070368469","_cell_guid":"6376c9f1-6908-49ce-8380-e5d45ab06e6d","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Let's start the training!\nhistory = model.fit(\n    train_dataset,\n    epochs=5,   #increase or decrease epoch as per your liking. Beaware! increasing epoch doesn't necessarily means increase in accuracy. Experiment Yourself...\n    validation_data=validation_dataset,\n)","metadata":{"_uuid":"c9e6270d-26c6-463d-80e3-8b97c7d53c06","_cell_guid":"a324ecda-f93c-4668-983e-4f76ee789ba8","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 8. Charting the Progress (Visualizing Training)\n\nLet's plot the model's accuracy and loss on both the training data (study material) and validation data (quizzes).\n\n**How to Read These Charts:**\n*   **Accuracy:** We want both lines to go up. If the training accuracy (blue) gets very high but the validation accuracy (orange) flattens out or goes down, it means the child is **overfitting** (memorizing instead of learning).\n*   **Loss:** We want both lines to go down.","metadata":{"_uuid":"1e6ce546-fbc8-4125-b3f7-8463d8b1c017","_cell_guid":"6a55a3e5-320f-41f1-8452-5afa9643824f","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Get the accuracy and loss values from the training history.\nacc = history.history['accuracy']\nval_acc = history.history['validation_accuracy']\nloss = history.history['loss']\nval_loss = history.history['validation_loss']\n\nepochs_range = range(len(acc))\n\nplt.figure(figsize=(15, 5))\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Training Accuracy')\nplt.plot(epochs_range, val_acc, label='Validation Accuracy')\nplt.legend(loc='lower right')\nplt.title('Training and Validation Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Training Loss')\nplt.plot(epochs_range, val_loss, label='Validation Loss')\nplt.legend(loc='upper right')\nplt.title('Training and Validation Loss')\nplt.show()","metadata":{"_uuid":"c81f43f4-db5f-46be-9943-579af265aa98","_cell_guid":"2de2367b-73d4-4a0d-897a-61ada20d5dc9","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 9. The Final Exam (Making Predictions)\n\nThe training is complete! Now for the ultimate test: we'll give the child a brand new photo.\n\nThe final output is a single number:\n*   Close to **0** means confident it's a **cat**.\n*   Close to **1** means confident it's a **dog**.","metadata":{"_uuid":"d9204eb9-2c0a-4180-b822-5608ed2a019b","_cell_guid":"a28f03aa-4b73-4abf-b55f-306a92c61296","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}},{"cell_type":"code","source":"# Let's use an image from our validation set to test a prediction.\nfor val_images, val_labels in validation_dataset.take(1):\n    first_image = val_images[0]\n    true_label = val_labels[0]\n    \n    plt.imshow(first_image.numpy().astype(\"uint8\"))\n    plt.title(f\"True Label: {class_names[true_label]}\")\n    plt.axis(\"off\")\n    plt.show()\n\n    img_array = tf.expand_dims(first_image, 0)\n    prediction = model.predict(img_array)\n    score = prediction[0][0]\n    \n    confidence = 100 * (1 - score) if score < 0.5 else 100 * score\n    predicted_class = \"Cat\" if score < 0.5 else \"Dog\"\n    \n    print(f\"This image is a {predicted_class} with {confidence:.2f}% confidence.\")","metadata":{"_uuid":"87ea8e11-8a0f-414b-b472-d36284a8ac13","_cell_guid":"acbea92c-18e4-46e3-ac8e-4fc28145432d","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## 10. Conclusion and Graduation Day\n\nCongratulations! We have successfully taught a \"digital brain\" to see and understand the difference between cats and dogs.\n\nAs **Data Scientists**, our job was to wrangle the messy data, design the lesson plan (preprocessing, augmentation), and build the brain (the CNN architecture).\n\n### What Happens Next? The ML Engineer Builds the App\n\nOur trained model is like a knowledgeable graduate, but it needs a job! This is where the **ML Engineer** comes in. They would take our saved model and **deploy it to production**. They would build the mobile app or website feature that lets users upload a photo, sends it to our model, and automatically tags the photo as \"Cat\" or \"Dog\". The ML Engineer turns our intelligent model into a useful, real-world tool.","metadata":{"_uuid":"0d2835c7-675b-492e-9321-cf0c2238c1a1","_cell_guid":"d2bff682-2bc3-4edb-8b38-17a786fde638","trusted":true,"collapsed":false,"jupyter":{"outputs_hidden":false}}}]}