{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "61b27552-3203-4a48-9196-0936bac7a330",
   "metadata": {},
   "source": [
    "# Practical-3a (Convolutional Neural Network - Plant Diseases)\n",
    "\n",
    "---\n",
    "\n",
    "Problem Statement: Convolutional neural network (CNN): Use any dataset of plant disease and design a plant disease detection system using CNN.\n",
    "\n",
    "- Dataset link: https://www.kaggle.com/datasets/vipoooool/new-plant-diseases-dataset/data\n",
    "- Haven't added it to the `/Datasets` directory due to its large size.\n",
    "- tbh the dataset doesn't really matter in this case, you just need to ensure dataset directory contains `train` and `valid` sub-directories.\n",
    "- Required dataset structure:\n",
    "\n",
    "```shell\n",
    "New Plant Diseases Dataset(Augmented)/\n",
    "├── train\n",
    "│   ├── Apple___Apple_scab\n",
    "│   ├── Apple___Black_rot\n",
    "│   ├── Apple___Cedar_apple_rust\n",
    "├── valid\n",
    "│   ├── Apple___Apple_scab\n",
    "│   ├── Apple___Black_rot\n",
    "│   ├── Apple___Cedar_apple_rust\n",
    "```\n",
    "\n",
    "---"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "8585ce11",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1. Import Libraries\n",
    "import os\n",
    "import numpy as np\n",
    "import cv2\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import confusion_matrix, classification_report\n",
    "from tensorflow.keras.models import Sequential\n",
    "from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D, Flatten, Dense, Dropout\n",
    "from tensorflow.keras.utils import to_categorical"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "cdf6b412",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Classes found: 38\n",
      "Dataset shape: (7600, 64, 64, 3)\n",
      "Labels shape: (7600,)\n"
     ]
    }
   ],
   "source": [
    "# 2. Load Dataset\n",
    "data = []\n",
    "labels = []\n",
    "\n",
    "# Path to dataset folder containing one subfolder per disease class\n",
    "path = './New Plant Diseases Dataset(Augmented)/train/'\n",
    "categories = sorted(os.listdir(path))  # sort for consistent label ordering\n",
    "\n",
    "# Map each category name to a numeric index\n",
    "label_dict = {category: idx for idx, category in enumerate(categories)}\n",
    "print(\"Classes found:\", len(categories))\n",
    "\n",
    "max_per_class = 200  # cap images per class to avoid RAM overflow on large datasets\n",
    "\n",
    "for category in categories:\n",
    "    folder = os.path.join(path, category)\n",
    "    count = 0\n",
    "    for img_name in os.listdir(folder):\n",
    "        if count >= max_per_class:\n",
    "            break\n",
    "        img_path = os.path.join(folder, img_name)\n",
    "        img_array = cv2.imread(img_path)\n",
    "        if img_array is not None:                          # skip unreadable files\n",
    "            img_array = cv2.resize(img_array, (64, 64))   # resize to fixed 64x64 pixels\n",
    "            data.append(img_array)\n",
    "            labels.append(label_dict[category])\n",
    "            count += 1\n",
    "\n",
    "data = np.array(data) / 255.0   # normalize pixel values from [0,255] to [0,1]\n",
    "labels = np.array(labels)\n",
    "print(\"Dataset shape:\", data.shape)\n",
    "print(\"Labels shape:\", labels.shape)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "af827a9a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Total images: 7600\n",
      "Image shape: (64, 64, 3)\n",
      "Number of classes: 38\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 164388 characters]",
      "text/plain": [
       "<Figure size 1400x500 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 99892 characters]",
      "text/plain": [
       "<Figure size 1500x300 with 5 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 3. Exploratory Data Analysis (EDA)\n",
    "print(\"Total images:\", len(data))\n",
    "print(\"Image shape:\", data[0].shape)\n",
    "print(\"Number of classes:\", len(categories))\n",
    "\n",
    "# Class distribution bar chart\n",
    "class_counts = {cat: int((labels == idx).sum()) for cat, idx in label_dict.items()}\n",
    "plt.figure(figsize=(14, 5))\n",
    "plt.bar(class_counts.keys(), class_counts.values())\n",
    "plt.xticks(rotation=90)\n",
    "plt.title(\"Number of Images per Disease Class\")\n",
    "plt.xlabel(\"Class\")\n",
    "plt.ylabel(\"Count\")\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "# Sample images from first 5 classes\n",
    "plt.figure(figsize=(15, 3))\n",
    "for i, category in enumerate(categories[:5]):\n",
    "    idx = np.where(labels == label_dict[category])[0][0]  # index of first image in class\n",
    "    plt.subplot(1, 5, i + 1)\n",
    "    plt.imshow(cv2.cvtColor((data[idx] * 255).astype(np.uint8), cv2.COLOR_BGR2RGB))\n",
    "    plt.title(category[:15], fontsize=8)\n",
    "    plt.axis('off')\n",
    "plt.suptitle(\"Sample Images per Class\")\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2722e437",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Train samples: 6080\n",
      "Test samples:  1520\n"
     ]
    }
   ],
   "source": [
    "# 4. Split into Training and Testing Sets\n",
    "X_train, X_test, y_train, y_test = train_test_split(data, labels, test_size=0.2, random_state=42)\n",
    "\n",
    "num_classes = len(categories)\n",
    "# One-hot encode labels: e.g. class 2 of 5 → [0, 0, 1, 0, 0]\n",
    "y_train = to_categorical(y_train, num_classes)\n",
    "y_test  = to_categorical(y_test,  num_classes)\n",
    "print(\"Train samples:\", X_train.shape[0])\n",
    "print(\"Test samples: \", X_test.shape[0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "58b4fb5d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\">Model: \"sequential_1\"</span>\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1mModel: \"sequential_1\"\u001b[0m\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\">┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃<span style=\"font-weight: bold\"> Layer (type)                    </span>┃<span style=\"font-weight: bold\"> Output Shape           </span>┃<span style=\"font-weight: bold\">       Param # </span>┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ conv2d_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv2D</span>)               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">62</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">62</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">32</span>)     │           <span style=\"color: #00af00; text-decoration-color: #00af00\">896</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling2d_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">MaxPooling2D</span>)  │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">31</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">31</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">32</span>)     │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ conv2d_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Conv2D</span>)               │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">29</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">29</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)     │        <span style=\"color: #00af00; text-decoration-color: #00af00\">18,496</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling2d_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">MaxPooling2D</span>)  │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">14</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">14</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">64</span>)     │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ flatten_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Flatten</span>)             │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">12544</span>)          │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>)            │     <span style=\"color: #00af00; text-decoration-color: #00af00\">1,605,760</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_1 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dropout</span>)             │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">128</span>)            │             <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_3 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Dense</span>)                 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">38</span>)             │         <span style=\"color: #00af00; text-decoration-color: #00af00\">4,902</span> │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
       "</pre>\n"
      ],
      "text/plain": [
       "┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
       "┃\u001b[1m \u001b[0m\u001b[1mLayer (type)                   \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape          \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m      Param #\u001b[0m\u001b[1m \u001b[0m┃\n",
       "┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
       "│ conv2d_2 (\u001b[38;5;33mConv2D\u001b[0m)               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m62\u001b[0m, \u001b[38;5;34m62\u001b[0m, \u001b[38;5;34m32\u001b[0m)     │           \u001b[38;5;34m896\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling2d_2 (\u001b[38;5;33mMaxPooling2D\u001b[0m)  │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m31\u001b[0m, \u001b[38;5;34m31\u001b[0m, \u001b[38;5;34m32\u001b[0m)     │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ conv2d_3 (\u001b[38;5;33mConv2D\u001b[0m)               │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m29\u001b[0m, \u001b[38;5;34m29\u001b[0m, \u001b[38;5;34m64\u001b[0m)     │        \u001b[38;5;34m18,496\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ max_pooling2d_3 (\u001b[38;5;33mMaxPooling2D\u001b[0m)  │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m14\u001b[0m, \u001b[38;5;34m14\u001b[0m, \u001b[38;5;34m64\u001b[0m)     │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ flatten_1 (\u001b[38;5;33mFlatten\u001b[0m)             │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12544\u001b[0m)          │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_2 (\u001b[38;5;33mDense\u001b[0m)                 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m)            │     \u001b[38;5;34m1,605,760\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dropout_1 (\u001b[38;5;33mDropout\u001b[0m)             │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m128\u001b[0m)            │             \u001b[38;5;34m0\u001b[0m │\n",
       "├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
       "│ dense_3 (\u001b[38;5;33mDense\u001b[0m)                 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m38\u001b[0m)             │         \u001b[38;5;34m4,902\u001b[0m │\n",
       "└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Total params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">1,630,054</span> (6.22 MB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Total params: \u001b[0m\u001b[38;5;34m1,630,054\u001b[0m (6.22 MB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">1,630,054</span> (6.22 MB)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m1,630,054\u001b[0m (6.22 MB)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/html": [
       "<pre style=\"white-space:pre;overflow-x:auto;line-height:normal;font-family:Menlo,'DejaVu Sans Mono',consolas,'Courier New',monospace\"><span style=\"font-weight: bold\"> Non-trainable params: </span><span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> (0.00 B)\n",
       "</pre>\n"
      ],
      "text/plain": [
       "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 5. Build the CNN Model\n",
    "model = Sequential()\n",
    "\n",
    "model.add(Input(shape=(64, 64, 3)))               # input: 64x64 RGB image\n",
    "model.add(Conv2D(32, (3, 3), activation='relu'))  # 32 filters, detect basic features\n",
    "model.add(MaxPooling2D(2, 2))                      # downsample by 2x\n",
    "\n",
    "model.add(Conv2D(64, (3, 3), activation='relu'))  # 64 filters, detect complex features\n",
    "model.add(MaxPooling2D(2, 2))\n",
    "\n",
    "model.add(Flatten())                              # convert 2D feature maps to 1D vector\n",
    "\n",
    "model.add(Dense(128, activation='relu'))          # fully connected layer\n",
    "model.add(Dropout(0.5))                           # randomly drop 50% neurons to reduce overfitting\n",
    "\n",
    "model.add(Dense(num_classes, activation='softmax'))  # output: probability for each class\n",
    "\n",
    "model.summary()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "1b78aece",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 6. Compile the Model\n",
    "# categorical_crossentropy: standard loss for multi-class classification with one-hot labels\n",
    "model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "ddf42094",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "W0000 00:00:1777820220.390755   83765 cpu_allocator_impl.cc:82] Allocation of 239075328 exceeds 10% of free system memory.\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m12s\u001b[0m 73ms/step - accuracy: 0.1151 - loss: 3.3164 - val_accuracy: 0.2689 - val_loss: 2.6826\n",
      "Epoch 2/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 70ms/step - accuracy: 0.3020 - loss: 2.4561 - val_accuracy: 0.5099 - val_loss: 1.9074\n",
      "Epoch 3/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 70ms/step - accuracy: 0.4200 - loss: 2.0002 - val_accuracy: 0.5789 - val_loss: 1.5372\n",
      "Epoch 4/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 70ms/step - accuracy: 0.4953 - loss: 1.7063 - val_accuracy: 0.6209 - val_loss: 1.3292\n",
      "Epoch 5/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.5549 - loss: 1.4903 - val_accuracy: 0.6414 - val_loss: 1.2810\n",
      "Epoch 6/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.6028 - loss: 1.3174 - val_accuracy: 0.6579 - val_loss: 1.1252\n",
      "Epoch 7/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.6320 - loss: 1.1883 - val_accuracy: 0.6908 - val_loss: 1.0678\n",
      "Epoch 8/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.6819 - loss: 1.0257 - val_accuracy: 0.6776 - val_loss: 1.0920\n",
      "Epoch 9/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.6941 - loss: 0.9483 - val_accuracy: 0.6965 - val_loss: 0.9725\n",
      "Epoch 10/10\n",
      "\u001b[1m152/152\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m11s\u001b[0m 71ms/step - accuracy: 0.7259 - loss: 0.8547 - val_accuracy: 0.7196 - val_loss: 0.9444\n"
     ]
    }
   ],
   "source": [
    "# 7. Train the Model\n",
    "history = model.fit(X_train, y_train, epochs=10, batch_size=32, validation_split=0.2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "916907f3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m48/48\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step - accuracy: 0.7105 - loss: 0.9758\n",
      "Test Loss: 0.9758\n",
      "Test Accuracy: 71.05%\n"
     ]
    }
   ],
   "source": [
    "# 8. Evaluate the Model on Test Data\n",
    "loss, accuracy = model.evaluate(X_test, y_test)\n",
    "print(f\"Test Loss: {loss:.4f}\")\n",
    "print(f\"Test Accuracy: {accuracy*100:.2f}%\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "4f2350c6",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 46328 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 42168 characters]",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 9. Plot Training vs Validation Accuracy\n",
    "plt.plot(history.history['accuracy'], label='Training Accuracy')\n",
    "plt.plot(history.history['val_accuracy'], label='Validation Accuracy')\n",
    "plt.title('CNN Model Accuracy Over Epochs')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Accuracy')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()\n",
    "\n",
    "# 10. Plot Training vs Validation Loss\n",
    "plt.plot(history.history['loss'], label='Training Loss')\n",
    "plt.plot(history.history['val_loss'], label='Validation Loss')\n",
    "plt.title('CNN Model Loss Over Epochs')\n",
    "plt.xlabel('Epoch')\n",
    "plt.ylabel('Loss')\n",
    "plt.legend()\n",
    "plt.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "050a8c5b",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\u001b[1m48/48\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 14ms/step\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 395556 characters]",
      "text/plain": [
       "<Figure size 1400x1200 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Classification Report:\n",
      "\n",
      "                                                    precision    recall  f1-score   support\n",
      "\n",
      "                                Apple___Apple_scab       0.62      0.58      0.60        48\n",
      "                                 Apple___Black_rot       0.74      0.56      0.64        41\n",
      "                          Apple___Cedar_apple_rust       0.67      0.78      0.72        49\n",
      "                                   Apple___healthy       0.52      0.70      0.60        37\n",
      "                               Blueberry___healthy       0.47      0.81      0.60        31\n",
      "          Cherry_(including_sour)___Powdery_mildew       0.88      0.73      0.80        52\n",
      "                 Cherry_(including_sour)___healthy       0.74      0.74      0.74        35\n",
      "Corn_(maize)___Cercospora_leaf_spot Gray_leaf_spot       0.87      0.62      0.72        55\n",
      "                       Corn_(maize)___Common_rust_       0.92      1.00      0.96        47\n",
      "               Corn_(maize)___Northern_Leaf_Blight       0.75      0.95      0.84        42\n",
      "                            Corn_(maize)___healthy       0.94      1.00      0.97        33\n",
      "                                 Grape___Black_rot       0.77      0.64      0.70        42\n",
      "                      Grape___Esca_(Black_Measles)       0.76      0.74      0.75        47\n",
      "        Grape___Leaf_blight_(Isariopsis_Leaf_Spot)       1.00      0.91      0.96        35\n",
      "                                   Grape___healthy       0.60      0.94      0.73        36\n",
      "          Orange___Haunglongbing_(Citrus_greening)       0.88      0.93      0.90        40\n",
      "                            Peach___Bacterial_spot       0.58      0.62      0.60        34\n",
      "                                   Peach___healthy       0.62      0.91      0.74        33\n",
      "                     Pepper,_bell___Bacterial_spot       0.62      0.47      0.54        32\n",
      "                            Pepper,_bell___healthy       0.57      0.48      0.52        42\n",
      "                             Potato___Early_blight       0.72      0.67      0.69        39\n",
      "                              Potato___Late_blight       0.50      0.59      0.54        51\n",
      "                                  Potato___healthy       0.52      0.66      0.58        38\n",
      "                               Raspberry___healthy       0.88      0.64      0.74        45\n",
      "                                 Soybean___healthy       0.86      0.83      0.85        36\n",
      "                           Squash___Powdery_mildew       0.86      0.97      0.91        32\n",
      "                          Strawberry___Leaf_scorch       0.71      0.83      0.77        36\n",
      "                              Strawberry___healthy       0.91      0.87      0.89        45\n",
      "                           Tomato___Bacterial_spot       0.89      0.74      0.81        42\n",
      "                             Tomato___Early_blight       0.61      0.26      0.36        43\n",
      "                              Tomato___Late_blight       0.44      0.47      0.46        38\n",
      "                                Tomato___Leaf_Mold       0.48      0.36      0.41        39\n",
      "                       Tomato___Septoria_leaf_spot       0.62      0.43      0.51        30\n",
      "     Tomato___Spider_mites Two-spotted_spider_mite       0.62      0.50      0.55        36\n",
      "                              Tomato___Target_Spot       0.44      0.73      0.55        33\n",
      "            Tomato___Tomato_Yellow_Leaf_Curl_Virus       0.92      0.83      0.87        41\n",
      "                      Tomato___Tomato_mosaic_virus       0.88      0.86      0.87        43\n",
      "                                  Tomato___healthy       0.94      0.74      0.83        42\n",
      "\n",
      "                                          accuracy                           0.71      1520\n",
      "                                         macro avg       0.72      0.71      0.71      1520\n",
      "                                      weighted avg       0.73      0.71      0.71      1520\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 11. Confusion Matrix and Classification Report\n",
    "y_pred = np.argmax(model.predict(X_test), axis=1)  # predicted class index\n",
    "y_true = np.argmax(y_test, axis=1)                  # actual class index (from one-hot)\n",
    "\n",
    "cm = confusion_matrix(y_true, y_pred)\n",
    "plt.figure(figsize=(14, 12))\n",
    "sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n",
    "            xticklabels=categories, yticklabels=categories)\n",
    "plt.title('Confusion Matrix')\n",
    "plt.ylabel('Actual')\n",
    "plt.xlabel('Predicted')\n",
    "plt.xticks(rotation=90)\n",
    "plt.tight_layout()\n",
    "plt.show()\n",
    "\n",
    "print(\"\\nClassification Report:\\n\")\n",
    "print(classification_report(y_true, y_pred, target_names=categories))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a0a20c98-de25-44bd-9748-9f8f7a3d25cb",
   "metadata": {},
   "source": [
    "---"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
