{ "nbformat": 4, "nbformat_minor": 0, "metadata": { "colab": { "provenance": [] }, "kernelspec": { "name": "python3", "display_name": "Python 3" }, "language_info": { "name": "python" } }, "cells": [ { "cell_type": "code", "source": [ "import tensorflow as tf\n", "from tensorflow import keras\n", "from tensorflow.keras import layers\n", "from tensorflow.keras.callbacks import EarlyStopping, ModelCheckpoint\n", "import numpy as np\n", "import matplotlib.pyplot as plt\n", "from datasets import load_dataset\n", "from PIL import Image\n", "import os\n", "\n", "tf.random.set_seed(42)\n", "np.random.seed(42)" ], "metadata": { "id": "PmpwRxtW-EaZ" }, "execution_count": 5, "outputs": [] }, { "cell_type": "code", "source": [ "class BeanCNNClassifier:\n", " def __init__(self, img_size=(224, 224), num_classes=3):\n", " self.img_size = img_size\n", " self.num_classes = num_classes\n", " self.model = None\n", " self.history = None\n", "\n", " def load_and_preprocess_dataset(self):\n", " print(\"Loading beans dataset from Hugging Face...\")\n", "\n", " dataset = load_dataset(\"AI-Lab-Makerere/beans\")\n", "\n", " self.class_names = dataset['train'].features['labels'].names\n", " print(f\"Classes: {self.class_names}\")\n", "\n", " train_images, train_labels = self._process_split(dataset['train'])\n", " val_images, val_labels = self._process_split(dataset['validation'])\n", " test_images, test_labels = self._process_split(dataset['test'])\n", "\n", " print(f\"Training samples: {len(train_images)}\")\n", " print(f\"Validation samples: {len(val_images)}\")\n", " print(f\"Test samples: {len(test_images)}\")\n", "\n", " return (train_images, train_labels), (val_images, val_labels), (test_images, test_labels)\n", "\n", " def _process_split(self, split):\n", " images = []\n", " labels = []\n", "\n", " for item in split:\n", " img = item['image']\n", " if img.mode != 'RGB':\n", " img = img.convert('RGB')\n", "\n", " img = img.resize(self.img_size)\n", " img_array = np.array(img) / 255.0\n", "\n", " images.append(img_array)\n", " labels.append(item['labels'])\n", "\n", " return np.array(images), np.array(labels)\n", "\n", " def build_cnn_model(self):\n", " model = keras.Sequential([\n", " layers.Conv2D(32, (3, 3), activation='relu',\n", " input_shape=(*self.img_size, 3)),\n", " layers.MaxPooling2D((2, 2)),\n", " layers.Dropout(0.25),\n", "\n", " layers.Conv2D(64, (3, 3), activation='relu'),\n", " layers.MaxPooling2D((2, 2)),\n", " layers.Dropout(0.25),\n", "\n", " layers.Conv2D(128, (3, 3), activation='relu'),\n", " layers.MaxPooling2D((2, 2)),\n", " layers.Dropout(0.25),\n", "\n", " layers.Conv2D(256, (3, 3), activation='relu'),\n", " layers.MaxPooling2D((2, 2)),\n", " layers.Dropout(0.25),\n", "\n", " layers.Flatten(),\n", " layers.Dense(512, activation='relu'),\n", " layers.Dropout(0.5),\n", " layers.Dense(256, activation='relu'),\n", " layers.Dropout(0.5),\n", " layers.Dense(self.num_classes, activation='softmax')\n", " ])\n", "\n", " model.compile(\n", " optimizer='adam',\n", " loss='sparse_categorical_crossentropy',\n", " metrics=['accuracy']\n", " )\n", "\n", " self.model = model\n", " return model\n", "\n", " def train_model(self, train_data, val_data, epochs=50, batch_size=32):\n", " train_images, train_labels = train_data\n", " val_images, val_labels = val_data\n", "\n", " early_stopping = EarlyStopping(\n", " monitor='val_loss',\n", " patience=10,\n", " restore_best_weights=True,\n", " verbose=1\n", " )\n", "\n", " model_checkpoint = ModelCheckpoint(\n", " 'best_bean_cnn_model.h5',\n", " monitor='val_accuracy',\n", " save_best_only=True,\n", " verbose=1\n", " )\n", "\n", " callbacks = [early_stopping, model_checkpoint]\n", "\n", " print(\"Starting training...\")\n", " self.history = self.model.fit(\n", " train_images, train_labels,\n", " batch_size=batch_size,\n", " epochs=epochs,\n", " validation_data=(val_images, val_labels),\n", " callbacks=callbacks,\n", " verbose=1\n", " )\n", "\n", " return self.history\n", "\n", " def evaluate_model(self, test_data):\n", " test_images, test_labels = test_data\n", "\n", " test_loss, test_accuracy = self.model.evaluate(\n", " test_images, test_labels, verbose=0\n", " )\n", "\n", " print(f\"\\nTest Results:\")\n", " print(f\"Test Loss: {test_loss:.4f}\")\n", " print(f\"Test Accuracy: {test_accuracy:.4f}\")\n", "\n", " return test_loss, test_accuracy\n", "\n", " def plot_training_history(self):\n", " if self.history is None:\n", " print(\"No training history available. Train the model first.\")\n", " return\n", "\n", " fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))\n", "\n", " ax1.plot(self.history.history['accuracy'], label='Training Accuracy')\n", " ax1.plot(self.history.history['val_accuracy'], label='Validation Accuracy')\n", " ax1.set_title('Model Accuracy')\n", " ax1.set_xlabel('Epoch')\n", " ax1.set_ylabel('Accuracy')\n", " ax1.legend()\n", " ax1.grid(True)\n", "\n", " ax2.plot(self.history.history['loss'], label='Training Loss')\n", " ax2.plot(self.history.history['val_loss'], label='Validation Loss')\n", " ax2.set_title('Model Loss')\n", " ax2.set_xlabel('Epoch')\n", " ax2.set_ylabel('Loss')\n", " ax2.legend()\n", " ax2.grid(True)\n", "\n", " plt.tight_layout()\n", " plt.savefig('training_history.png', dpi=300, bbox_inches='tight')\n", " plt.show()\n", "\n", " def print_model_summary(self):\n", " if self.model is None:\n", " print(\"Model not built yet. Call build_cnn_model() first.\")\n", " return\n", "\n", " print(\"\\nModel Architecture:\")\n", " print(\"=\" * 50)\n", " self.model.summary()\n", "\n", " def get_training_report(self):\n", " if self.history is None:\n", " print(\"No training history available.\")\n", " return\n", "\n", " final_train_acc = self.history.history['accuracy'][-1]\n", " final_val_acc = self.history.history['val_accuracy'][-1]\n", " final_train_loss = self.history.history['loss'][-1]\n", " final_val_loss = self.history.history['val_loss'][-1]\n", "\n", " best_val_acc = max(self.history.history['val_accuracy'])\n", " best_val_acc_epoch = self.history.history['val_accuracy'].index(best_val_acc) + 1\n", "\n", " print(\"\\n\" + \"=\"*60)\n", " print(\"TRAINING REPORT\")\n", " print(\"=\"*60)\n", " print(f\"Total Epochs Trained: {len(self.history.history['accuracy'])}\")\n", " print(f\"Best Validation Accuracy: {best_val_acc:.4f} (Epoch {best_val_acc_epoch})\")\n", " print(\"\\nFinal Epoch Metrics:\")\n", " print(f\" Training Accuracy: {final_train_acc:.4f}\")\n", " print(f\" Validation Accuracy: {final_val_acc:.4f}\")\n", " print(f\" Training Loss: {final_train_loss:.4f}\")\n", " print(f\" Validation Loss: {final_val_loss:.4f}\")\n", " print(\"=\"*60)" ], "metadata": { "id": "4dsBhybF-i4n" }, "execution_count": 6, "outputs": [] }, { "cell_type": "code", "source": [ "!pip install --upgrade datasets" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/" }, "id": "BAU9G1e5-8D9", "outputId": "a1d19a57-a8b1-46b0-bed1-ab44a3e5cce4" }, "execution_count": 7, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Requirement already satisfied: datasets in /usr/local/lib/python3.11/dist-packages (3.6.0)\n", "Requirement already satisfied: filelock in /usr/local/lib/python3.11/dist-packages (from datasets) (3.18.0)\n", "Requirement already satisfied: numpy>=1.17 in /usr/local/lib/python3.11/dist-packages (from datasets) (2.0.2)\n", "Requirement already satisfied: pyarrow>=15.0.0 in /usr/local/lib/python3.11/dist-packages (from datasets) (18.1.0)\n", "Requirement already satisfied: dill<0.3.9,>=0.3.0 in /usr/local/lib/python3.11/dist-packages (from datasets) (0.3.7)\n", "Requirement already satisfied: pandas in /usr/local/lib/python3.11/dist-packages (from datasets) (2.2.2)\n", "Requirement already satisfied: requests>=2.32.2 in /usr/local/lib/python3.11/dist-packages (from datasets) (2.32.3)\n", "Requirement already satisfied: tqdm>=4.66.3 in /usr/local/lib/python3.11/dist-packages (from datasets) (4.67.1)\n", "Requirement already satisfied: xxhash in /usr/local/lib/python3.11/dist-packages (from datasets) (3.5.0)\n", "Requirement already satisfied: multiprocess<0.70.17 in /usr/local/lib/python3.11/dist-packages (from datasets) (0.70.15)\n", "Requirement already satisfied: fsspec<=2025.3.0,>=2023.1.0 in /usr/local/lib/python3.11/dist-packages (from fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (2025.3.0)\n", "Requirement already satisfied: huggingface-hub>=0.24.0 in /usr/local/lib/python3.11/dist-packages (from datasets) (0.32.2)\n", "Requirement already satisfied: packaging in /usr/local/lib/python3.11/dist-packages (from datasets) (24.2)\n", "Requirement already satisfied: pyyaml>=5.1 in /usr/local/lib/python3.11/dist-packages (from datasets) (6.0.2)\n", "Requirement already satisfied: aiohttp!=4.0.0a0,!=4.0.0a1 in /usr/local/lib/python3.11/dist-packages (from fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (3.11.15)\n", "Requirement already satisfied: typing-extensions>=3.7.4.3 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub>=0.24.0->datasets) (4.13.2)\n", "Requirement already satisfied: hf-xet<2.0.0,>=1.1.2 in /usr/local/lib/python3.11/dist-packages (from huggingface-hub>=0.24.0->datasets) (1.1.2)\n", "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (3.4.2)\n", "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (3.10)\n", "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (2.4.0)\n", "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.11/dist-packages (from requests>=2.32.2->datasets) (2025.4.26)\n", "Requirement already satisfied: python-dateutil>=2.8.2 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2.9.0.post0)\n", "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2025.2)\n", "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.11/dist-packages (from pandas->datasets) (2025.2)\n", "Requirement already satisfied: aiohappyeyeballs>=2.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (2.6.1)\n", "Requirement already satisfied: aiosignal>=1.1.2 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.3.2)\n", "Requirement already satisfied: attrs>=17.3.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (25.3.0)\n", "Requirement already satisfied: frozenlist>=1.1.1 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.6.0)\n", "Requirement already satisfied: multidict<7.0,>=4.5 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (6.4.4)\n", "Requirement already satisfied: propcache>=0.2.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (0.3.1)\n", "Requirement already satisfied: yarl<2.0,>=1.17.0 in /usr/local/lib/python3.11/dist-packages (from aiohttp!=4.0.0a0,!=4.0.0a1->fsspec[http]<=2025.3.0,>=2023.1.0->datasets) (1.20.0)\n", "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.11/dist-packages (from python-dateutil>=2.8.2->pandas->datasets) (1.17.0)\n" ] } ] }, { "cell_type": "code", "source": [ "def main():\n", " print(\"Bean Leaf Disease Classification - Baseline CNN\")\n", " print(\"=\"*50)\n", "\n", " classifier = BeanCNNClassifier(img_size=(224, 224), num_classes=3)\n", "\n", " train_data, val_data, test_data = classifier.load_and_preprocess_dataset()\n", "\n", " model = classifier.build_cnn_model()\n", " classifier.print_model_summary()\n", "\n", " history = classifier.train_model(\n", " train_data, val_data,\n", " epochs=50,\n", " batch_size=32\n", " )\n", "\n", " classifier.get_training_report()\n", "\n", " classifier.evaluate_model(test_data)\n", "\n", " classifier.plot_training_history()\n", "\n", " print(\"\\nTraining completed! Model saved as 'best_bean_cnn_model.h5'\")\n", " print(\"Training history plot saved as 'training_history.png'\")\n", "\n", "if __name__ == \"__main__\":\n", " main()" ], "metadata": { "colab": { "base_uri": "https://localhost:8080/", "height": 1000 }, "id": "EiVWQwc_-niU", "outputId": "470ea8f8-f327-4889-82c7-7f78c5dc4335" }, "execution_count": 8, "outputs": [ { "output_type": "stream", "name": "stdout", "text": [ "Bean Leaf Disease Classification - Baseline CNN\n", "==================================================\n", "Loading beans dataset from Hugging Face...\n", "Classes: ['angular_leaf_spot', 'bean_rust', 'healthy']\n", "Training samples: 1034\n", "Validation samples: 133\n", "Test samples: 128\n", "\n", "Model Architecture:\n", "==================================================\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "\u001b[1mModel: \"sequential_1\"\u001b[0m\n" ], "text/html": [ "
Model: \"sequential_1\"\n",
"\n"
]
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"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_4 (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m222\u001b[0m, \u001b[38;5;34m222\u001b[0m, \u001b[38;5;34m32\u001b[0m) │ \u001b[38;5;34m896\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_4 (\u001b[38;5;33mMaxPooling2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m111\u001b[0m, \u001b[38;5;34m111\u001b[0m, \u001b[38;5;34m32\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_6 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m111\u001b[0m, \u001b[38;5;34m111\u001b[0m, \u001b[38;5;34m32\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_5 (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m109\u001b[0m, \u001b[38;5;34m109\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m18,496\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_5 (\u001b[38;5;33mMaxPooling2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m54\u001b[0m, \u001b[38;5;34m54\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_7 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m54\u001b[0m, \u001b[38;5;34m54\u001b[0m, \u001b[38;5;34m64\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_6 (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m52\u001b[0m, \u001b[38;5;34m52\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m73,856\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_6 (\u001b[38;5;33mMaxPooling2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_8 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m26\u001b[0m, \u001b[38;5;34m128\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_7 (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m24\u001b[0m, \u001b[38;5;34m24\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m295,168\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_7 (\u001b[38;5;33mMaxPooling2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_9 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m12\u001b[0m, \u001b[38;5;34m256\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;34m36864\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;34m512\u001b[0m) │ \u001b[38;5;34m18,874,880\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_10 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_4 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m131,328\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_11 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_5 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m771\u001b[0m │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n"
],
"text/html": [
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓\n",
"┃ Layer (type) ┃ Output Shape ┃ Param # ┃\n",
"┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩\n",
"│ conv2d_4 (Conv2D) │ (None, 222, 222, 32) │ 896 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_4 (MaxPooling2D) │ (None, 111, 111, 32) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_6 (Dropout) │ (None, 111, 111, 32) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_5 (Conv2D) │ (None, 109, 109, 64) │ 18,496 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_5 (MaxPooling2D) │ (None, 54, 54, 64) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_7 (Dropout) │ (None, 54, 54, 64) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_6 (Conv2D) │ (None, 52, 52, 128) │ 73,856 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_6 (MaxPooling2D) │ (None, 26, 26, 128) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_8 (Dropout) │ (None, 26, 26, 128) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_7 (Conv2D) │ (None, 24, 24, 256) │ 295,168 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d_7 (MaxPooling2D) │ (None, 12, 12, 256) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_9 (Dropout) │ (None, 12, 12, 256) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ flatten_1 (Flatten) │ (None, 36864) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_3 (Dense) │ (None, 512) │ 18,874,880 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_10 (Dropout) │ (None, 512) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_4 (Dense) │ (None, 256) │ 131,328 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_11 (Dropout) │ (None, 256) │ 0 │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_5 (Dense) │ (None, 3) │ 771 │\n",
"└─────────────────────────────────┴────────────────────────┴───────────────┘\n",
"\n"
]
},
"metadata": {}
},
{
"output_type": "display_data",
"data": {
"text/plain": [
"\u001b[1m Total params: \u001b[0m\u001b[38;5;34m19,395,395\u001b[0m (73.99 MB)\n"
],
"text/html": [
"Total params: 19,395,395 (73.99 MB)\n", "\n" ] }, "metadata": {} }, { "output_type": "display_data", "data": { "text/plain": [ "\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m19,395,395\u001b[0m (73.99 MB)\n" ], "text/html": [ "
Trainable params: 19,395,395 (73.99 MB)\n", "\n" ] }, "metadata": {} }, { "output_type": "display_data", "data": { "text/plain": [ "\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m0\u001b[0m (0.00 B)\n" ], "text/html": [ "
Non-trainable params: 0 (0.00 B)\n", "\n" ] }, "metadata": {} }, { "output_type": "stream", "name": "stdout", "text": [ "Starting training...\n", "Epoch 1/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.3158 - loss: 1.4492\n", "Epoch 1: val_accuracy improved from -inf to 0.39098, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m144s\u001b[0m 4s/step - accuracy: 0.3167 - loss: 1.4424 - val_accuracy: 0.3910 - val_loss: 1.0763\n", "Epoch 2/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.4567 - loss: 1.0373\n", "Epoch 2: val_accuracy improved from 0.39098 to 0.56391, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m139s\u001b[0m 4s/step - accuracy: 0.4581 - loss: 1.0355 - val_accuracy: 0.5639 - val_loss: 0.9554\n", "Epoch 3/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.5135 - loss: 0.9583\n", "Epoch 3: val_accuracy improved from 0.56391 to 0.63910, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m146s\u001b[0m 4s/step - accuracy: 0.5150 - loss: 0.9566 - val_accuracy: 0.6391 - val_loss: 0.7900\n", "Epoch 4/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6088 - loss: 0.8670\n", "Epoch 4: val_accuracy improved from 0.63910 to 0.71429, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m197s\u001b[0m 4s/step - accuracy: 0.6097 - loss: 0.8653 - val_accuracy: 0.7143 - val_loss: 0.6763\n", "Epoch 5/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6482 - loss: 0.8036\n", "Epoch 5: val_accuracy did not improve from 0.71429\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m140s\u001b[0m 4s/step - accuracy: 0.6494 - loss: 0.8019 - val_accuracy: 0.7143 - val_loss: 0.6661\n", "Epoch 6/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6738 - loss: 0.7581\n", "Epoch 6: val_accuracy improved from 0.71429 to 0.74436, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m138s\u001b[0m 4s/step - accuracy: 0.6748 - loss: 0.7563 - val_accuracy: 0.7444 - val_loss: 0.5999\n", "Epoch 7/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6801 - loss: 0.7127\n", "Epoch 7: val_accuracy improved from 0.74436 to 0.75188, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m149s\u001b[0m 4s/step - accuracy: 0.6807 - loss: 0.7117 - val_accuracy: 0.7519 - val_loss: 0.6230\n", "Epoch 8/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6962 - loss: 0.6683\n", "Epoch 8: val_accuracy did not improve from 0.75188\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m193s\u001b[0m 4s/step - accuracy: 0.6965 - loss: 0.6674 - val_accuracy: 0.7519 - val_loss: 0.5376\n", "Epoch 9/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.6868 - loss: 0.6531\n", "Epoch 9: val_accuracy improved from 0.75188 to 0.77444, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m148s\u001b[0m 4s/step - accuracy: 0.6873 - loss: 0.6522 - val_accuracy: 0.7744 - val_loss: 0.5254\n", "Epoch 10/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.7173 - loss: 0.6178\n", "Epoch 10: val_accuracy did not improve from 0.77444\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m195s\u001b[0m 4s/step - accuracy: 0.7184 - loss: 0.6162 - val_accuracy: 0.7519 - val_loss: 0.5039\n", "Epoch 11/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.7275 - loss: 0.5906\n", "Epoch 11: val_accuracy did not improve from 0.77444\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m151s\u001b[0m 4s/step - accuracy: 0.7282 - loss: 0.5895 - val_accuracy: 0.7368 - val_loss: 0.5171\n", "Epoch 12/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.7727 - loss: 0.5156\n", "Epoch 12: val_accuracy improved from 0.77444 to 0.78195, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m200s\u001b[0m 4s/step - accuracy: 0.7733 - loss: 0.5146 - val_accuracy: 0.7820 - val_loss: 0.5415\n", "Epoch 13/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.8030 - loss: 0.4460\n", "Epoch 13: val_accuracy did not improve from 0.78195\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m202s\u001b[0m 4s/step - accuracy: 0.8040 - loss: 0.4447 - val_accuracy: 0.7820 - val_loss: 0.5051\n", "Epoch 14/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.7861 - loss: 0.5163\n", "Epoch 14: val_accuracy improved from 0.78195 to 0.80451, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m156s\u001b[0m 5s/step - accuracy: 0.7871 - loss: 0.5137 - val_accuracy: 0.8045 - val_loss: 0.4885\n", "Epoch 15/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.8406 - loss: 0.3717\n", "Epoch 15: val_accuracy improved from 0.80451 to 0.82707, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m192s\u001b[0m 4s/step - accuracy: 0.8412 - loss: 0.3709 - val_accuracy: 0.8271 - val_loss: 0.4223\n", "Epoch 16/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.8246 - loss: 0.4097\n", "Epoch 16: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m193s\u001b[0m 4s/step - accuracy: 0.8252 - loss: 0.4087 - val_accuracy: 0.7895 - val_loss: 0.5063\n", "Epoch 17/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.8407 - loss: 0.3963\n", "Epoch 17: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m157s\u001b[0m 5s/step - accuracy: 0.8409 - loss: 0.3954 - val_accuracy: 0.7744 - val_loss: 0.5320\n", "Epoch 18/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.8572 - loss: 0.3609\n", "Epoch 18: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m189s\u001b[0m 4s/step - accuracy: 0.8583 - loss: 0.3590 - val_accuracy: 0.8271 - val_loss: 0.5313\n", "Epoch 19/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9287 - loss: 0.2286\n", "Epoch 19: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m140s\u001b[0m 4s/step - accuracy: 0.9290 - loss: 0.2271 - val_accuracy: 0.8271 - val_loss: 0.5223\n", "Epoch 20/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9172 - loss: 0.1756\n", "Epoch 20: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m147s\u001b[0m 4s/step - accuracy: 0.9174 - loss: 0.1757 - val_accuracy: 0.8045 - val_loss: 0.5673\n", "Epoch 21/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9025 - loss: 0.2481\n", "Epoch 21: val_accuracy did not improve from 0.82707\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m203s\u001b[0m 4s/step - accuracy: 0.9031 - loss: 0.2465 - val_accuracy: 0.8271 - val_loss: 0.4534\n", "Epoch 22/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9501 - loss: 0.1532\n", "Epoch 22: val_accuracy improved from 0.82707 to 0.86466, saving model to best_bean_cnn_model.h5\n" ] }, { "output_type": "stream", "name": "stderr", "text": [ "WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`. \n" ] }, { "output_type": "stream", "name": "stdout", "text": [ "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\r\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m210s\u001b[0m 5s/step - accuracy: 0.9503 - loss: 0.1524 - val_accuracy: 0.8647 - val_loss: 0.5192\n", "Epoch 23/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9509 - loss: 0.1125\n", "Epoch 23: val_accuracy did not improve from 0.86466\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m150s\u001b[0m 4s/step - accuracy: 0.9511 - loss: 0.1125 - val_accuracy: 0.8271 - val_loss: 0.6103\n", "Epoch 24/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9465 - loss: 0.1388\n", "Epoch 24: val_accuracy did not improve from 0.86466\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m190s\u001b[0m 4s/step - accuracy: 0.9469 - loss: 0.1382 - val_accuracy: 0.8271 - val_loss: 0.6168\n", "Epoch 25/50\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 4s/step - accuracy: 0.9642 - loss: 0.1108\n", "Epoch 25: val_accuracy did not improve from 0.86466\n", "\u001b[1m33/33\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m141s\u001b[0m 4s/step - accuracy: 0.9641 - loss: 0.1108 - val_accuracy: 0.7744 - val_loss: 0.7844\n", "Epoch 25: early stopping\n", "Restoring model weights from the end of the best epoch: 15.\n", "\n", "============================================================\n", "TRAINING REPORT\n", "============================================================\n", "Total Epochs Trained: 25\n", "Best Validation Accuracy: 0.8647 (Epoch 22)\n", "\n", "Final Epoch Metrics:\n", " Training Accuracy: 0.9623\n", " Validation Accuracy: 0.7744\n", " Training Loss: 0.1085\n", " Validation Loss: 0.7844\n", "============================================================\n", "\n", "Test Results:\n", "Test Loss: 0.3682\n", "Test Accuracy: 0.8281\n" ] }, { "output_type": "display_data", "data": { "text/plain": [ "