Files
zeavis-edu/Machine_Learning/notebook.ipynb
T

992 lines
1.5 MiB
Plaintext
Raw Normal View History

2026-05-22 14:23:45 +08:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "fqNIt28_pKnS"
},
"source": [
"1. Persiapan Lingkungan"
]
2026-05-22 14:23:45 +08:00
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"id": "n6mBf6uO1VS6"
},
"outputs": [],
"source": [
"!pip install -q split-folders"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "dNC9QMXh1mWq",
"outputId": "132f1b20-f2b3-4acc-a0f5-7464e74ca613"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"TensorFlow Version: 2.20.0\n"
]
}
],
"source": [
"import os\n",
"import shutil\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"import splitfolders\n",
"import tarfile\n",
"import zipfile\n",
"from PIL import Image\n",
"\n",
"from pathlib import Path\n",
"from PIL import Image\n",
"from google.colab import drive\n",
"\n",
"\n",
"import tensorflow as tf\n",
"from tensorflow.keras import layers, models, callbacks\n",
"from tensorflow.keras.applications import EfficientNetV2B0\n",
"from sklearn.metrics import classification_report, confusion_matrix\n",
"\n",
"print(f\"TensorFlow Version: {tf.__version__}\")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "A6j2Vv8ypnrd"
},
"source": [
"2. Download dan Ekstraksi Dataset"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bsGJEEFs7Flg",
"outputId": "30228ce8-1b64-47f5-93f7-30632b2af1c5"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Mounted at /content/drive\n",
"Moving ZIP file to /content...\n",
"File successfully moved.\n",
"Extracting dataset...\n",
"Extraction completed!\n"
]
}
],
"source": [
"drive.mount('/content/drive')\n",
"\n",
"archive_path = '/content/drive/MyDrive/jagung/dataset_jagung.zip'\n",
"destination_path = '/content/dataset_jagung.zip'\n",
"extract_path = '/content/dataset'\n",
"\n",
"if os.path.exists(archive_path):\n",
" print(\"Moving ZIP file to /content...\")\n",
" shutil.copy(archive_path, destination_path)\n",
" print(\"File successfully moved.\")\n",
"else:\n",
" print(f\"Error: File not found at {archive_path}\")\n",
"\n",
"if os.path.exists(destination_path):\n",
" if not os.path.exists(extract_path) or len(os.listdir(extract_path)) == 0:\n",
" os.makedirs(extract_path, exist_ok=True)\n",
" print(\"Extracting dataset...\")\n",
" try:\n",
" with zipfile.ZipFile(destination_path, 'r') as zip_ref:\n",
" zip_ref.extractall(path=extract_path)\n",
" print(\"Extraction completed!\")\n",
" except Exception as e:\n",
" print(f\"Extraction failed: {e}\")\n",
" else:\n",
" print(\"Dataset is already extracted and ready for use.\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "148LNQ7Ips01"
},
"source": [
"4. Data Cleaning dan Validasi Gambat (RGB)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "bIPb9DIX1spd",
"outputId": "422957b6-c1e7-4f65-8834-14673b50a70e"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Starting data cleanup process...\n",
"Cleanup completed. Total of 0 problematic files removed.\n"
]
}
],
"source": [
"dataset_path = \"/content/dataset/dataset_jagung_v1\"\n",
"\n",
"def clean_image_data(directory):\n",
" removed_count = 0\n",
" for root, dirs, files in os.walk(directory):\n",
" for file in files:\n",
" file_path = os.path.join(root, file)\n",
" try:\n",
" img = Image.open(file_path)\n",
" img.verify()\n",
"\n",
" img = Image.open(file_path)\n",
" if img.mode != 'RGB':\n",
" img = img.convert('RGB')\n",
" img.save(file_path)\n",
" except Exception as e:\n",
" print(f\"Removing corrupt/invalid file: {file_path}\")\n",
" os.remove(file_path)\n",
" removed_count += 1\n",
" return removed_count\n",
"\n",
"print(\"Starting data cleanup process...\")\n",
"removed = clean_image_data(dataset_path)\n",
"print(f\"Cleanup completed. Total of {removed} problematic files removed.\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "YSQX48hTp3vW"
},
"source": [
"5. Data Spliting (70/15/15/)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "8Zg2hJw4a3RJ",
"outputId": "3daeef44-6e99-48d4-da8e-53f7f431a550"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Splitting dataset into Train, Validation, and Test...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Copying files: 7106 files [01:11, 99.29 files/s] "
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset splitting completed.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"output_dir = \"/content/dataset_split\"\n",
"\n",
"if os.path.exists(output_dir):\n",
" shutil.rmtree(output_dir)\n",
"\n",
"print(\"Splitting dataset into Train, Validation, and Test...\")\n",
"splitfolders.ratio(dataset_path, output=output_dir,\n",
" seed=42, ratio=(0.7, 0.15, 0.15),\n",
" group_prefix=None, move=False)\n",
"print(\"Dataset splitting completed.\")\n",
"\n",
"train_dir = os.path.join(output_dir, 'train')\n",
"val_dir = os.path.join(output_dir, 'val')\n",
"test_dir = os.path.join(output_dir, 'test')"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "F0q8ELD5qPAY"
},
"source": [
"6. Data Loader dan Augmentasi"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "rNU4YGv61wFX",
"outputId": "beda9f63-d52a-46dd-a28c-6d1ac17e7169"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 4973 files belonging to 4 classes.\n",
"Found 1063 files belonging to 4 classes.\n",
"Found 1070 files belonging to 4 classes.\n",
"Number of classes: 4\n",
"Class names: ['Bercak Daun', 'Daun Sehat', 'Karat Daun', 'hawar daun']\n"
]
}
],
"source": [
"BATCH_SIZE = 32\n",
"IMG_SIZE = (224, 224)\n",
"\n",
"train_ds = tf.keras.utils.image_dataset_from_directory(\n",
" train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"\n",
"val_ds = tf.keras.utils.image_dataset_from_directory(\n",
" val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"\n",
"test_ds = tf.keras.utils.image_dataset_from_directory(\n",
" test_dir, shuffle=False, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"\n",
"class_names = train_ds.class_names\n",
"NUM_CLASSES = len(class_names)\n",
"print(f\"Number of classes: {NUM_CLASSES}\")\n",
"print(f\"Class names: {class_names}\")\n",
"\n",
"def to_one_hot(image, label):\n",
" return image, tf.one_hot(label, NUM_CLASSES)\n",
"\n",
"train_ds = train_ds.map(to_one_hot, num_parallel_calls=tf.data.AUTOTUNE)\n",
"val_ds = val_ds.map(to_one_hot, num_parallel_calls=tf.data.AUTOTUNE)\n",
"test_ds = test_ds.map(to_one_hot, num_parallel_calls=tf.data.AUTOTUNE)\n",
"\n",
"AUTOTUNE = tf.data.AUTOTUNE\n",
"train_ds = train_ds.prefetch(buffer_size=AUTOTUNE)\n",
"val_ds = val_ds.prefetch(buffer_size=AUTOTUNE)\n",
"test_ds = test_ds.prefetch(buffer_size=AUTOTUNE)\n",
"\n",
"data_augmentation = tf.keras.Sequential([\n",
" layers.RandomFlip(\"horizontal_and_vertical\"),\n",
" layers.RandomRotation(0.2),\n",
" layers.RandomZoom(0.2),\n",
" layers.RandomTranslation(0.1, 0.1),\n",
" layers.RandomContrast(0.2),\n",
" layers.RandomBrightness(0.2)\n",
"], name=\"data_augmentation\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "BwSHXm-WqXeE"
},
"source": [
"7. Visualisasi Sample dan Hasil Augmentasi"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 610
},
"id": "tc8SYmZH3lGS",
"outputId": "44f07316-12d9-41a7-8069-5b108a335a18"
},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABJEAAAJRCAYAAAD1diY8AAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQABAABJREFUeJzs/XncJVdV74+/91DTGZ+55/SQhIQMBJAwJ+RKICiIoheviMogiIAoeuGlX1/K5O/q66oXFbwXwQE1CFdBRECZrkRmMAgkkBBCku4kPfczn7GGvffvj111nqfTTToJGFqtD68m3efUqdq1q2rVWp/9WWsJ55yjRo0aNWrUqFGjRo0aNWrUqFGjRo17gfxuD6BGjRo1atSoUaNGjRo1atSoUaPG2Y+aRKpRo0aNGjVq1KhRo0aNGjVq1KhxRtQkUo0aNWrUqFGjRo0aNWrUqFGjRo0zoiaRatSoUaNGjRo1atSoUaNGjRo1apwRNYlUo0aNGjVq1KhRo0aNGjVq1KhR44yoSaQaNWrUqFGjRo0aNWrUqFGjRo0aZ0RNItWoUaNGjRo1atSoUaNGjRo1atQ4I2oSqUaNGjVq1KhRo0aNGjVq1KhRo8YZUZNINWrUqFGjRo0aNWrUqFGjRo0aNc6ImkQ6C/C6170OIcR3exg1atSocQpq+1SjRo2zDd+uXRJC8HM/93PfwRH9+0Btz2vU+M7jP/Nz9fznP59Wq/XdHkaN7wJqEunbwE033cRP/MRPsGPHDqIoYvv27Tz3uc/lpptuelDHsWfPHp7xjGec8vm1116LUoqnPe1pjMfjB3VMhw8f5nWvex1f+cpX7tP2f/7nf44QYvInjmO2b9/ONddcw5ve9CZ6vd6/7YBr1PgPhto+fWvU9qlGje8Ozha7VKNGjRpniz3as2fPKT7G+eefz6tf/WqWl5cf1LE8mKjIt+pPo9HgnHPO4Qd+4Ad4+9vfTpqm3+0h1rgX1CTSA8R73/teHvnIR/JP//RPvOAFL+D//J//w0//9E9z3XXX8chHPpK/+7u/u8/7+rVf+zVGo9F3dHx/9Vd/xfOf/3yuvvpq3ve+9xHH8Xd0/2fC4cOHef3rX3+fg7QKb3jDG7j22mt5y1vewite8QoAXvnKV3LppZdy4403/huMtEaN/3io7dO9o7ZPNWo8+Djb7VKNGjX+8+Bss0cPf/jDufbaa7n22mv5wz/8Q66++mp+//d/n6c97Wnf1n7/PeAtb3kL1157LW9+85t50YtexPLyMi984Qt59KMfzd133/3dHl6NbwVX437jtttuc41Gw1144YXu+PHjJ3134sQJd+GFF7pms+luv/32e91Pv9//joxn9+7d7ulPf/rk3+9617ucUspdffXVbjQafUeOMRqNnDHmPm9//fXXO8C9/e1vv0/bv/3tb3eAu/7660/57p/+6Z9ckiRu9+7dbjgc3ucx1KjxnxG1fTozavtUo8aDi7PNLgHu5S9/+XdkX98tPJC5eO1rX+tq17/Gf3acbfbonn5ShVe96lUOcLfeeut35DjfqfFuxvOe9zzXbDYf0G8re3TixIlTvnvHO97hpJTuMY95zLc7xBr/RqiVSA8Av/M7v8NwOORtb3sb8/PzJ303NzfHW9/6VgaDAb/92789+byS7N188838+I//ONPT0zzxiU886bvNWFxc5JZbbmE4HN6vsf3N3/wNP/ETP8FVV13F+9///pNW+JeXl3nVq17FpZdeSqvVotPp8H3f933ccMMNJ+3jn//5nxFC8H//7//l137t19ixYweNRoP19fX7tI9//ud/5vLLLwfgBS94wUSm+Od//uf361wqfO/3fi+//uu/zp133sk73vGOyec33ngjz3/+89m3bx9xHLN161Ze+MIXsrS0dNLvn//857Nnz55T9nu6ea/qJLzvfe/jkksuIYoiLr74Yj784Q8/oLHXqPFgo7ZPtX2qUeNsw9lql870LN1555287GUv44ILLiBJEmZnZ3n2s5/NgQMHJtusrq6ilOJNb3rTSWORUjI7O4tzbvL5S1/6UrZu3Tr596c+9Sme/exnc8455xBFEbt27eIXf/EXT1E1VHVHbr/9dr7/+7+fdrvNc5/73Hs9t09/+tNcfvnlxHHMueeey1vf+tbTbvf2t7+d7/3e72VhYYEoirjooot4y1vecsp2Qghe97rXnfL5nj17eP7znz/5d5X++5nPfIZf+qVfYn5+nmazybOe9SxOnDhxr2OuUePBwNlqj+6JylZorU/6/JZbbuG//tf/yszMDHEc86hHPYr3v//9J21TPYef+MQneNnLXsbCwgI7d+6cfP+hD32IJz3pSbTbbTqdDpdffjnvfOc7J9/fV9t0OnzlK19hfn6eq666in6//4DO/bnPfS4vetGL+MIXvsDHPvax+z2uq666iquuuuqU/d7T5zpw4ABCCH73d3+Xt73tbZx77rlEUcTll1/O9ddf/4DG/p8F+syb1LgnPvCBD7Bnzx6uuOKK035/5ZVXsmfPHv7hH/7hlO+e/exnc/755/Obv/mbJzkW98Qf/uEf8vrXv57rrrvutA/B6fC3f/u3PPe5z+XKK6/kAx/4AEmSnPT9HXfcwfve9z6e/exns3fvXo4dO8Zb3/pWnvSkJ3HzzTezffv2k7b/jd/4DcIw5FWvehVpmhKGITfffPMZ9/HQhz6UN7zhDbzmNa/hZ37mZybz9PjHP/4+ncfp8JM/+ZP86q/+Kh/96Ed58YtfDMDHPvYx7rjjDl7wghewdetWbrrpJt72trdx00038fnPf/4BF7n79Kc/zXvf+15e9rKX0W63edOb3sSP/MiPcNdddzE7O/uAz6FGjQcDtX2q7VONGmcbzka7dF+epeuvv57Pfvaz/NiP/Rg7d+7kwIEDvOUtb+Gqq67i5ptvptFoMDU1xSWXXMInP/lJfv7nf36ybyEEy8vL3HzzzVx88cWAD4A2z8G73/1uhsMhL33pS5mdneVf/uVfePOb38zBgwd597vffdJ4i6Lgmmuu4YlPfCK/+7u/S6PR+Jbn9tWvfpWnPvWpzM/P87rXvY6iKHjta1/Lli1bTtn2LW95CxdffDHPfOYz0VrzgQ98gJe97GVYa3n5y19+xnn8VnjFK17B9PQ0r33tazlw4AC///u/z8/93M/x13/91w94nzVqfCdwNtqjPM9ZXFwEYDwe8+Uvf5k3vvGNXHnllezdu3ey3U033cQTnvAEduzYwa/8yq/QbDb5m7/5G37oh36Iv/3bv+VZz3rWSft92ctexvz8PK95zWsYDAaAJ5he+MIXcvHFF/P//X//H1NTU3z5y1/mwx/+MD/+4z8O3D/btBnXX38911xzDY961KP4+7//+1N8vfuDn/zJn+Rtb3sbH/3oR3nKU57ybY3rTHjnO99Jr9fjJS95CUIIfvu3f5sf/uEf5o477iAIgge83//Q+K7qoP4dYnV11QHuB3/wB+91u2c+85kOcOvr6865Dcnec57znFO2PZ28uPrsuuuuO+OYdu/e7bZv3+601u6qq65yg8HgtNuNx+NTUj7279/voihyb3jDGyafXXfddQ5w+/btOyU9477u4zuZLlKh2+26RzziEZN/ny515F3vepcD3Cc/+cnJZ8973vPc7t27T9n2dPMOuDAM3W233Tb57IYbbnCAe/Ob33yfzqVGje8WavtU26caNc42nI126b4+S6d7jj/3uc85wP3lX/7l5LOXv/zlbsuWLZN//9Iv/ZK78sor3cLCgnvLW97inHNuaWnJCSHcH/zBH9zr/n/rt37LCSHcnXfeOfnsec97ngPcr/zKr5zx3Jxz7od+6IdcHMcn7ePmm292SqlT5u10Y7jmmmvcvn37TvoMcK997WtP2Xb37t3uec973uTflb28+uqrnbV28vkv/uIvOqWUW11dvU/nUKPGvwXORnu0e/duB5zy5wlPeIJbXFw8adsnP/nJ7tJLL3Xj8XjymbXWPf7xj3fnn3/+5LPqOXziE5/oiqI46fzb7bZ7zGMec0pJgc3P6/2xTVU626c//WnX6XTc05/+9JPG961wb+l
"text/plain": [
"<Figure size 1200x600 with 8 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"plt.figure(figsize=(12, 6))\n",
"for images, labels in train_ds.take(1):\n",
" for i in range(4):\n",
" ax = plt.subplot(2, 4, i + 1)\n",
" plt.imshow(images[i].numpy().astype(\"uint8\"))\n",
" orig_class_idx = np.argmax(labels[i].numpy())\n",
"\n",
" plt.title(f\"Ori: {class_names[orig_class_idx]}\")\n",
" plt.axis(\"off\")\n",
"\n",
" augmented_images = data_augmentation(images, training=True)\n",
" for i in range(4):\n",
" ax = plt.subplot(2, 4, i + 5)\n",
" plt.imshow(augmented_images[i].numpy().astype(\"uint8\"))\n",
" orig_class_idx = np.argmax(labels[i].numpy())\n",
"\n",
" plt.title(f\"Aug: {class_names[orig_class_idx]}\")\n",
" plt.axis(\"off\")\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "vQefwIFlqhU0"
},
"source": [
"8. Arsitektur Model CNN (EfficientNetv2B0)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 737
},
"id": "iswHWuZb3pZj",
"outputId": "a83c5bc3-e512-4e01-c359-0766daaa608c"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"No checkpoint found.\n",
"Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/efficientnet_v2/efficientnetv2-b0_notop.h5\n",
"\u001b[1m24274472/24274472\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 0us/step\n"
]
},
{
"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: \"functional_1\"</span>\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1mModel: \"functional_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",
"│ input_layer_2 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">InputLayer</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">224</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">224</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ data_augmentation (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Sequential</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">224</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">224</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ efficientnetv2-b0 (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">Functional</span>) │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1280</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">5,919,312</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d (<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\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">512</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">5,898,752</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">7</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">512</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">2,048</span> │\n",
"│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">BatchNormalization</span>) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d (<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\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">512</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout (<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\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">512</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_1 (<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\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">1,179,904</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_1 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">3</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">1,024</span> │\n",
"│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">BatchNormalization</span>) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ global_average_pooling2d │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GlobalAveragePooling2D</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\">256</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense (<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\">1024</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">263,168</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_2 │ (<span style=\"color: #00d7ff; text-decoration-color: #00d7ff\">None</span>, <span style=\"color: #00af00; text-decoration-color: #00af00\">1024</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">4,096</span> │\n",
"│ (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">BatchNormalization</span>) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_2 (<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\">1024</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">0</span> │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_1 (<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\">4</span>) │ <span style=\"color: #00af00; text-decoration-color: #00af00\">4,100</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",
"│ input_layer_2 (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ data_augmentation (\u001b[38;5;33mSequential\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ efficientnetv2-b0 (\u001b[38;5;33mFunctional\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m5,919,312\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m5,898,752\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m2,048\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ max_pooling2d (\u001b[38;5;33mMaxPooling2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m512\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ conv2d_1 (\u001b[38;5;33mConv2D\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m1,179,904\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_1 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m3\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m1,024\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ global_average_pooling2d │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m256\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"│ (\u001b[38;5;33mGlobalAveragePooling2D\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_1 (\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 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1024\u001b[0m) │ \u001b[38;5;34m263,168\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ batch_normalization_2 │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1024\u001b[0m) │ \u001b[38;5;34m4,096\u001b[0m │\n",
"│ (\u001b[38;5;33mBatchNormalization\u001b[0m) │ │ │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dropout_2 (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1024\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │\n",
"├─────────────────────────────────┼────────────────────────┼───────────────┤\n",
"│ dense_1 (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m4\u001b[0m) │ \u001b[38;5;34m4,100\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\">13,272,404</span> (50.63 MB)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Total params: \u001b[0m\u001b[38;5;34m13,272,404\u001b[0m (50.63 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\">7,349,508</span> (28.04 MB)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m7,349,508\u001b[0m (28.04 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\">5,922,896</span> (22.59 MB)\n",
"</pre>\n"
],
"text/plain": [
"\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m5,922,896\u001b[0m (22.59 MB)\n"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def build_model(num_classes):\n",
" base_model = EfficientNetV2B0(\n",
" input_shape=IMG_SIZE + (3,),\n",
" include_top=False,\n",
" weights='imagenet',\n",
" )\n",
" base_model.trainable = False\n",
"\n",
" inputs = tf.keras.Input(shape=IMG_SIZE + (3,))\n",
"\n",
" x = data_augmentation(inputs)\n",
" x = base_model(x, training=False)\n",
"\n",
" x = layers.Conv2D(512, (3, 3), padding='same', activation='swish')(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.MaxPooling2D((2, 2))(x)\n",
" x = layers.Dropout(0.2)(x)\n",
"\n",
" x = layers.Conv2D(256, (3, 3), padding='same', activation='swish')(x)\n",
" x = layers.BatchNormalization()(x)\n",
"\n",
" x = layers.GlobalAveragePooling2D()(x)\n",
" x = layers.Dropout(0.3)(x)\n",
"\n",
" x = layers.Dense(1024, activation='swish')(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.Dropout(0.4)(x)\n",
"\n",
" outputs = layers.Dense(num_classes, activation='sigmoid', dtype='float32')(x)\n",
"\n",
" model = models.Model(inputs, outputs)\n",
" return model, base_model\n",
"\n",
"checkpoint_path = '/content/best_model/best_model.keras'\n",
"\n",
"if os.path.exists(checkpoint_path):\n",
" print(f\"Loading weights from model checkpoint: {checkpoint_path}...\")\n",
" try:\n",
" model = models.load_model(checkpoint_path)\n",
" except Exception as e:\n",
" print(f\"Failed to load checkpoint model: {e}.\")\n",
" model, base_model = build_model(NUM_CLASSES)\n",
"else:\n",
" print(\"No checkpoint found.\")\n",
" model, base_model = build_model(NUM_CLASSES)\n",
"\n",
"model.summary()\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "yik1l5ngqt_1"
},
"source": [
"9. Implementasi Callbacks"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"id": "s4Trlvno3wny"
},
"outputs": [],
"source": [
"checkpoint_cb = callbacks.ModelCheckpoint(\n",
" \"best_model/best_model.keras\",\n",
" save_best_only=True,\n",
" monitor=\"val_loss\",\n",
" mode=\"min\"\n",
")\n",
"\n",
"early_stopping_cb = callbacks.EarlyStopping(\n",
" monitor=\"val_loss\",\n",
" patience=7,\n",
" restore_best_weights=True,\n",
" mode=\"min\"\n",
")\n",
"\n",
"reduce_lr_cb = callbacks.ReduceLROnPlateau(\n",
" monitor='val_loss',\n",
" factor=0.2,\n",
" patience=3,\n",
" min_lr=1e-6,\n",
" verbose=1,\n",
" mode=\"min\"\n",
")\n",
"\n",
"callbacks_list = [checkpoint_cb, early_stopping_cb, reduce_lr_cb]\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "UKyFNmVvqyHx"
},
"source": [
"10. Training Model"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "cq5rllO63zXA",
"outputId": "0d3c03c8-d354-4b8b-befb-ecbb68b18735"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Training...\n",
"Epoch 1/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m207s\u001b[0m 1s/step - accuracy: 0.9153 - loss: 0.2220 - val_accuracy: 0.9459 - val_loss: 0.1425 - learning_rate: 0.0010\n",
"Epoch 2/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m186s\u001b[0m 1s/step - accuracy: 0.9512 - loss: 0.1323 - val_accuracy: 0.9781 - val_loss: 0.0640 - learning_rate: 0.0010\n",
"Epoch 3/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m191s\u001b[0m 1s/step - accuracy: 0.9649 - loss: 0.0948 - val_accuracy: 0.9730 - val_loss: 0.0645 - learning_rate: 0.0010\n",
"Epoch 4/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m180s\u001b[0m 1s/step - accuracy: 0.9707 - loss: 0.0796 - val_accuracy: 0.9748 - val_loss: 0.0763 - learning_rate: 0.0010\n",
"Epoch 5/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 958ms/step - accuracy: 0.9725 - loss: 0.0770\n",
"Epoch 5: ReduceLROnPlateau reducing learning rate to 0.00020000000949949026.\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m191s\u001b[0m 1s/step - accuracy: 0.9733 - loss: 0.0757 - val_accuracy: 0.9661 - val_loss: 0.0838 - learning_rate: 0.0010\n",
"Epoch 6/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m185s\u001b[0m 1s/step - accuracy: 0.9778 - loss: 0.0564 - val_accuracy: 0.9824 - val_loss: 0.0445 - learning_rate: 2.0000e-04\n",
"Epoch 7/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m179s\u001b[0m 1s/step - accuracy: 0.9786 - loss: 0.0557 - val_accuracy: 0.9857 - val_loss: 0.0419 - learning_rate: 2.0000e-04\n",
"Epoch 8/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m167s\u001b[0m 1s/step - accuracy: 0.9804 - loss: 0.0534 - val_accuracy: 0.9880 - val_loss: 0.0354 - learning_rate: 2.0000e-04\n",
"Epoch 9/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m171s\u001b[0m 1s/step - accuracy: 0.9807 - loss: 0.0495 - val_accuracy: 0.9882 - val_loss: 0.0317 - learning_rate: 2.0000e-04\n",
"Epoch 10/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m179s\u001b[0m 1s/step - accuracy: 0.9842 - loss: 0.0427 - val_accuracy: 0.9894 - val_loss: 0.0319 - learning_rate: 2.0000e-04\n",
"Epoch 11/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m173s\u001b[0m 1s/step - accuracy: 0.9833 - loss: 0.0452 - val_accuracy: 0.9892 - val_loss: 0.0293 - learning_rate: 2.0000e-04\n",
"Epoch 12/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m214s\u001b[0m 1s/step - accuracy: 0.9839 - loss: 0.0413 - val_accuracy: 0.9889 - val_loss: 0.0320 - learning_rate: 2.0000e-04\n",
"Epoch 13/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m181s\u001b[0m 1s/step - accuracy: 0.9864 - loss: 0.0393 - val_accuracy: 0.9880 - val_loss: 0.0329 - learning_rate: 2.0000e-04\n",
"Epoch 14/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 1s/step - accuracy: 0.9878 - loss: 0.0355\n",
"Epoch 14: ReduceLROnPlateau reducing learning rate to 4.0000001899898055e-05.\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m246s\u001b[0m 1s/step - accuracy: 0.9877 - loss: 0.0358 - val_accuracy: 0.9885 - val_loss: 0.0340 - learning_rate: 2.0000e-04\n",
"Epoch 15/15\n",
"\u001b[1m156/156\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m176s\u001b[0m 1s/step - accuracy: 0.9866 - loss: 0.0358 - val_accuracy: 0.9897 - val_loss: 0.0326 - learning_rate: 4.0000e-05\n"
]
}
],
"source": [
"model.compile(\n",
" optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),\n",
" loss=tf.keras.losses.BinaryCrossentropy(),\n",
" metrics=[tf.keras.metrics.BinaryAccuracy(name='accuracy')]\n",
")\n",
"\n",
"print(\"Training...\")\n",
"EPOCHS_PHASE_1 = 15\n",
"\n",
"history_1 = model.fit(\n",
" train_ds,\n",
" validation_data=val_ds,\n",
" epochs=EPOCHS_PHASE_1,\n",
" callbacks=callbacks_list\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Fq0qppJ_rGDE"
},
"source": [
"11. Plot History"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 545
},
"id": "wOW7f13UD4wy",
"outputId": "eff4a3d7-9ddc-4992-da43-0ab09631e47d"
},
"outputs": [
{
"data": {
"image/png": "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6NChNGvWjNTUVN5880169+7N7t27iYiIoE2bNkyfPp2pU6dy77330rNnTwB69OhR7rENw+Avf/kLa9as4Z577iEuLo4VK1bw6KOPkpiYyL///W+78RX5vbiQ999/n+joaLp27Uq7du3w8vLigw8+4NFHH7Ubd88997BgwQIGDBjAuHHjKC4u5qeffuKXX36hS5cuADz77LNMmzaNHj16MH36dNzc3Ni4cSPff/89N954Y4U//7Pdf//9hISEMHXqVHJycgDYvHkzP//8M3fccQeNGzfmyJEjzJ07lz59+rB7927bbIvs7Gx69uzJnj17uPvuu7nqqqs4ceIEX3zxBQkJCcTFxTF48GA+/PBDZs2aZfdN/gcffIBhGIwcOfKS4hYREaltdH2r69sr5fr2QvLy8ujTpw8HDhxg4sSJNGvWjI8//pgxY8aQnp5u+6J55cqVjBgxgj//+c+8+OKLgLXu+Pr1621jpk2bxowZMxg3bhzdunUjMzOTLVu2sG3bNm644YbLilPE4QwRuaAHHnjAOPc/ld69exuAMW/evDLjc3Nzy2z729/+Znh5eRn5+fm2baNHjzaaNm1qe3748GEDMIKCgoxTp07Ztn/++ecGYHz55Ze2bc8880yZmADDzc3NOHDggG3bjh07DMCYM2eObdugQYMMLy8vIzEx0bZt//79houLS5l9lqe885sxY4ZhMpmMo0eP2p0fYEyfPt1ubKdOnYzOnTvbni9btswAjJdeesm2rbi42OjZs6cBGPPnz79oTF27djUaN25smM1m27bly5cbgPHmm2/a9llQUGD3vtOnTxuhoaHG3XffbbcdMJ555hnb8/nz5xuAcfjwYcMwDCMtLc1wc3MzbrrpJsNisdjGPfnkkwZgjB492rYtPz/fLi7DsP6s3d3d7T6bzZs3n/d8z/1dKf3M/u///s9u3O23326YTCa734GK/l6cT2FhoREUFGT885//tG278847jY4dO9qN+/777w3AePDBB8vso/Qz2r9/v+Hk5GQMHjy4zGdy9ud47udfqmnTpnafbenP5brrrjOKi4vtxpb3e7phwwYDMP73v//Ztk2dOtUAjKVLl5437hUrVhiA8e2339q93qFDB6N3795l3iciIlLb6fr24uen61ur+nZ9W/o7+fLLL593zOzZsw3AWLRokW1bYWGhcc011xg+Pj5GZmamYRiG8fe//93w8/Mrcx16to4dOxo33XTTBWMSqau05FnkErm7uzN27Ngy2z09PW2Ps7KyOHHiBD179iQ3N5e9e/dedL/Dhw+nQYMGtuel3+YdOnToou/t27cv0dHRtucdOnTAz8/P9l6z2cyqVau49dZbiYiIsI1r0aIFAwYMuOj+wf78cnJyOHHiBD169MAwDH799dcy4++77z675z179rQ7l2+++QYXFxfbN7pgrekyadKkCsUD1rpACQkJ/Pjjj7Ztixcvxs3NjaFDh9r26ebmBliX5p46dYri4mK6dOlS7nKSC1m1ahWFhYVMmjTJbhnNQw89VGasu7s7Tk7W/9WazWZOnjyJj48PrVu3rvRxS33zzTc4Ozvz4IMP2m3/xz/+gWEYfPvtt3bbL/Z7cSHffvstJ0+eZMSIEbZtI0aMYMeOHXZLYD799FNMJhPPPPNMmX2UfkbLli3DYrEwdep
"text/plain": [
"<Figure size 1600x600 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def plot_history(history_1, initial_epochs):\n",
" acc = history_1.history['accuracy']\n",
" val_acc = history_1.history['val_accuracy']\n",
" loss = history_1.history['loss']\n",
" val_loss = history_1.history['val_loss']\n",
"\n",
" plt.figure(figsize=(16, 6))\n",
"\n",
" plt.subplot(1, 2, 1)\n",
" plt.plot(acc, label='Training Accuracy')\n",
" plt.plot(val_acc, label='Validation Accuracy')\n",
" plt.legend(loc='lower right')\n",
" plt.title('Training and Validation Accuracy')\n",
"\n",
" plt.subplot(1, 2, 2)\n",
" plt.plot(loss, label='Training Loss')\n",
" plt.plot(val_loss, label='Validation Loss')\n",
" plt.legend(loc='upper right')\n",
" plt.title('Training and Validation Loss')\n",
" plt.show()\n",
"\n",
"plot_history(history_1, EPOCHS_PHASE_1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "TxXzQ8ZrrmiS"
},
"source": [
"12. Test Time Augmentation"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/"
},
"id": "5vnDCrqLD5hT",
"outputId": "b4e04c95-c570-4817-cf1f-37321560c89c"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Evaluating model using TTA (Test-Time Augmentation) for Multi-Label...\n",
"TTA Step 1/5\n",
"TTA Step 2/5\n",
"TTA Step 3/5\n",
"TTA Step 4/5\n",
"TTA Step 5/5\n",
"\n",
"Subset Accuracy (Exact Match) on Test Set (with TTA): 97.20%\n",
"Binary Accuracy (Per-Class Average) on Test Set (with TTA): 98.86%\n"
]
}
],
"source": [
"print(\"Evaluating model using TTA (Test-Time Augmentation) for Multi-Label...\")\n",
"\n",
"test_images = []\n",
"test_labels_true = []\n",
"\n",
"for images, labels in test_ds.unbatch():\n",
" test_images.append(images.numpy())\n",
" test_labels_true.append(labels.numpy())\n",
"\n",
"test_images = np.array(test_images)\n",
"test_labels_true = np.array(test_labels_true)\n",
"\n",
"TTA_STEPS = 5\n",
"tta_predictions = []\n",
"\n",
"for i in range(TTA_STEPS):\n",
" print(f\"TTA Step {i+1}/{TTA_STEPS}\")\n",
" aug_images = data_augmentation(test_images, training=True)\n",
" preds = model.predict(aug_images, batch_size=BATCH_SIZE, verbose=0)\n",
" tta_predictions.append(preds)\n",
"\n",
"mean_tta_preds = np.mean(tta_predictions, axis=0)\n",
"\n",
"THRESHOLD = 0.5\n",
"test_preds_binary = (mean_tta_preds > THRESHOLD).astype(int)\n",
"\n",
"correct_predictions = np.equal(test_preds_binary, test_labels_true.astype(int))\n",
"tta_accuracy = np.mean(correct_predictions)\n",
"\n",
"print(f\"\\nSubset Accuracy (Exact Match) on Test Set (with TTA): {np.mean(np.all(correct_predictions, axis=1)) * 100:.2f}%\")\n",
"print(f\"Binary Accuracy (Per-Class Average) on Test Set (with TTA): {tta_accuracy * 100:.2f}%\")\n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "y-ADQvPIr1Wo"
},
"source": [
"13. Metrik Evaluasi"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"colab": {
"base_uri": "https://localhost:8080/",
"height": 1000
},
"id": "4ea9-S50EtQ6",
"outputId": "f1632cab-a233-4072-d0ec-70f141f83757"
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Classification Report (Multi-Label):\n",
"\n",
" precision recall f1-score support\n",
"\n",
" Bercak Daun 0.96 0.94 0.95 224\n",
" Daun Sehat 0.99 1.00 1.00 345\n",
" Karat Daun 0.97 0.98 0.98 259\n",
" hawar daun 0.98 0.97 0.98 242\n",
"\n",
" micro avg 0.98 0.98 0.98 1070\n",
" macro avg 0.98 0.97 0.97 1070\n",
"weighted avg 0.98 0.98 0.98 1070\n",
" samples avg 0.97 0.98 0.98 1070\n",
"\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"/usr/local/lib/python3.12/dist-packages/sklearn/metrics/_classification.py:1565: UndefinedMetricWarning: Precision is ill-defined and being set to 0.0 in samples with no predicted labels. Use `zero_division` parameter to control this behavior.\n",
" _warn_prf(average, modifier, f\"{metric.capitalize()} is\", len(result))\n"
]
},
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAABKUAAAPeCAYAAADd/6nHAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjAsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvlHJYcgAAAAlwSFlzAAAPYQAAD2EBqD+naQAAqppJREFUeJzs3Xd0VOX69vFrEsikkQIk0kM10hTFQi+CRgFFEBERCUiXohQF9UiJCIqKFKXooRMUkSLNQxGQIgdRikjv/JQoHQwBAsnz/sGbOQyTwASSPRP8ftZiLeaZZ/a+92SY3Fyz59k2Y4wRAAAAAAAAYCEfTxcAAAAAAACAfx5CKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKQAAAAAAAFiOUAoAAAAAAACWI5QCAAAAAACA5QilAAAAAAAAYDlCKcAL7N27V48//rhCQ0Nls9k0b968LN3+oUOHZLPZNHny5Czdbk5Wp04d1alTx9NleDWbzaZu3bp5ugwAANxGT2U9eirPmTx5smw2m37++WdPlwLcMkIp4P/bv3+/OnXqpJIlS8rf318hISGqXr26Ro4cqQsXLmTrvmNjY7Vt2za99957mjZtmh588MFs3Z+V2rRpI5vNppCQkHSfx71798pms8lms+mjjz7K9PaPHj2qgQMHasuWLVlQbdZatWqV49jS/uTNm1dVqlRRfHy8p8vLVsWLF3ccs4+Pj8LCwlSxYkV17NhRGzZs8HR5AIBsRE+VPeip/tdP2e123XXXXapTp46GDBmi48ePe7pEtyQmJmrAgAGqUKGCgoKClC9fPlWqVEmvvvqqjh496unyJEkzZszQiBEjPF0G/kFyeboAwBssWrRIzz33nOx2u1q3bq0KFSooOTlZa9eu1euvv67t27fr888/z5Z9X7hwQevXr9fbb7+dbWelREVF6cKFC8qdO3e2bP9mcuXKpaSkJC1YsEDNmzd3ui8+Pl7+/v66ePHiLW376NGjGjRokIoXL65KlSq5/bilS5fe0v5uRY8ePfTQQw9Jkk6ePKmZM2eqVatWOnPmjLp27WpZHVarVKmSevfuLUn6+++/tXPnTs2aNUtffPGFevbsqeHDh3u4QgBAVqOnyl70VFd7qpSUFB0/flw//vijBgwYoOHDh+vrr7/Wo48+alktmXX58mXVqlVLu3btUmxsrLp3767ExERt375dM2bMUJMmTVSoUCFPl6kZM2bot99+02uvvebpUvAPQSiFf7yDBw+qRYsWioqK0ooVK1SwYEHHfV27dtW+ffu0aNGibNt/2ic7YWFh2bYPm80mf3//bNv+zdjtdlWvXl1ffvmlSwM1Y8YMNWzYULNnz7aklqSkJAUGBsrPz8+S/UlSzZo11axZM8ftLl26qGTJkpoxY0aWhVJpx+VNChcurFatWjmNffDBB2rZsqU++eQTlSlTRl26dPFQdQCArEZPlf3oqZx7KknaunWrHn/8cT377LPasWOH0+vOm8ybN0+bN29WfHy8WrZs6XTfxYsXlZyc7KHKAM/i63v4xxs2bJgSExM1YcKEdH+JlS5dWq+++qrj9pUrV/Tuu++qVKlSstvtKl68uN566y1dunTJ6XHFixdXo0aNtHbtWj388MPy9/dXyZIlNXXqVMecgQMHKioqSpL0+uuvy2azqXjx4pKunqKd9vdrDRw4UDabzWls2bJlqlGjhsLCwhQcHKzo6Gi99dZbjvszWv9gxYoVqlmzpoKCghQWFqbGjRtr586d6e5v3759atOmjcLCwhQaGqq2bdsqKSkp4yf2Oi1bttR3332nM2fOOMY2btyovXv3uvxilqRTp06pT58+qlixooKDgxUSEqInn3xSW7dudcxZtWqV4wyktm3bOk7pTjvOOnXqqEKFCvrll19Uq1YtBQYGOp6X69c/iI2Nlb+/v8vxx8TEKDw83OmU6v3792v//v1uH/v1/Pz8FB4erly5XD8XmD59uipXrqyAgADlzZtXLVq00P/93/85zbnRcV28eFEDBw7U3XffLX9/fxUsWFBNmzZ1qvejjz5StWrVlC9fPgUEBKhy5cr65ptv3Kp98ODB8vHx0ejRo2/p2AMCAjRt2jTlzZtX7733nowxmarrRmt52Gw2DRw40HE7q167AAD30FPRU0nW9lSSdN9992nEiBE6c+aMPv30U8f44cOH9corryg6OloBAQHKly+fnnvuOR06dMjp8em9DqT/rdd07Xx3XosZSTvO6tWru9yX9jXXa+3atUvNmjVT3rx55e/vrwcffFDz589Pd9uXLl1Sr169FBERoaCgIDVp0sTlK43ffvutGjZsqEKFCslut6tUqVJ69913lZKS4phTp04dLVq0SIcPH3a8BtL7twNkJUIp/OMtWLBAJUuWVLVq1dya3759e/Xv318PPPCAPvnkE9WuXVtDhw5VixYtXObu27dPzZo102OPPaaPP/5Y4eHhatOmjbZv3y5Jatq0qT755BNJ0gsvvKBp06Zl+jvc27dvV6NGjXTp0iXFxcXp448/1tNPP61169bd8HHLly9XTEyMjh07poEDB6pXr1768ccfVb16dZdf1pLUvHlz/f333xo6dKiaN2+uyZMna9CgQW7X2bRpU9lsNs2ZM8cxNmPGDN1zzz164IEHXOYfOHBA8+bNU6NGjTR8+HC9/vrr2rZtm2rXru1oZsqWLau4uDhJUseOHTVt2jRNmzZNtWrVcmzn5MmTevLJJ1WpUiWNGDFCdevWTbe+kSNHKiIiQrGxsY5fzuPHj9fSpUs1evRop9Op69Wrp3r16rl97H///bdOnDihEydOaM+ePRo4cKB+++03xcbGOs1777331Lp1a5UpU0bDhw/Xa6+9pu+//161atVyajwzOq6UlBQ1atRIgwYNUuXKlfXxxx/r1Vdf1dmzZ/Xbb785Hev999+vuLg4DRkyRLly5dJzzz1300+v//Wvf6l///4aP368unfv7vbxXy84OFhNmjTRH3/8oR07dtx2XTdzu69dAIB76KnoqaTs7aky0qxZMwUEBDh9lXDjxo368ccf1aJFC40aNUqdO3fW999/rzp16tzWh1M3ey1mJC00nTp1qtOHcunZvn27qlSpop07d6pfv376+OOPFRQUpGeeeUZz5851md+9e3dt3bpVAwYMUJcuXbRgwQKXr7BOnjxZwcHB6tWrl0aOHKnKlSurf//+6tevn2PO22+/rUqVKil//vyO1wDrSyHbGeAf7OzZs0aSady4sVvzt2zZYiSZ9u3bO4336dPHSDIrVqxwjEVFRRlJZvXq1Y6xY8eOGbvdbnr37u0YO3jwoJFkPvzwQ6dtxsbGmqioKJcaBgwYYK79p/vJJ58YSeb48eMZ1p22j0mTJjnGKlWqZCIjI83JkycdY1u3bjU+Pj6mdevWLvt7+eWXnbbZpEkTky9fvgz3ee1xBAUFGWOMadasmalXr54xxpiUlBRToEABM2jQoHSfg4sXL5qUlBSX47Db7SYuLs4xtnHjRpdjS1O7dm0jyYwbNy7d+2rXru00tmTJEiPJDB482Bw4cMAEBwebZ555xuWxUVFR6f5srrdy5UojyeWPj4+Pee+995zmHjp0yPj6+rqMb9u2zeTKlctpPKPjmjhxopFkhg8f7lJLamqq4+9JSUlO9yUnJ5sKFSqYRx991GlckunatasxxpjevXsbHx8fM3ny5JsetzFXn6OGDRtmeH/a6/bbb7/NVF3pvZavrXfAgAGO27f72gUAuI+eip7qWtnVU82aNSvDOffdd58JDw933L6+rzDGmPXr1xtJZurUqY6x618HaSZNmmQkmYMHDzrV685rMT1JSUkmOjraSDJRUVGmTZs2ZsKECeavv/5ymVuvXj1TsWJFc/HiRcdYamqqqVatmilTpoxLjfXr13fq9Xr27Gl8fX3NmTNnbvh8dOrUyQQGBjrtp2HDhm79TICswplS+Ec7d+6cJClPnjxuzV+8eLEkqVevXk7jaYs5X39GR7ly5VSzZk3H7YiICEVHR+vAgQO3XPP10tZN+Pbbb5WamurWYxI
"text/plain": [
"<Figure size 1200x1000 with 4 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"from sklearn.metrics import multilabel_confusion_matrix\n",
"\n",
"print(\"\\nClassification Report (Multi-Label):\\n\")\n",
"print(classification_report(test_labels_true, test_preds_binary, target_names=class_names))\n",
"\n",
"mcm = multilabel_confusion_matrix(test_labels_true, test_preds_binary)\n",
"\n",
"fig, axes = plt.subplots(2, 2, figsize=(12, 10))\n",
"axes = axes.ravel()\n",
"\n",
"for i, class_name in enumerate(class_names):\n",
" sns.heatmap(mcm[i], annot=True, fmt='d', cmap='Blues', ax=axes[i], cbar=False,\n",
" xticklabels=['Negative', 'Positive'], yticklabels=['Negative', 'Positive'])\n",
" axes[i].set_title(f'Confusion Matrix: {class_name}')\n",
" axes[i].set_xlabel('Predicted')\n",
" axes[i].set_ylabel('True')\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# ──────────────────────────────────────────────\n",
"# 14. Upload Model ke Hugging Face Hub\n",
"# ──────────────────────────────────────────────\n",
"print(\"Mengunggah model ke Hugging Face Hub...\")\n",
"try:\n",
" from huggingface_hub import HfApi, login\n",
" import os\n",
"\n",
" hf_token = os.environ.get(\"HF_TOKEN\")\n",
" if hf_token:\n",
" login(token=hf_token, add_to_git_credential=False)\n",
"\n",
" api = HfApi()\n",
" model_path = \"/content/best_model/best_model.keras\"\n",
" repo_id = \"MythEclipse2737/zeavis-edu-model\"\n",
"\n",
" if os.path.exists(model_path):\n",
" api.upload_file(\n",
" path_or_fileobj=model_path,\n",
" path_in_repo=\"best_model/best_model.keras\",\n",
" repo_id=repo_id,\n",
" repo_type=\"model\",\n",
" )\n",
" print(f\"✅ Model berhasil diunggah ke https://huggingface.co/{repo_id}\")\n",
" else:\n",
" print(f\"⚠️ {model_path} tidak ditemukan, upload dilewati.\")\n",
"except ImportError:\n",
" print(\"⚠️ huggingface_hub tidak terinstal. Jalankan: pip install huggingface_hub\")\n",
"except Exception as e:\n",
" print(f\"⚠️ Upload gagal: {e}\")"
]
}
],
"metadata": {
"accelerator": "GPU",
"colab": {
"gpuType": "T4",
"provenance": []
},
"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": 0
2026-05-22 14:23:45 +08:00
}