Files
zeavis-edu/Machine_Learning/notebook.ipynb
T

3743 lines
1.9 MiB
Plaintext
Raw Normal View History

2026-05-22 14:23:45 +08:00
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# ZeaVis Edu — Corn Leaf Disease Classifier\n",
"\n",
"Mengklasifikasikan penyakit daun jagung (Bercak Daun, Hawar Daun, Karat Daun, Daun Sehat) menggunakan EfficientNetV2B0 dengan transfer learning.\n",
"---"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 1. Persiapan Lingkungan\n",
"\n",
"Mengimpor pustaka, mengatur seed, dan mengoptimalkan konfigurasi.\n",
"**Presisi float32** digunakan untuk komputasi.\n",
"Resolusi gambar: **224x224** (EfficientNetV2B0)."
]
2026-05-22 14:23:45 +08:00
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 12,
2026-06-11 16:39:04 +00:00
"id": "94627f52",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: tensorflow==2.19.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 1)) (2.19.0)\n",
"Requirement already satisfied: tensorflowjs==4.22.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 2)) (4.22.0)\n",
"Requirement already satisfied: gdown in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 3)) (6.1.0)\n",
"Requirement already satisfied: numpy in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 4)) (2.1.3)\n",
"Requirement already satisfied: matplotlib in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 5)) (3.10.9)\n",
"Requirement already satisfied: seaborn in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 6)) (0.13.2)\n",
"Requirement already satisfied: pillow in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 7)) (12.2.0)\n",
"Requirement already satisfied: split-folders in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 8)) (0.6.1)\n",
"Requirement already satisfied: scikit-learn in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 9)) (1.9.0)\n",
"Requirement already satisfied: tf2onnx in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 10)) (1.17.0)\n",
"Requirement already satisfied: onnxruntime in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 11)) (1.26.0)\n",
"Requirement already satisfied: absl-py>=1.0.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (2.4.0)\n",
"Requirement already satisfied: astunparse>=1.6.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (1.6.3)\n",
"Requirement already satisfied: flatbuffers>=24.3.25 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (25.12.19)\n",
"Requirement already satisfied: gast!=0.5.0,!=0.5.1,!=0.5.2,>=0.2.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (0.7.0)\n",
"Requirement already satisfied: google-pasta>=0.1.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (0.2.0)\n",
"Requirement already satisfied: libclang>=13.0.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (18.1.1)\n",
"Requirement already satisfied: opt-einsum>=2.3.2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (3.4.0)\n",
"Requirement already satisfied: packaging in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (23.2)\n",
"Requirement already satisfied: protobuf!=4.21.0,!=4.21.1,!=4.21.2,!=4.21.3,!=4.21.4,!=4.21.5,<6.0.0dev,>=3.20.3 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (5.29.6)\n",
"Requirement already satisfied: requests<3,>=2.21.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (2.34.2)\n",
"Requirement already satisfied: setuptools in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (82.0.1)\n",
"Requirement already satisfied: six>=1.12.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (1.17.0)\n",
"Requirement already satisfied: termcolor>=1.1.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (3.3.0)\n",
"Requirement already satisfied: typing-extensions>=3.6.6 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (4.15.0)\n",
"Requirement already satisfied: wrapt>=1.11.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (2.2.1)\n",
"Requirement already satisfied: grpcio<2.0,>=1.24.3 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (1.81.1)\n",
"Requirement already satisfied: tensorboard~=2.19.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (2.19.0)\n",
"Requirement already satisfied: keras>=3.5.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (3.14.1)\n",
"Requirement already satisfied: h5py>=3.11.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (3.14.0)\n",
"Requirement already satisfied: ml-dtypes<1.0.0,>=0.5.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow==2.19.0->-r requirements.txt (line 1)) (0.5.4)\n",
"Requirement already satisfied: flax>=0.7.2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.12.7)\n",
"Requirement already satisfied: importlib_resources>=5.9.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (7.1.0)\n",
"Requirement already satisfied: jax>=0.4.13 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.10.1)\n",
"Requirement already satisfied: jaxlib>=0.4.13 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.10.1)\n",
"Requirement already satisfied: tf-keras>=2.13.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (2.19.0)\n",
"Requirement already satisfied: tensorflow-decision-forests>=1.5.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (1.12.0)\n",
"Requirement already satisfied: tensorflow-hub>=0.16.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.16.1)\n",
"Requirement already satisfied: charset_normalizer<4,>=2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from requests<3,>=2.21.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (3.4.7)\n",
"Requirement already satisfied: idna<4,>=2.5 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from requests<3,>=2.21.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (3.18)\n",
"Requirement already satisfied: urllib3<3,>=1.26 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from requests<3,>=2.21.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (2.7.0)\n",
"Requirement already satisfied: certifi>=2023.5.7 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from requests<3,>=2.21.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (2026.5.20)\n",
"Requirement already satisfied: markdown>=2.6.8 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorboard~=2.19.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (3.10.2)\n",
"Requirement already satisfied: tensorboard-data-server<0.8.0,>=0.7.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorboard~=2.19.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (0.7.2)\n",
"Requirement already satisfied: werkzeug>=1.0.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorboard~=2.19.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (3.1.8)\n",
"Requirement already satisfied: beautifulsoup4 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from gdown->-r requirements.txt (line 3)) (4.15.0)\n",
"Requirement already satisfied: filelock in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from gdown->-r requirements.txt (line 3)) (3.29.3)\n",
"Requirement already satisfied: tqdm in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from gdown->-r requirements.txt (line 3)) (4.68.2)\n",
"Requirement already satisfied: contourpy>=1.0.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (1.3.3)\n",
"Requirement already satisfied: cycler>=0.10 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (0.12.1)\n",
"Requirement already satisfied: fonttools>=4.22.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (4.63.0)\n",
"Requirement already satisfied: kiwisolver>=1.3.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (1.5.0)\n",
"Requirement already satisfied: pyparsing>=3 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (3.3.2)\n",
"Requirement already satisfied: python-dateutil>=2.7 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 5)) (2.9.0.post0)\n",
"Requirement already satisfied: pandas>=1.2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from seaborn->-r requirements.txt (line 6)) (3.0.3)\n",
"Requirement already satisfied: scipy>=1.10.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from scikit-learn->-r requirements.txt (line 9)) (1.17.1)\n",
"Requirement already satisfied: joblib>=1.4.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from scikit-learn->-r requirements.txt (line 9)) (1.5.3)\n",
"Requirement already satisfied: narwhals>=2.0.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from scikit-learn->-r requirements.txt (line 9)) (2.22.1)\n",
"Requirement already satisfied: threadpoolctl>=3.5.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from scikit-learn->-r requirements.txt (line 9)) (3.6.0)\n",
"Requirement already satisfied: onnx>=1.14.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tf2onnx->-r requirements.txt (line 10)) (1.21.0)\n",
"Requirement already satisfied: wheel<1.0,>=0.23.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from astunparse>=1.6.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (0.45.1)\n",
"Requirement already satisfied: msgpack in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (1.2.0)\n",
"Requirement already satisfied: optax in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.2.8)\n",
"Requirement already satisfied: orbax-checkpoint in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.12.0)\n",
"Requirement already satisfied: tensorstore in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.1.84)\n",
"Requirement already satisfied: rich>=11.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (15.0.0)\n",
"Requirement already satisfied: PyYAML>=5.4.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (6.0.3)\n",
"Requirement already satisfied: treescope>=0.1.7 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.1.10)\n",
"Requirement already satisfied: namex in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from keras>=3.5.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (0.1.0)\n",
"Requirement already satisfied: optree in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from keras>=3.5.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (0.19.1)\n",
"Requirement already satisfied: markdown-it-py>=2.2.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from rich>=11.1->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (4.2.0)\n",
"Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from rich>=11.1->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (2.20.0)\n",
"Requirement already satisfied: mdurl~=0.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from markdown-it-py>=2.2.0->rich>=11.1->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.1.2)\n",
"Requirement already satisfied: wurlitzer in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow-decision-forests>=1.5.0->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (3.1.1)\n",
"Requirement already satisfied: ydf>=0.11.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tensorflow-decision-forests>=1.5.0->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.16.0)\n",
"Requirement already satisfied: markupsafe>=2.1.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from werkzeug>=1.0.1->tensorboard~=2.19.0->tensorflow==2.19.0->-r requirements.txt (line 1)) (3.0.3)\n",
"Requirement already satisfied: soupsieve>=1.6.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from beautifulsoup4->gdown->-r requirements.txt (line 3)) (2.8.4)\n",
"Requirement already satisfied: etils[epath,epy] in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (1.14.0)\n",
"Requirement already satisfied: prometheus-client>=0.20.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.25.0)\n",
"Requirement already satisfied: aiofiles in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (25.1.0)\n",
"Requirement already satisfied: humanize in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (4.15.0)\n",
"Requirement already satisfied: simplejson>=3.16.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (4.1.1)\n",
"Requirement already satisfied: psutil in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (7.2.2)\n",
"Requirement already satisfied: uvloop in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (0.22.1)\n",
"Requirement already satisfied: fsspec in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from etils[epath,epy]->orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (2026.4.0)\n",
"Requirement already satisfied: zipp in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from etils[epath,epy]->orbax-checkpoint->flax>=0.7.2->tensorflowjs==4.22.0->-r requirements.txt (line 2)) (4.1.0)\n",
"Requirement already satisfied: PySocks!=1.5.7,>=1.5.6 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from requests[socks]->gdown->-r requirements.txt (line 3)) (1.7.1)\n"
]
}
],
"source": [
"!pip install -r requirements.txt"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 13,
2026-06-11 16:39:04 +00:00
"id": "bad56dcc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Running locally (TF 2.19.0, GPU: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')])\n",
"Setup OK. IMG=(224, 224), BATCH=32\n"
]
}
],
"source": [
"import os\n",
"import shutil\n",
"import zipfile\n",
"import random\n",
"from collections import Counter\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import seaborn as sns\n",
"import splitfolders\n",
"from PIL import Image\n",
"\n",
"import tensorflow as tf\n",
"from tensorflow.keras import layers, models, callbacks\n",
"from tensorflow.keras.applications import EfficientNetV2B0\n",
"from tensorflow.keras.applications.efficientnet_v2 import preprocess_input\n",
"from tensorflow.keras.optimizers import AdamW\n",
"from sklearn.metrics import classification_report, confusion_matrix\n",
"from sklearn.utils.class_weight import compute_class_weight\n",
"\n",
"# Detect environment\n",
"try:\n",
" from google.colab import drive\n",
" IS_COLAB = True\n",
" print(\"Running on Google Colab\")\n",
"except ModuleNotFoundError:\n",
" IS_COLAB = False\n",
" print(f\"Running locally (TF {tf.__version__}, GPU: {tf.config.list_physical_devices('GPU')})\")\n",
"\n",
"tf.keras.mixed_precision.set_global_policy('float32')\n",
"\n",
"# Hyperparams\n",
"IMG_SIZE = (224, 224)\n",
"BATCH_SIZE = 32\n",
"SEED = 42\n",
"random.seed(SEED)\n",
"np.random.seed(SEED)\n",
"tf.random.set_seed(SEED)\n",
"\n",
"AUTOTUNE = tf.data.AUTOTUNE\n",
"print(f\"Setup OK. IMG={IMG_SIZE}, BATCH={BATCH_SIZE}\")"
]
},
{
"cell_type": "markdown",
2026-06-11 16:39:04 +00:00
"id": "83235964",
"metadata": {},
"source": [
"## 2. Download dan Ekstraksi Dataset"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 14,
2026-06-11 16:39:04 +00:00
"id": "c18354b4",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset ready.\n"
]
}
],
"source": [
"if IS_COLAB:\n",
" drive.mount('/content/drive')\n",
" archive_path = '/content/drive/MyDrive/jagung/dataset_jagung.zip'\n",
" destination_path = '/content/dataset_jagung.zip'\n",
" extract_path = '/content/dataset'\n",
"else:\n",
" import gdown\n",
" base = os.getcwd()\n",
" archive_path = os.path.join(base, 'dataset_jagung.zip')\n",
" destination_path = archive_path\n",
" extract_path = os.path.join(base, 'dataset')\n",
" DRIVE_FILE_ID = \"1s0H2lDOQVCixywk5eZXJz2i9jj4JihxJ\"\n",
" if not os.path.exists(archive_path):\n",
" print(\"Downloading from Google Drive...\")\n",
" try:\n",
" gdown.download(f\"https://drive.google.com/uc?id={DRIVE_FILE_ID}\", archive_path, quiet=False)\n",
" except Exception as e:\n",
" print(f\"Download failed: {e}\")\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 ready.\")"
]
},
{
"cell_type": "markdown",
2026-06-11 16:39:04 +00:00
"id": "5e19a255",
"metadata": {},
"source": [
"## 3. Data Cleaning dan Validasi Gambar (RGB)"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 15,
2026-06-11 16:39:04 +00:00
"id": "63ee82cc",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Dataset path: /home/asephs/ZeaVis-Edu/Machine_Learning/dataset\n",
"Cleaning data...\n",
"Done. 0 problematic files removed.\n"
]
}
],
"source": [
2026-06-11 16:39:04 +00:00
"# --- Determine dataset path ---\n",
"# Colab: zip extracts to dataset/ with dataset_jagung_v1/ subfolder\n",
"# Local: zip extracts classes directly to dataset/\n",
"if IS_COLAB:\n",
" dataset_path = \"/content/dataset/dataset_jagung_v1\"\n",
"else:\n",
2026-06-11 16:39:04 +00:00
" candidate = os.path.join(extract_path, \"dataset_jagung_v1\")\n",
" if os.path.isdir(candidate):\n",
" dataset_path = candidate\n",
" else:\n",
" dataset_path = extract_path # classes are directly in dataset/\n",
"\n",
"print(f\"Dataset path: {dataset_path}\")\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",
" img = Image.open(file_path)\n",
" if img.mode != 'RGB':\n",
" img = img.convert('RGB')\n",
" img.save(file_path)\n",
" except Exception:\n",
" print(f\"Removing: {file_path}\")\n",
" os.remove(file_path)\n",
" removed_count += 1\n",
" return removed_count\n",
"\n",
"print(\"Cleaning data...\")\n",
"removed = clean_image_data(dataset_path)\n",
"print(f\"Done. {removed} problematic files removed.\")"
]
},
{
"cell_type": "markdown",
2026-06-11 16:39:04 +00:00
"id": "c93f0a16",
"metadata": {},
"source": [
"## 4. Data Splitting (Train:Validation:Test = 70:15:15)"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 16,
"id": "35d34ff6",
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Splitting dataset 70:15:15...\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
2026-06-11 19:42:02 +00:00
"Copying files: 6988 files [00:08, 830.89 files/s] "
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"Done.\n",
"Train: 4890 | Val: 1046 | Test: 1052\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"\n"
]
}
],
"source": [
"if IS_COLAB:\n",
" output_dir = \"/content/dataset_split\"\n",
"else:\n",
" output_dir = os.path.join(os.getcwd(), \"dataset_split\")\n",
"\n",
"if os.path.exists(output_dir):\n",
" shutil.rmtree(output_dir)\n",
"\n",
"print(\"Splitting dataset 70:15:15...\")\n",
"splitfolders.ratio(dataset_path, output=output_dir,\n",
" seed=SEED, ratio=(0.7, 0.15, 0.15),\n",
" group_prefix=None, move=False)\n",
"print(\"Done.\")\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')\n",
"\n",
"# Count\n",
"def count_images(path):\n",
" return sum(len(files) for _, _, files in os.walk(path))\n",
"\n",
"print(f'Train: {count_images(train_dir)} | Val: {count_images(val_dir)} | Test: {count_images(test_dir)}')"
]
},
{
"cell_type": "markdown",
"id": "a0ab36ff",
"metadata": {},
"source": [
"## 5. Data Loader dengan Augmentasi Lanjutan\n",
"\n",
"Menggunakan pipeline augmentasi berlapis:\n",
"- **Geometric**: RandomFlip, Rotation, Zoom, Translation, Contrast, Brightness\n",
"- **CutMix & MixUp**: mencampur dua gambar dan label (probabilitas 50% masing-masing)\n",
"- **RandomErasing**: menghapus area acak pada gambar\n",
"- **GaussianNoise** di dalam model (layer terpisah)\n",
"- **Class weights**: menangani ketidakseimbangan kelas (capped max 2.5)"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 17,
"id": "36109306",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 4890 files belonging to 4 classes.\n",
"Found 1046 files belonging to 4 classes.\n",
"Found 1052 files belonging to 4 classes.\n",
"Classes (4): ['Bercak Daun', 'Daun Sehat', 'Hawar Daun', 'Karat Daun']\n",
"Class weights (capped at 2.5):\n",
" Bercak Daun: 1.1665\n",
" Daun Sehat: 0.8080\n",
" Hawar Daun: 1.0847\n",
" Karat Daun: 1.0171\n",
"Data pipelines ready.\n"
]
}
],
"source": [
"# --- Load datasets ---\n",
"train_ds = tf.keras.utils.image_dataset_from_directory(\n",
" train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"val_ds = tf.keras.utils.image_dataset_from_directory(\n",
" val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\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\"Classes ({NUM_CLASSES}): {class_names}\")\n",
"\n",
"# --- Helper: one-hot ---\n",
"def to_one_hot(image, label):\n",
" return image, tf.one_hot(label, NUM_CLASSES)\n",
"\n",
"# --- Beta distribution for MixUp/CutMix ---\n",
"def sample_beta_distribution(size, concentration_0=0.2, concentration_1=0.2):\n",
" gamma_1 = tf.random.gamma(shape=[size], alpha=concentration_1, dtype=tf.float32)\n",
" gamma_2 = tf.random.gamma(shape=[size], alpha=concentration_0, dtype=tf.float32)\n",
" return gamma_2 / (gamma_1 + gamma_2 + 1e-8)\n",
"\n",
"# --- MixUp ---\n",
"def mix_up(images, labels, alpha=0.2):\n",
" batch_size = tf.shape(images)[0]\n",
" lambda_param = sample_beta_distribution(batch_size, alpha, alpha)\n",
" lambda_param_img = tf.reshape(lambda_param, [batch_size, 1, 1, 1])\n",
" random_indices = tf.random.shuffle(tf.range(batch_size))\n",
" mixed_images = lambda_param_img * images + (1 - lambda_param_img) * tf.gather(images, random_indices)\n",
" labels = tf.cast(labels, tf.float32)\n",
" lambda_param_lbl = tf.reshape(lambda_param, [-1, 1])\n",
" mixed_labels = lambda_param_lbl * labels + (1 - lambda_param_lbl) * tf.gather(labels, random_indices)\n",
" return mixed_images, mixed_labels\n",
"\n",
"# --- CutMix (batch-level via coordinate-grid broadcasting) ---\n",
"def cut_mix(images, labels, alpha=0.2):\n",
" batch_size = tf.shape(images)[0]\n",
" h = tf.shape(images)[1]\n",
" w = tf.shape(images)[2]\n",
" \n",
" lambda_param = sample_beta_distribution(batch_size, alpha, alpha) # [B]\n",
" random_indices = tf.random.shuffle(tf.range(batch_size))\n",
" \n",
" # Per-sample cut sizes (in pixels)\n",
" cut_ratio = tf.sqrt(1.0 - lambda_param) # [B]\n",
" r_h = tf.cast(cut_ratio * tf.cast(h, tf.float32), tf.int32) # [B]\n",
" r_w = tf.cast(cut_ratio * tf.cast(w, tf.float32), tf.int32) # [B]\n",
" \n",
" # Per-sample random cut centres\n",
" cx = tf.random.uniform([batch_size], 0, w, tf.int32) # [B]\n",
" cy = tf.random.uniform([batch_size], 0, h, tf.int32) # [B]\n",
" \n",
" half_h = r_h // 2\n",
" half_w = r_w // 2\n",
" x1 = tf.clip_by_value(cx - half_w, 0, w) # [B]\n",
" x2 = tf.clip_by_value(cx + half_w, 0, w) # [B]\n",
" y1 = tf.clip_by_value(cy - half_h, 0, h) # [B]\n",
" y2 = tf.clip_by_value(cy + half_h, 0, h) # [B]\n",
" \n",
" # Build boolean cut mask via coordinate broadcasting\n",
" col_idx = tf.range(w, dtype=tf.int32) # [W]\n",
" row_idx = tf.range(h, dtype=tf.int32) # [H]\n",
" \n",
" in_x = tf.logical_and(\n",
" tf.reshape(col_idx, [1, 1, w]) >= tf.reshape(x1, [batch_size, 1, 1]),\n",
" tf.reshape(col_idx, [1, 1, w]) < tf.reshape(x2, [batch_size, 1, 1])\n",
" ) # [B, 1, W]\n",
" in_y = tf.logical_and(\n",
" tf.reshape(row_idx, [1, h, 1]) >= tf.reshape(y1, [batch_size, 1, 1]),\n",
" tf.reshape(row_idx, [1, h, 1]) < tf.reshape(y2, [batch_size, 1, 1])\n",
" ) # [B, H, 1]\n",
" \n",
" cut_mask = tf.cast(tf.logical_and(in_y, in_x), tf.float32) # [B, H, W]\n",
" cut_mask = tf.expand_dims(cut_mask, -1) # [B, H, W, 1]\n",
" \n",
" # Mix images\n",
" shuffled = tf.gather(images, random_indices)\n",
" mixed_images = (1.0 - cut_mask) * images + cut_mask * shuffled\n",
" \n",
" # Mix labels\n",
" labels = tf.cast(labels, tf.float32)\n",
" lambda_reshaped = tf.reshape(lambda_param, [-1, 1])\n",
" mixed_labels = lambda_reshaped * labels + (1.0 - lambda_reshaped) * tf.gather(labels, random_indices)\n",
" \n",
" return mixed_images, mixed_labels\n",
"\n",
"# --- RandomErasing ---\n",
"def random_erasing(images, probability=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3)):\n",
" batch_size = tf.shape(images)[0]\n",
" h = tf.shape(images)[1]\n",
" w = tf.shape(images)[2]\n",
" \n",
" target_area = tf.random.uniform([], scale[0], scale[1]) * tf.cast(h * w, tf.float32)\n",
" aspect_ratio = tf.random.uniform([], ratio[0], ratio[1])\n",
" erasing_h = tf.cast(tf.math.sqrt(target_area / aspect_ratio), tf.int32)\n",
" erasing_w = tf.cast(tf.math.sqrt(target_area * aspect_ratio), tf.int32)\n",
" erasing_h = tf.clip_by_value(erasing_h, 1, h - 1)\n",
" erasing_w = tf.clip_by_value(erasing_w, 1, w - 1)\n",
" \n",
" cx = tf.random.uniform([], 0, w - erasing_w, tf.int32)\n",
" cy = tf.random.uniform([], 0, h - erasing_h, tf.int32)\n",
" \n",
" # Build erase mask via coordinate broadcasting (same pattern as CutMix)\n",
" col_idx = tf.range(w, dtype=tf.int32)\n",
" row_idx = tf.range(h, dtype=tf.int32)\n",
" \n",
" in_x = tf.logical_and(col_idx >= cx, col_idx < cx + erasing_w) # [W]\n",
" in_y = tf.logical_and(row_idx >= cy, row_idx < cy + erasing_h) # [H]\n",
" erase_mask = tf.cast(tf.expand_dims(in_y, 1) & tf.expand_dims(in_x, 0), tf.float32) # [H, W]\n",
" erase_mask = tf.expand_dims(erase_mask, 0) # [1, H, W]\n",
" erase_mask = tf.expand_dims(erase_mask, -1) # [1, H, W, 1]\n",
" \n",
" noise = tf.random.uniform([batch_size, erasing_h, erasing_w, 3], 0.0, 255.0, dtype=tf.float32)\n",
" \n",
" # Pad the noise patch to full image size\n",
" paddings = [[0, 0], [cy, h - (cy + erasing_h)], [cx, w - (cx + erasing_w)], [0, 0]]\n",
" noise_padded = tf.pad(noise, paddings, constant_values=0.0)\n",
" \n",
" erased = images * (1.0 - erase_mask) + noise_padded * erase_mask\n",
" return tf.cond(\n",
" tf.random.uniform([]) < probability,\n",
" lambda: erased,\n",
" lambda: images\n",
" )\n",
"\n",
"# --- Geometric augmentation (kept for TTA compatibility) ---\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",
"\n",
"# --- Augment + MixUp/CutMix + RandomErasing pipeline ---\n",
"def augment_and_mix(images, labels):\n",
" # images are uint8 [0,255], labels are int\n",
" # 1. Geometric augmentation\n",
" images = data_augmentation(images, training=True)\n",
" # 2. Convert to float32 for MixUp/CutMix\n",
" images = tf.cast(images, tf.float32)\n",
" # 3. Apply CutMix or MixUp with 50% probability\n",
" choice = tf.random.uniform([])\n",
" labels_onehot = tf.one_hot(labels, NUM_CLASSES)\n",
" images, labels_onehot = tf.cond(\n",
" choice < 0.3, # 30% MixUp\n",
" lambda: mix_up(images, labels_onehot),\n",
" lambda: tf.cond(\n",
" choice < 0.6, # 30% CutMix\n",
" lambda: cut_mix(images, labels_onehot),\n",
" lambda: (images, labels_onehot) # 40% no mix\n",
" )\n",
" )\n",
" # 4. Random Erasing\n",
" images = random_erasing(images, probability=0.25)\n",
" return images, labels_onehot\n",
"\n",
"# --- Preprocessing (EfficientNetV2: [-1,1]) ---\n",
"def preprocess_fn(image, label):\n",
" return preprocess_input(image), label\n",
"\n",
"# --- Class Weights ---\n",
"train_class_counts = Counter()\n",
"for cn in class_names:\n",
" p = os.path.join(train_dir, cn)\n",
" if os.path.exists(p):\n",
" train_class_counts[cn] = len(os.listdir(p))\n",
"\n",
"y_integer = []\n",
"for i, cn in enumerate(class_names):\n",
" y_integer.extend([i] * train_class_counts[cn])\n",
"\n",
"class_weights_array = compute_class_weight('balanced', classes=np.unique(y_integer), y=y_integer)\n",
"class_weights_capped = [min(w, 2.5) for w in class_weights_array]\n",
"class_weights_tensor = tf.constant(class_weights_capped, dtype=tf.float32)\n",
"\n",
"def add_sample_weight(image, label):\n",
" class_indices = tf.argmax(label, axis=-1)\n",
" sample_weights = tf.gather(class_weights_tensor, class_indices)\n",
" return image, label, sample_weights\n",
"\n",
"print(\"Class weights (capped at 2.5):\")\n",
"for i, cn in enumerate(class_names):\n",
" print(f\" {cn}: {class_weights_capped[i]:.4f}\")\n",
"\n",
"# --- Build pipelines ---\n",
"# Train: augment → mix → erase → preprocess → onehot → sample_weight → prefetch\n",
"train_ds = (train_ds\n",
" .map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n",
" .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n",
" .map(add_sample_weight, num_parallel_calls=AUTOTUNE)\n",
" .prefetch(AUTOTUNE))\n",
"\n",
"# Val/Test: preprocess → onehot → prefetch\n",
"val_ds = (val_ds\n",
" .map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n",
" .map(to_one_hot, num_parallel_calls=AUTOTUNE)\n",
" .prefetch(AUTOTUNE))\n",
"\n",
"test_ds = (test_ds\n",
" .map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n",
" .map(to_one_hot, num_parallel_calls=AUTOTUNE)\n",
" .prefetch(AUTOTUNE))\n",
"\n",
"print(\"Data pipelines ready.\")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "47e6aada",
"metadata": {},
"source": [
"## 6. Visualisasi Sampel Data (dengan Augmentasi)"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 18,
"id": "e48f7b06",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 4890 files belonging to 4 classes.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-06-11 17:05:59.854775: I tensorflow/core/framework/local_rendezvous.cc:407] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence\n"
]
},
{
"data": {
"image/png": "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8pe/nOOPP56qqjbbnvXr1/P4xz+e973vfey33348/elPJ8bIueeeyxFHHHGXvF9jjJx99tkAvOQlL1n03+b1e5Lf//73HHbYYbzzne9kfn6eE044oTUMHH744Xd4DpdddhkHHXQQV155JU9+8pPZf//9ufTSSznllFM477zz+MxnPsNRRx3FDTfcwJOf/GQe8YhHcMkll3Dcccfxne98Z5Pj3XjjjRx22GH89V//Nb/61a845JBDeMYznsFoNOJtb3sbBx98MNdee+1m23Jn7seRRx7JqaeeCsDU1NSi5+O0005rP3fllVfyZ3/2Z3znO99hxx135MQTT+TII4/k97//PW95y1s45JBDNhHWb7rpJg4++GDe8Y53MBqNOO644zjppJPYc889ueKKK3jzm9+81ffn7vCDH/wAEGPSypUrN3n/r//6r3nKU57CBRdcwG677cbJJ5/MXnvtxQUXXMBRRx11u8/bGWecwUtf+lKstRx//PEcdthht2tEgbt2LSd5xzvewbOe9SxGoxEnnHAC++23H9/85jc5/vjjeec737mVVwVe+tKX8rKXvYzLLruMQw45hOc85zk89rGPZTAY8K53vYsrrrhiq4+VyWQymUwmc78kZjKZTCaTyTyAeeELXxiB+KQnPekuff+9731vBOJ2220XL7/88vb1EEJ8wxveEIG4bNmyeMsttyz63u677x6BWBRF/NznPrfovbPPPjsCcenSpXFhYWHRe6eddloE4tlnn73Z9gyHw/bYL3/5y2NVVe17v/nNb+Iee+wRgfh3f/d3m/1NID7taU+L69evb99bs2ZNPOCAAyIQ3/KWt9yZyxNjjPGiiy6KQFy1alXbnsFgEJctWxaB+K1vfWuz32vasyWOPvroCMSvf/3ri14/5ZRTIhCf+MQnLjqPtWvXxiOPPLI97sbXsLm2QHzzm98cQwjte+94xzsiEHfZZZe4fPnyeO655y767l/+5V9GID7lKU9Z9HoIIR5xxBERiH/yJ38SN2zY0L5X13V87WtfG4F4zDHHLPreXb0fV199dQTi7rvvvsXrdv3118evfOUr0Xu/6PX5+fn4ohe9KALxFa94xaL33vSmN0Ug/tmf/dmi6xJjjFVVxa985St3uh2bo7mnb3jDG9rXQgjxpptuih/5yEfiypUrIxDf8573bPLdf//3f49AfOhDHxqvvPLKRe9985vfjDMzM7Esy/jLX/5y0XvNdV6yZEn83ve+t9l2banf3ZVrGeO4/yul4n/8x38seu/jH/94VEpFa238yU9+coftuPbaa9tn8/e///0mv/Xzn/88XnvttZs9r0wmk8lkMpkHClnEzmQymUwm84DmuOOOi0B83vOed5e+v/fee0cgvuMd79jkvRBCfMxjHhOB+E//9E+L3mtErNe85jWbPe4+++yzWYH3jkTsj3zkIxGIO++8cxwOh5u8f95550UgzszMxMFg0L7eiKZTU1Pxxhtv3OR7H//4x++y2P/c5z43AvG1r33totdf8YpXRCCedtppm/3eXRGxr7nmmqiUilrr+Itf/GKT7/zkJz+JSqnbFbEPPfTQTYTauq7jihUrIhCf85znbHLc2267LQKxLMtFhoMvfvGLEYgHHHBArOt6k+957+OjHvWoCCwSLO/q/bir4nHD/Px8tNbG7bf
"text/plain": [
"<Figure size 1600x1000 with 12 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Visualisasi augmentasi (non-preprocessed)\n",
"vis_ds = tf.keras.utils.image_dataset_from_directory(\n",
" train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"\n",
"plt.figure(figsize=(16, 10))\n",
"for images, labels in vis_ds.take(1):\n",
" # Original (4)\n",
" for i in range(4):\n",
" plt.subplot(3, 4, i + 1)\n",
" plt.imshow(images[i].numpy().astype(\"uint8\"))\n",
" plt.title(f\"Asli: {class_names[labels[i].numpy()]}\", fontsize=11)\n",
" plt.axis(\"off\")\n",
" # Augmented (4) — geometric only\n",
" aug = data_augmentation(images, training=True)\n",
" for i in range(4):\n",
" plt.subplot(3, 4, i + 5)\n",
" plt.imshow(aug[i].numpy().astype(\"uint8\"))\n",
" plt.title(f\"Aug: {class_names[labels[i].numpy()]}\", fontsize=11)\n",
" plt.axis(\"off\")\n",
" # MixUp/CutMix result (4)\n",
" aug_f = tf.cast(images, tf.float32)\n",
" mixed, _ = mix_up(aug_f, tf.one_hot(labels, NUM_CLASSES))\n",
" for i in range(4):\n",
" plt.subplot(3, 4, i + 9)\n",
" plt.imshow(tf.clip_by_value(mixed[i], 0, 255).numpy().astype(\"uint8\"))\n",
" plt.title(\"MixUp/CutMix\", fontsize=11)\n",
" plt.axis(\"off\")\n",
"\n",
"plt.suptitle(\"Contoh Augmentasi Berlapis\", fontsize=16)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "e5492170",
"metadata": {},
"source": [
"## 7. Arsitektur Model CNN (EfficientNetV2B0)\n",
"\n",
"Base model **EfficientNetV2B0** (imagenet, frozen) + Conv2D tambahan + BatchNorm + Dropout + Dense.\n",
"Ditambah **GaussianNoise(0.1)** untuk regularisasi tambahan."
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 19,
"id": "399f093e",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading checkpoint: /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\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",
"│ gaussian_noise (<span style=\"color: #0087ff; text-decoration-color: #0087ff\">GaussianNoise</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",
"│ gaussian_noise (\u001b[38;5;33mGaussianNoise\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",
" x = layers.GaussianNoise(0.1)(inputs)\n",
" x = base_model(x, training=False)\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",
" x = layers.Conv2D(256, (3, 3), padding='same', activation='swish')(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.GlobalAveragePooling2D()(x)\n",
" x = layers.Dropout(0.3)(x)\n",
" x = layers.Dense(1024, activation='swish')(x)\n",
" x = layers.BatchNormalization()(x)\n",
" x = layers.Dropout(0.4)(x)\n",
" outputs = layers.Dense(num_classes, activation='softmax', dtype='float32')(x)\n",
" return models.Model(inputs, outputs), base_model\n",
"\n",
"if IS_COLAB:\n",
" ckpt_dir = '/content/best_model'\n",
"else:\n",
" ckpt_dir = os.path.join(os.getcwd(), 'best_model')\n",
"checkpoint_path = os.path.join(ckpt_dir, 'best_model.keras')\n",
"\n",
"if os.path.exists(checkpoint_path):\n",
" print(f\"Loading checkpoint: {checkpoint_path}\")\n",
" try:\n",
" model = models.load_model(checkpoint_path, compile=False)\n",
" except Exception as e:\n",
" print(f\"Load failed: {e}. Building fresh.\")\n",
" model, base_model = build_model(NUM_CLASSES)\n",
"else:\n",
" print(\"No checkpoint. Building fresh model.\")\n",
" model, base_model = build_model(NUM_CLASSES)\n",
"\n",
"os.makedirs(ckpt_dir, exist_ok=True)\n",
"model.summary()"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "a5c7c829",
"metadata": {},
"source": [
"## 8. Callbacks\n",
"\n",
"- **ModelCheckpoint**: simpan yang terbaik (val_accuracy)\n",
"- **EarlyStopping**: patience 15 (lebih panjang untuk fine-tuning)\n",
"- **ReduceLROnPlateau**: faktor 0.2, patience 5, min 1e-8\n",
"- **CSVLogger**: riwayat training"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 20,
"id": "f2f08f67",
"metadata": {},
"outputs": [],
"source": [
"import time\n",
"\n",
2026-06-11 19:42:02 +00:00
"log_dir = \"logs/fit/\" + time.strftime(\"%Y%m%d-%H%M%S\")\n",
"\n",
"checkpoint_cb = callbacks.ModelCheckpoint(\n",
" checkpoint_path,\n",
" save_best_only=True,\n",
" monitor=\"val_accuracy\",\n",
" mode=\"max\",\n",
" verbose=1\n",
")\n",
"\n",
"early_stopping_cb = callbacks.EarlyStopping(\n",
" monitor=\"val_accuracy\",\n",
" patience=15,\n",
" restore_best_weights=True,\n",
" mode=\"max\",\n",
" verbose=1\n",
")\n",
"\n",
"reduce_lr_cb = callbacks.ReduceLROnPlateau(\n",
" monitor='val_loss',\n",
" factor=0.2,\n",
" patience=5,\n",
" min_lr=1e-8,\n",
" verbose=1,\n",
" mode=\"min\"\n",
")\n",
"\n",
"csv_logger = callbacks.CSVLogger(os.path.join(ckpt_dir, 'training_log.csv'))\n",
"\n",
"callbacks_list = [checkpoint_cb, early_stopping_cb, reduce_lr_cb, csv_logger]"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "8fb0224a",
"metadata": {},
"source": [
"## 9. Pelatihan Fase 1 — Head Only\n",
"\n",
"Optimizer **AdamW** dengan EMA (Exponential Moving Average) dan **Label Smoothing** 0.2.\n",
"Base model beku, hanya head yang dilatih."
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 21,
"id": "1ba541b1",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fase 1: Head training (base frozen)...\n",
"Epoch 1/30\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 72/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m2s\u001b[0m 36ms/step - accuracy: 0.8908 - loss: 0.8013"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 135ms/step - accuracy: 0.8922 - loss: 0.8094\n",
"Epoch 1: val_accuracy improved from None to 0.95411, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 1: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m61s\u001b[0m 215ms/step - accuracy: 0.8941 - loss: 0.8123 - val_accuracy: 0.9541 - val_loss: 0.7203 - learning_rate: 0.0010\n",
"Epoch 2/30\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 68ms/step - accuracy: 0.9128 - loss: 0.7974"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 64/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 72ms/step - accuracy: 0.9082 - loss: 0.8043"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9014 - loss: 0.8124\n",
"Epoch 2: val_accuracy improved from 0.95411 to 0.95985, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 2: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 94ms/step - accuracy: 0.8957 - loss: 0.8151 - val_accuracy: 0.9598 - val_loss: 0.7770 - learning_rate: 0.0010\n",
"Epoch 3/30\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 68ms/step - accuracy: 0.8883 - loss: 0.8339"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 68ms/step - accuracy: 0.8923 - loss: 0.8253"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.8969 - loss: 0.8170\n",
"Epoch 3: val_accuracy improved from 0.95985 to 0.97514, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 3: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m16s\u001b[0m 96ms/step - accuracy: 0.9033 - loss: 0.8026 - val_accuracy: 0.9751 - val_loss: 0.6700 - learning_rate: 0.0010\n",
"Epoch 4/30\n",
"\u001b[1m 38/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 78ms/step - accuracy: 0.8932 - loss: 0.8082"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 72/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 72ms/step - accuracy: 0.8967 - loss: 0.8057"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.8977 - loss: 0.8050\n",
"Epoch 4: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 84ms/step - accuracy: 0.8984 - loss: 0.8053 - val_accuracy: 0.9618 - val_loss: 0.6673 - learning_rate: 0.0010\n",
"Epoch 5/30\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 82ms/step - accuracy: 0.8997 - loss: 0.8094 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 87/153\u001b[0m \u001b[32m━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━\u001b[0m \u001b[1m4s\u001b[0m 71ms/step - accuracy: 0.8984 - loss: 0.8092"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9004 - loss: 0.8062\n",
"Epoch 5: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 82ms/step - accuracy: 0.9055 - loss: 0.7987 - val_accuracy: 0.9512 - val_loss: 0.7019 - learning_rate: 0.0010\n",
"Epoch 6/30\n",
"\u001b[1m 40/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 77ms/step - accuracy: 0.9069 - loss: 0.7904"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 71ms/step - accuracy: 0.9013 - loss: 0.8002"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.8983 - loss: 0.8076\n",
"Epoch 6: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 82ms/step - accuracy: 0.8965 - loss: 0.8128 - val_accuracy: 0.9646 - val_loss: 0.6677 - learning_rate: 0.0010\n",
"Epoch 7/30\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 82ms/step - accuracy: 0.9011 - loss: 0.7930 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 76/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 75ms/step - accuracy: 0.8995 - loss: 0.8002"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9031 - loss: 0.7991\n",
"Epoch 7: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 84ms/step - accuracy: 0.9065 - loss: 0.7975 - val_accuracy: 0.9685 - val_loss: 0.6607 - learning_rate: 0.0010\n",
"Epoch 8/30\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 74ms/step - accuracy: 0.9106 - loss: 0.7855"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 71ms/step - accuracy: 0.9116 - loss: 0.7886"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9099 - loss: 0.7915\n",
"Epoch 8: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 84ms/step - accuracy: 0.9108 - loss: 0.7886 - val_accuracy: 0.9732 - val_loss: 0.6645 - learning_rate: 0.0010\n",
"Epoch 9/30\n",
"\u001b[1m 38/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 64ms/step - accuracy: 0.9102 - loss: 0.7870"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 74/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 75ms/step - accuracy: 0.9106 - loss: 0.7890"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9121 - loss: 0.7885\n",
"Epoch 9: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9119 - loss: 0.7855 - val_accuracy: 0.9474 - val_loss: 0.6715 - learning_rate: 0.0010\n",
"Epoch 10/30\n",
"\u001b[1m 41/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 72ms/step - accuracy: 0.9041 - loss: 0.7846"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 84/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m4s\u001b[0m 70ms/step - accuracy: 0.9028 - loss: 0.7952"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9047 - loss: 0.7963\n",
"Epoch 10: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 82ms/step - accuracy: 0.9102 - loss: 0.7911 - val_accuracy: 0.9656 - val_loss: 0.6569 - learning_rate: 0.0010\n",
"Epoch 11/30\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 66ms/step - accuracy: 0.9093 - loss: 0.7968"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 69ms/step - accuracy: 0.9116 - loss: 0.7899"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9124 - loss: 0.7892\n",
"Epoch 11: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 81ms/step - accuracy: 0.9110 - loss: 0.7865 - val_accuracy: 0.9522 - val_loss: 0.6961 - learning_rate: 0.0010\n",
"Epoch 12/30\n",
"\u001b[1m 43/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 66ms/step - accuracy: 0.9099 - loss: 0.7873"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 82/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m4s\u001b[0m 68ms/step - accuracy: 0.9096 - loss: 0.7893"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 67ms/step - accuracy: 0.9108 - loss: 0.7897\n",
"Epoch 12: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 80ms/step - accuracy: 0.9147 - loss: 0.7860 - val_accuracy: 0.9627 - val_loss: 0.6555 - learning_rate: 0.0010\n",
"Epoch 13/30\n",
"\u001b[1m 38/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 60ms/step - accuracy: 0.8981 - loss: 0.7914"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 66/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 68ms/step - accuracy: 0.9016 - loss: 0.7904"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 66ms/step - accuracy: 0.9061 - loss: 0.7873\n",
"Epoch 13: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 82ms/step - accuracy: 0.9129 - loss: 0.7795 - val_accuracy: 0.9560 - val_loss: 0.6718 - learning_rate: 0.0010\n",
"Epoch 14/30\n",
"\u001b[1m 56/153\u001b[0m \u001b[32m━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 75ms/step - accuracy: 0.9193 - loss: 0.7872"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9188 - loss: 0.7865"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 74ms/step - accuracy: 0.9196 - loss: 0.7812\n",
"Epoch 14: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 89ms/step - accuracy: 0.9180 - loss: 0.7753 - val_accuracy: 0.9570 - val_loss: 0.6654 - learning_rate: 0.0010\n",
"Epoch 15/30\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 74ms/step - accuracy: 0.9333 - loss: 0.7673"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 69ms/step - accuracy: 0.9285 - loss: 0.7714"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9224 - loss: 0.7744\n",
"Epoch 15: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 83ms/step - accuracy: 0.9172 - loss: 0.7775 - val_accuracy: 0.9589 - val_loss: 0.6675 - learning_rate: 0.0010\n",
"Epoch 16/30\n",
"\u001b[1m 29/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 73ms/step - accuracy: 0.9020 - loss: 0.7942"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 72ms/step - accuracy: 0.9073 - loss: 0.7869"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9098 - loss: 0.7838\n",
"Epoch 16: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9135 - loss: 0.7756 - val_accuracy: 0.9656 - val_loss: 0.6626 - learning_rate: 0.0010\n",
"Epoch 17/30\n",
"\u001b[1m 36/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 78ms/step - accuracy: 0.9200 - loss: 0.7642"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 67/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 78ms/step - accuracy: 0.9167 - loss: 0.7716"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9165 - loss: 0.7747\n",
"Epoch 17: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9160 - loss: 0.7748 - val_accuracy: 0.9723 - val_loss: 0.6553 - learning_rate: 0.0010\n",
"Epoch 18/30\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 77ms/step - accuracy: 0.9418 - loss: 0.7480 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 78ms/step - accuracy: 0.9343 - loss: 0.7633"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9280 - loss: 0.7724\n",
"Epoch 18: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9223 - loss: 0.7801 - val_accuracy: 0.9713 - val_loss: 0.6571 - learning_rate: 0.0010\n",
"Epoch 18: early stopping\n",
"Restoring model weights from the end of the best epoch: 3.\n"
]
}
],
"source": [
"model.compile(\n",
" optimizer=AdamW(use_ema=True, ema_momentum=0.999,\n",
" learning_rate=1e-3, weight_decay=1e-4),\n",
" loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.2),\n",
" metrics=['accuracy']\n",
")\n",
"\n",
"print(\"Fase 1: Head training (base frozen)...\")\n",
"history_1 = model.fit(\n",
" train_ds,\n",
" validation_data=val_ds,\n",
" epochs=30,\n",
" callbacks=callbacks_list\n",
")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "e180ce30",
"metadata": {},
"source": [
"## 10. Fine-tuning Fase 2 — Unfreeze Layer Atas\n",
"\n",
"Membuka **100 layer teratas** base model. Learning rate diturunkan ke 1e-4."
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 22,
"id": "ba09fabd",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fase 2: Fine-tuning top 100 layers...\n",
"Epoch 19/60\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n",
"2026-06-11 17:11:41.079500: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:11:41.237435: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 78/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m2s\u001b[0m 39ms/step - accuracy: 0.8603 - loss: 0.8519"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m150/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 51ms/step - accuracy: 0.8652 - loss: 0.8433"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-06-11 17:12:10.589920: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:12:10.748299: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 194ms/step - accuracy: 0.8654 - loss: 0.8430\n",
"Epoch 19: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m89s\u001b[0m 259ms/step - accuracy: 0.8763 - loss: 0.8239 - val_accuracy: 0.9637 - val_loss: 0.6448 - learning_rate: 1.0000e-04\n",
"Epoch 20/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 67ms/step - accuracy: 0.8962 - loss: 0.8058"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 70ms/step - accuracy: 0.9015 - loss: 0.8021"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 67ms/step - accuracy: 0.9021 - loss: 0.7997\n",
"Epoch 20: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 82ms/step - accuracy: 0.9033 - loss: 0.7931 - val_accuracy: 0.9656 - val_loss: 0.6464 - learning_rate: 1.0000e-04\n",
"Epoch 21/60\n",
"\u001b[1m 38/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 80ms/step - accuracy: 0.9096 - loss: 0.7774"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 75ms/step - accuracy: 0.9055 - loss: 0.7842"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9021 - loss: 0.7901\n",
"Epoch 21: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9027 - loss: 0.7900 - val_accuracy: 0.9637 - val_loss: 0.6389 - learning_rate: 1.0000e-04\n",
"Epoch 22/60\n",
"\u001b[1m 41/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 86ms/step - accuracy: 0.9098 - loss: 0.7861 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9108 - loss: 0.7885"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 74ms/step - accuracy: 0.9111 - loss: 0.7886\n",
"Epoch 22: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 89ms/step - accuracy: 0.9096 - loss: 0.7858 - val_accuracy: 0.9751 - val_loss: 0.6314 - learning_rate: 1.0000e-04\n",
"Epoch 23/60\n",
"\u001b[1m 46/153\u001b[0m \u001b[32m━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 77ms/step - accuracy: 0.9281 - loss: 0.7582"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 72/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9233 - loss: 0.7659"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9193 - loss: 0.7723\n",
"Epoch 23: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 88ms/step - accuracy: 0.9176 - loss: 0.7735 - val_accuracy: 0.9751 - val_loss: 0.6300 - learning_rate: 1.0000e-04\n",
"Epoch 24/60\n",
"\u001b[1m 30/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 81ms/step - accuracy: 0.9006 - loss: 0.7649 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 76/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 72ms/step - accuracy: 0.9058 - loss: 0.7704"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9101 - loss: 0.7699\n",
"Epoch 24: val_accuracy did not improve from 0.97514\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9172 - loss: 0.7660 - val_accuracy: 0.9723 - val_loss: 0.6350 - learning_rate: 1.0000e-04\n",
"Epoch 25/60\n",
"\u001b[1m 50/153\u001b[0m \u001b[32m━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 77ms/step - accuracy: 0.9242 - loss: 0.7608"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 72/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9237 - loss: 0.7632"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9236 - loss: 0.7635\n",
"Epoch 25: val_accuracy improved from 0.97514 to 0.97897, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 25: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m16s\u001b[0m 98ms/step - accuracy: 0.9239 - loss: 0.7602 - val_accuracy: 0.9790 - val_loss: 0.6311 - learning_rate: 1.0000e-04\n",
"Epoch 26/60\n",
"\u001b[1m 38/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 67ms/step - accuracy: 0.9397 - loss: 0.7498"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 70ms/step - accuracy: 0.9341 - loss: 0.7563"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9308 - loss: 0.7591\n",
"Epoch 26: val_accuracy did not improve from 0.97897\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9284 - loss: 0.7577 - val_accuracy: 0.9780 - val_loss: 0.6284 - learning_rate: 1.0000e-04\n",
"Epoch 27/60\n",
"\u001b[1m 30/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 83ms/step - accuracy: 0.9301 - loss: 0.7455"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 84/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 76ms/step - accuracy: 0.9292 - loss: 0.7529"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9306 - loss: 0.7538\n",
"Epoch 27: val_accuracy did not improve from 0.97897\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9339 - loss: 0.7496 - val_accuracy: 0.9780 - val_loss: 0.6246 - learning_rate: 1.0000e-04\n",
"Epoch 28/60\n",
"\u001b[1m 64/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 74ms/step - accuracy: 0.9320 - loss: 0.7515"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n",
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9291 - loss: 0.7553\n",
"Epoch 28: val_accuracy did not improve from 0.97897\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9278 - loss: 0.7560 - val_accuracy: 0.9771 - val_loss: 0.6247 - learning_rate: 1.0000e-04\n",
"Epoch 29/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 83ms/step - accuracy: 0.9392 - loss: 0.7419"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 65/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 79ms/step - accuracy: 0.9357 - loss: 0.7439"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9338 - loss: 0.7478\n",
"Epoch 29: val_accuracy improved from 0.97897 to 0.98088, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 29: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 95ms/step - accuracy: 0.9321 - loss: 0.7475 - val_accuracy: 0.9809 - val_loss: 0.6241 - learning_rate: 1.0000e-04\n",
"Epoch 30/60\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 69ms/step - accuracy: 0.9211 - loss: 0.7697"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 66/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 72ms/step - accuracy: 0.9290 - loss: 0.7616"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9309 - loss: 0.7562\n",
"Epoch 30: val_accuracy improved from 0.98088 to 0.98279, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 30: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 90ms/step - accuracy: 0.9319 - loss: 0.7498 - val_accuracy: 0.9828 - val_loss: 0.6244 - learning_rate: 1.0000e-04\n",
"Epoch 31/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 85ms/step - accuracy: 0.9480 - loss: 0.7287"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9436 - loss: 0.7344"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9419 - loss: 0.7386\n",
"Epoch 31: val_accuracy did not improve from 0.98279\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9393 - loss: 0.7419 - val_accuracy: 0.9828 - val_loss: 0.6205 - learning_rate: 1.0000e-04\n",
"Epoch 32/60\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 75ms/step - accuracy: 0.9310 - loss: 0.7688"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 74ms/step - accuracy: 0.9300 - loss: 0.7629"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9298 - loss: 0.7579\n",
"Epoch 32: val_accuracy did not improve from 0.98279\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9313 - loss: 0.7486 - val_accuracy: 0.9828 - val_loss: 0.6224 - learning_rate: 1.0000e-04\n",
"Epoch 33/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 71ms/step - accuracy: 0.9487 - loss: 0.7287"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9475 - loss: 0.7323"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9430 - loss: 0.7388\n",
"Epoch 33: val_accuracy did not improve from 0.98279\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 90ms/step - accuracy: 0.9374 - loss: 0.7429 - val_accuracy: 0.9809 - val_loss: 0.6203 - learning_rate: 1.0000e-04\n",
"Epoch 34/60\n",
"\u001b[1m 36/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 80ms/step - accuracy: 0.9398 - loss: 0.7303"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 75ms/step - accuracy: 0.9384 - loss: 0.7403"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9367 - loss: 0.7442\n",
"Epoch 34: val_accuracy did not improve from 0.98279\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9374 - loss: 0.7437 - val_accuracy: 0.9790 - val_loss: 0.6263 - learning_rate: 1.0000e-04\n",
"Epoch 35/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 79ms/step - accuracy: 0.9413 - loss: 0.7367"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9405 - loss: 0.7398"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 74ms/step - accuracy: 0.9404 - loss: 0.7415\n",
"Epoch 35: val_accuracy did not improve from 0.98279\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 89ms/step - accuracy: 0.9395 - loss: 0.7400 - val_accuracy: 0.9828 - val_loss: 0.6210 - learning_rate: 1.0000e-04\n",
"Epoch 36/60\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 77ms/step - accuracy: 0.9411 - loss: 0.7312"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 65/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9378 - loss: 0.7412"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9379 - loss: 0.7430\n",
"Epoch 36: val_accuracy improved from 0.98279 to 0.98566, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 36: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 93ms/step - accuracy: 0.9378 - loss: 0.7419 - val_accuracy: 0.9857 - val_loss: 0.6177 - learning_rate: 1.0000e-04\n",
"Epoch 37/60\n",
"\u001b[1m 39/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 72ms/step - accuracy: 0.9443 - loss: 0.7402"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 71ms/step - accuracy: 0.9412 - loss: 0.7417"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9393 - loss: 0.7431\n",
"Epoch 37: val_accuracy did not improve from 0.98566\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 82ms/step - accuracy: 0.9389 - loss: 0.7403 - val_accuracy: 0.9847 - val_loss: 0.6154 - learning_rate: 1.0000e-04\n",
"Epoch 38/60\n",
"\u001b[1m 37/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 82ms/step - accuracy: 0.9461 - loss: 0.7304"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m117/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━\u001b[0m \u001b[1m2s\u001b[0m 73ms/step - accuracy: 0.9463 - loss: 0.7330"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9453 - loss: 0.7337\n",
"Epoch 38: val_accuracy improved from 0.98566 to 0.98662, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 38: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 96ms/step - accuracy: 0.9417 - loss: 0.7345 - val_accuracy: 0.9866 - val_loss: 0.6151 - learning_rate: 1.0000e-04\n",
"Epoch 39/60\n",
"\u001b[1m 42/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 79ms/step - accuracy: 0.9449 - loss: 0.7251"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 71/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 79ms/step - accuracy: 0.9439 - loss: 0.7302"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9420 - loss: 0.7343\n",
"Epoch 39: val_accuracy did not improve from 0.98662\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9397 - loss: 0.7370 - val_accuracy: 0.9818 - val_loss: 0.6191 - learning_rate: 1.0000e-04\n",
"Epoch 40/60\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 79ms/step - accuracy: 0.9374 - loss: 0.7308"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 75ms/step - accuracy: 0.9419 - loss: 0.7314"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9420 - loss: 0.7341\n",
"Epoch 40: val_accuracy improved from 0.98662 to 0.98757, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\n",
"Epoch 40: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 96ms/step - accuracy: 0.9440 - loss: 0.7332 - val_accuracy: 0.9876 - val_loss: 0.6149 - learning_rate: 1.0000e-04\n",
"Epoch 41/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 67ms/step - accuracy: 0.9416 - loss: 0.7311"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 77/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 77ms/step - accuracy: 0.9450 - loss: 0.7311"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9461 - loss: 0.7309\n",
"Epoch 41: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9476 - loss: 0.7281 - val_accuracy: 0.9828 - val_loss: 0.6191 - learning_rate: 1.0000e-04\n",
"Epoch 42/60\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 82ms/step - accuracy: 0.9547 - loss: 0.7103"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 76/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 75ms/step - accuracy: 0.9456 - loss: 0.7218"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9441 - loss: 0.7269\n",
"Epoch 42: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 83ms/step - accuracy: 0.9464 - loss: 0.7277 - val_accuracy: 0.9857 - val_loss: 0.6179 - learning_rate: 1.0000e-04\n",
"Epoch 43/60\n",
"\u001b[1m 30/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 84ms/step - accuracy: 0.9397 - loss: 0.7041"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 67/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 75ms/step - accuracy: 0.9422 - loss: 0.7177"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9454 - loss: 0.7238\n",
"Epoch 43: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9501 - loss: 0.7242 - val_accuracy: 0.9857 - val_loss: 0.6156 - learning_rate: 1.0000e-04\n",
"Epoch 44/60\n",
"\u001b[1m 37/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 86ms/step - accuracy: 0.9436 - loss: 0.7309 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 80/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 79ms/step - accuracy: 0.9452 - loss: 0.7302"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9444 - loss: 0.7302\n",
"Epoch 44: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9436 - loss: 0.7278 - val_accuracy: 0.9866 - val_loss: 0.6154 - learning_rate: 1.0000e-04\n",
"Epoch 45/60\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 89ms/step - accuracy: 0.9404 - loss: 0.7367"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 80ms/step - accuracy: 0.9442 - loss: 0.7334"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 74ms/step - accuracy: 0.9477 - loss: 0.7307\n",
"Epoch 45: val_accuracy did not improve from 0.98757\n",
"\n",
"Epoch 45: ReduceLROnPlateau reducing learning rate to 1.9999999494757503e-05.\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9501 - loss: 0.7272 - val_accuracy: 0.9828 - val_loss: 0.6205 - learning_rate: 1.0000e-04\n",
"Epoch 46/60\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 66ms/step - accuracy: 0.9486 - loss: 0.7205"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 66ms/step - accuracy: 0.9491 - loss: 0.7207"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 65ms/step - accuracy: 0.9501 - loss: 0.7230\n",
"Epoch 46: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 79ms/step - accuracy: 0.9507 - loss: 0.7220 - val_accuracy: 0.9866 - val_loss: 0.6155 - learning_rate: 2.0000e-05\n",
"Epoch 47/60\n",
"\u001b[1m 40/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 75ms/step - accuracy: 0.9507 - loss: 0.7353"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9503 - loss: 0.7324"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9493 - loss: 0.7299\n",
"Epoch 47: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9470 - loss: 0.7256 - val_accuracy: 0.9857 - val_loss: 0.6153 - learning_rate: 2.0000e-05\n",
"Epoch 48/60\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 70ms/step - accuracy: 0.9311 - loss: 0.7394"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 77/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 74ms/step - accuracy: 0.9393 - loss: 0.7374"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9450 - loss: 0.7312\n",
"Epoch 48: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 88ms/step - accuracy: 0.9528 - loss: 0.7190 - val_accuracy: 0.9857 - val_loss: 0.6142 - learning_rate: 2.0000e-05\n",
"Epoch 49/60\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 68ms/step - accuracy: 0.9430 - loss: 0.7231"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 71ms/step - accuracy: 0.9468 - loss: 0.7197"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9486 - loss: 0.7203\n",
"Epoch 49: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9495 - loss: 0.7192 - val_accuracy: 0.9857 - val_loss: 0.6142 - learning_rate: 2.0000e-05\n",
"Epoch 50/60\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 79ms/step - accuracy: 0.9544 - loss: 0.7062"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 77/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 77ms/step - accuracy: 0.9543 - loss: 0.7156"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9544 - loss: 0.7201\n",
"Epoch 50: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9556 - loss: 0.7218 - val_accuracy: 0.9857 - val_loss: 0.6141 - learning_rate: 2.0000e-05\n",
"Epoch 51/60\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 75ms/step - accuracy: 0.9369 - loss: 0.7202"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 71ms/step - accuracy: 0.9399 - loss: 0.7260"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9426 - loss: 0.7270\n",
"Epoch 51: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 83ms/step - accuracy: 0.9485 - loss: 0.7215 - val_accuracy: 0.9866 - val_loss: 0.6120 - learning_rate: 2.0000e-05\n",
"Epoch 52/60\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 81ms/step - accuracy: 0.9490 - loss: 0.7133"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9513 - loss: 0.7147"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9511 - loss: 0.7186\n",
"Epoch 52: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 83ms/step - accuracy: 0.9515 - loss: 0.7192 - val_accuracy: 0.9866 - val_loss: 0.6140 - learning_rate: 2.0000e-05\n",
"Epoch 53/60\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 78ms/step - accuracy: 0.9581 - loss: 0.7043"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 77ms/step - accuracy: 0.9552 - loss: 0.7114"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9532 - loss: 0.7162\n",
"Epoch 53: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9519 - loss: 0.7191 - val_accuracy: 0.9866 - val_loss: 0.6126 - learning_rate: 2.0000e-05\n",
"Epoch 54/60\n",
"\u001b[1m 34/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 65ms/step - accuracy: 0.9428 - loss: 0.7223"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 72/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 67ms/step - accuracy: 0.9470 - loss: 0.7227"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m151/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 68ms/step - accuracy: 0.9497 - loss: 0.7232\n",
"Epoch 54: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 83ms/step - accuracy: 0.9519 - loss: 0.7192 - val_accuracy: 0.9866 - val_loss: 0.6121 - learning_rate: 2.0000e-05\n",
"Epoch 55/60\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 81ms/step - accuracy: 0.9524 - loss: 0.7033 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 65/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 78ms/step - accuracy: 0.9525 - loss: 0.7081"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9527 - loss: 0.7140\n",
"Epoch 55: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m20s\u001b[0m 84ms/step - accuracy: 0.9528 - loss: 0.7169 - val_accuracy: 0.9837 - val_loss: 0.6128 - learning_rate: 2.0000e-05\n",
"Epoch 55: early stopping\n",
"Restoring model weights from the end of the best epoch: 40.\n"
]
}
],
"source": [
2026-06-11 19:42:02 +00:00
"base_model = model.layers[2] # layer[0]=InputLayer, layer[1]=GaussianNoise, layer[2]=EfficientNetV2B0\n",
"base_model.trainable = True\n",
"for layer in base_model.layers[:-100]:\n",
" layer.trainable = False\n",
"\n",
"model.compile(\n",
" optimizer=AdamW(use_ema=True, ema_momentum=0.999,\n",
" learning_rate=1e-4, weight_decay=1e-4),\n",
" loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.2),\n",
" metrics=['accuracy']\n",
")\n",
"\n",
"print(\"Fase 2: Fine-tuning top 100 layers...\")\n",
"history_2 = model.fit(\n",
" train_ds,\n",
" validation_data=val_ds,\n",
" epochs=60,\n",
" initial_epoch=history_1.epoch[-1] + 1,\n",
" callbacks=callbacks_list\n",
")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "5b3a6e29",
"metadata": {},
"source": [
"## 11. Fine-tuning Fase 3 — Full Unfreeze\n",
"\n",
"Membuka **semua layer** base model. Learning rate 5e-5 (sangat kecil agar tidak merusak bobot pretrained)."
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 23,
"id": "410d11c5",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Fase 3: Full fine-tuning...\n",
"Epoch 56/90\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n",
"2026-06-11 17:22:10.365783: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:22:10.516772: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:22:11.003935: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:22:11.170998: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:22:15.705420: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:22:15.856916: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 48/153\u001b[0m \u001b[32m━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 52ms/step - accuracy: 0.8750 - loss: 0.8173"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 55ms/step - accuracy: 0.8887 - loss: 0.8050"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-06-11 17:23:02.858842: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:23:03.009825: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:23:03.495720: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:23:03.662273: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:23:07.775573: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:23:07.927092: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 351ms/step - accuracy: 0.8887 - loss: 0.8049\n",
"Epoch 56: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m157s\u001b[0m 417ms/step - accuracy: 0.9000 - loss: 0.7896 - val_accuracy: 0.9646 - val_loss: 0.6448 - learning_rate: 5.0000e-05\n",
"Epoch 57/90\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 80ms/step - accuracy: 0.9124 - loss: 0.7628"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 99/153\u001b[0m \u001b[32m━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━\u001b[0m \u001b[1m4s\u001b[0m 75ms/step - accuracy: 0.9152 - loss: 0.7619"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9167 - loss: 0.7615\n",
"Epoch 57: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9213 - loss: 0.7588 - val_accuracy: 0.9732 - val_loss: 0.6351 - learning_rate: 5.0000e-05\n",
"Epoch 58/90\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 72ms/step - accuracy: 0.9371 - loss: 0.7455"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 73/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 73ms/step - accuracy: 0.9333 - loss: 0.7503"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step - accuracy: 0.9298 - loss: 0.7535\n",
"Epoch 58: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 82ms/step - accuracy: 0.9260 - loss: 0.7548 - val_accuracy: 0.9761 - val_loss: 0.6319 - learning_rate: 5.0000e-05\n",
"Epoch 59/90\n",
"\u001b[1m 33/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 87ms/step - accuracy: 0.9335 - loss: 0.7396"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 75/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 78ms/step - accuracy: 0.9295 - loss: 0.7522"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9292 - loss: 0.7565\n",
"Epoch 59: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m21s\u001b[0m 85ms/step - accuracy: 0.9321 - loss: 0.7544 - val_accuracy: 0.9771 - val_loss: 0.6291 - learning_rate: 5.0000e-05\n",
"Epoch 60/90\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 75ms/step - accuracy: 0.9324 - loss: 0.7550"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9322 - loss: 0.7533"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9339 - loss: 0.7503\n",
"Epoch 60: val_accuracy did not improve from 0.98757\n",
"\n",
"Epoch 60: ReduceLROnPlateau reducing learning rate to 9.999999747378752e-06.\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9348 - loss: 0.7452 - val_accuracy: 0.9685 - val_loss: 0.6415 - learning_rate: 5.0000e-05\n",
"Epoch 61/90\n",
"\u001b[1m 29/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 89ms/step - accuracy: 0.9491 - loss: 0.7270"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 70/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9471 - loss: 0.7332"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9448 - loss: 0.7365\n",
"Epoch 61: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 85ms/step - accuracy: 0.9393 - loss: 0.7366 - val_accuracy: 0.9751 - val_loss: 0.6266 - learning_rate: 1.0000e-05\n",
"Epoch 62/90\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 81ms/step - accuracy: 0.9465 - loss: 0.7358 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 95/153\u001b[0m \u001b[32m━━━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━\u001b[0m \u001b[1m4s\u001b[0m 77ms/step - accuracy: 0.9391 - loss: 0.7420"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9384 - loss: 0.7421\n",
"Epoch 62: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 90ms/step - accuracy: 0.9387 - loss: 0.7385 - val_accuracy: 0.9771 - val_loss: 0.6232 - learning_rate: 1.0000e-05\n",
"Epoch 63/90\n",
"\u001b[1m 47/153\u001b[0m \u001b[32m━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 76ms/step - accuracy: 0.9410 - loss: 0.7559"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 76ms/step - accuracy: 0.9399 - loss: 0.7529"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9388 - loss: 0.7501\n",
"Epoch 63: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9403 - loss: 0.7426 - val_accuracy: 0.9742 - val_loss: 0.6271 - learning_rate: 1.0000e-05\n",
"Epoch 64/90\n",
"\u001b[1m 35/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 84ms/step - accuracy: 0.9469 - loss: 0.7338 "
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 76/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 77ms/step - accuracy: 0.9449 - loss: 0.7385"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 73ms/step - accuracy: 0.9452 - loss: 0.7382\n",
"Epoch 64: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9436 - loss: 0.7356 - val_accuracy: 0.9771 - val_loss: 0.6201 - learning_rate: 1.0000e-05\n",
"Epoch 65/90\n",
"\u001b[1m 29/153\u001b[0m \u001b[32m━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 85ms/step - accuracy: 0.9236 - loss: 0.7620"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 65/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 75ms/step - accuracy: 0.9298 - loss: 0.7583"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9346 - loss: 0.7528\n",
"Epoch 65: val_accuracy did not improve from 0.98757\n",
"\n",
"Epoch 65: ReduceLROnPlateau reducing learning rate to 1.9999999494757505e-06.\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 84ms/step - accuracy: 0.9407 - loss: 0.7423 - val_accuracy: 0.9761 - val_loss: 0.6246 - learning_rate: 1.0000e-05\n",
"Epoch 66/90\n",
"\u001b[1m 36/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m9s\u001b[0m 82ms/step - accuracy: 0.9442 - loss: 0.7218"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 68/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 73ms/step - accuracy: 0.9456 - loss: 0.7259"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 69ms/step - accuracy: 0.9451 - loss: 0.7287\n",
"Epoch 66: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 84ms/step - accuracy: 0.9452 - loss: 0.7264 - val_accuracy: 0.9761 - val_loss: 0.6244 - learning_rate: 2.0000e-06\n",
"Epoch 67/90\n",
"\u001b[1m 32/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 70ms/step - accuracy: 0.9512 - loss: 0.7123"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 65/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 70ms/step - accuracy: 0.9483 - loss: 0.7208"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9436 - loss: 0.7282\n",
"Epoch 67: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 83ms/step - accuracy: 0.9407 - loss: 0.7299 - val_accuracy: 0.9780 - val_loss: 0.6249 - learning_rate: 2.0000e-06\n",
"Epoch 68/90\n",
"\u001b[1m 53/153\u001b[0m \u001b[32m━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━\u001b[0m \u001b[1m7s\u001b[0m 74ms/step - accuracy: 0.9455 - loss: 0.7280"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 67/153\u001b[0m \u001b[32m━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 72ms/step - accuracy: 0.9457 - loss: 0.7291"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 70ms/step - accuracy: 0.9452 - loss: 0.7308\n",
"Epoch 68: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9442 - loss: 0.7296 - val_accuracy: 0.9780 - val_loss: 0.6240 - learning_rate: 2.0000e-06\n",
"Epoch 69/90\n",
"\u001b[1m 43/153\u001b[0m \u001b[32m━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━\u001b[0m \u001b[1m8s\u001b[0m 77ms/step - accuracy: 0.9282 - loss: 0.7398"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 82/153\u001b[0m \u001b[32m━━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━\u001b[0m \u001b[1m5s\u001b[0m 75ms/step - accuracy: 0.9330 - loss: 0.7367"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step - accuracy: 0.9374 - loss: 0.7340\n",
"Epoch 69: val_accuracy did not improve from 0.98757\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 87ms/step - accuracy: 0.9423 - loss: 0.7319 - val_accuracy: 0.9751 - val_loss: 0.6239 - learning_rate: 2.0000e-06\n",
"Epoch 70/90\n",
"\u001b[1m 31/153\u001b[0m \u001b[32m━━━━\u001b[0m\u001b[37m━━━━━━━━━━━━━━━━\u001b[0m \u001b[1m10s\u001b[0m 86ms/step - accuracy: 0.9618 - loss: 0.7141"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: bad Huffman code\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m 69/153\u001b[0m \u001b[32m━━━━━━━━━\u001b[0m\u001b[37m━━━━━━━━━━━\u001b[0m \u001b[1m6s\u001b[0m 78ms/step - accuracy: 0.9542 - loss: 0.7217"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"Corrupt JPEG data: 75969 extraneous bytes before marker 0xd2\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
"\u001b[1m152/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m━\u001b[0m \u001b[1m0s\u001b[0m 71ms/step - accuracy: 0.9460 - loss: 0.7293\n",
"Epoch 70: val_accuracy did not improve from 0.98757\n",
"\n",
"Epoch 70: ReduceLROnPlateau reducing learning rate to 3.999999989900971e-07.\n",
"\u001b[1m153/153\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m14s\u001b[0m 86ms/step - accuracy: 0.9380 - loss: 0.7345 - val_accuracy: 0.9751 - val_loss: 0.6271 - learning_rate: 2.0000e-06\n",
"Epoch 70: early stopping\n",
"Restoring model weights from the end of the best epoch: 56.\n"
]
}
],
"source": [
2026-06-11 19:42:02 +00:00
"# Unfreeze all layers in base model\n",
"for layer in base_model.layers:\n",
" layer.trainable = True\n",
"\n",
"model.compile(\n",
" optimizer=AdamW(use_ema=True, ema_momentum=0.999,\n",
" learning_rate=5e-5, weight_decay=1e-4),\n",
" loss=tf.keras.losses.CategoricalCrossentropy(label_smoothing=0.2),\n",
" metrics=['accuracy']\n",
")\n",
"\n",
"print(\"Fase 3: Full fine-tuning...\")\n",
"history_3 = model.fit(\n",
" train_ds,\n",
" validation_data=val_ds,\n",
" epochs=90,\n",
" initial_epoch=history_2.epoch[-1] + 1,\n",
" callbacks=callbacks_list\n",
")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "027830a8",
"metadata": {},
"source": [
"## 12. Plot Akurasi dan Loss (Gabungan Semua Fase)"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 24,
"id": "e784723d",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1600x600 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"# Gabungkan history\n",
"acc = history_1.history['accuracy'] + history_2.history['accuracy'] + history_3.history['accuracy']\n",
"val_acc = history_1.history['val_accuracy'] + history_2.history['val_accuracy'] + history_3.history['val_accuracy']\n",
"loss = history_1.history['loss'] + history_2.history['loss'] + history_3.history['loss']\n",
"val_loss = history_1.history['val_loss'] + history_2.history['val_loss'] + history_3.history['val_loss']\n",
"\n",
"# Batas antar fase\n",
"boundary_1 = len(history_1.history['accuracy']) - 1\n",
"boundary_2 = boundary_1 + len(history_2.history['accuracy'])\n",
"\n",
"plt.figure(figsize=(16, 6))\n",
"\n",
"plt.subplot(1, 2, 1)\n",
"plt.plot(acc, label='Training Accuracy', linewidth=2)\n",
"plt.plot(val_acc, label='Validation Accuracy', linewidth=2)\n",
"plt.axvline(x=boundary_1, color='gray', linestyle='--', alpha=0.7, label='Fase 2 start')\n",
"plt.axvline(x=boundary_2, color='black', linestyle='--', alpha=0.7, label='Fase 3 start')\n",
"plt.legend(fontsize=12)\n",
"plt.title('Training & Validation Accuracy', fontsize=14)\n",
"plt.xlabel('Epoch')\n",
"plt.ylabel('Accuracy')\n",
"plt.grid(alpha=0.3)\n",
"\n",
"plt.subplot(1, 2, 2)\n",
"plt.plot(loss, label='Training Loss', linewidth=2)\n",
"plt.plot(val_loss, label='Validation Loss', linewidth=2)\n",
"plt.axvline(x=boundary_1, color='gray', linestyle='--', alpha=0.7, label='Fase 2 start')\n",
"plt.axvline(x=boundary_2, color='black', linestyle='--', alpha=0.7, label='Fase 3 start')\n",
"plt.legend(fontsize=12)\n",
"plt.title('Training & Validation Loss', fontsize=14)\n",
"plt.xlabel('Epoch')\n",
"plt.ylabel('Loss')\n",
"plt.grid(alpha=0.3)\n",
"\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "f42f70d1",
"metadata": {},
"source": [
"## 13. Test Time Augmentation (TTA)\n",
"\n",
"Menggunakan model terbaik (EMA) dan menerapkan augmentasi geometrik saat inferensi untuk meningkatkan akurasi."
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 25,
"id": "97cc1a15",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Loading best model from /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras...\n",
"Found 1052 files belonging to 4 classes.\n"
]
},
{
"name": "stderr",
"output_type": "stream",
"text": [
"2026-06-11 17:27:25.283775: I external/local_xla/xla/stream_executor/cuda/subprocess_compilation.cc:346] ptxas warning : Registers are spilled to local memory in function 'gemm_fusion_dot_2352', 36 bytes spill stores, 36 bytes spill loads\n",
"\n",
"2026-06-11 17:27:26.774709: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:26.931108: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:27.736506: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:27.900098: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:28.454775: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:28.605712: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:29.033373: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:29.200411: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:30.126019: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:30.281824: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:30.478454: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n",
"2026-06-11 17:27:30.636887: E external/local_xla/xla/stream_executor/cuda/cuda_timer.cc:86] Delay kernel timed out: measured time has sub-optimal accuracy. There may be a missing warmup execution, please investigate in Nsight Systems.\n"
]
},
{
"name": "stdout",
"output_type": "stream",
"text": [
" 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",
"Test Accuracy (TTA 5x): 98.67%\n"
]
}
],
"source": [
"# Load model terbaik\n",
"print(f\"Loading best model from {checkpoint_path}...\")\n",
"best_model = tf.keras.models.load_model(checkpoint_path, compile=False)\n",
"\n",
"# Kumpulkan gambar test asli\n",
"raw_test_ds = tf.keras.utils.image_dataset_from_directory(\n",
" test_dir, shuffle=False, batch_size=BATCH_SIZE, image_size=IMG_SIZE)\n",
"\n",
"test_images = []\n",
"test_labels_true_raw = []\n",
"for images, labels in raw_test_ds.unbatch():\n",
" test_images.append(images.numpy())\n",
" test_labels_true_raw.append(labels.numpy())\n",
"\n",
"test_images = np.array(test_images)\n",
"test_labels_true = tf.one_hot(np.array(test_labels_true_raw), NUM_CLASSES).numpy()\n",
"\n",
"TTA_STEPS = 5\n",
"tta_predictions = []\n",
"\n",
"for i in range(TTA_STEPS):\n",
" aug_images = data_augmentation(test_images, training=True)\n",
" aug_images = preprocess_input(aug_images)\n",
" preds = best_model.predict(aug_images, batch_size=BATCH_SIZE, verbose=0)\n",
" tta_predictions.append(preds)\n",
" print(f\" TTA step {i+1}/{TTA_STEPS}\")\n",
"\n",
"mean_tta = np.mean(tta_predictions, axis=0)\n",
"\n",
"test_preds = np.argmax(mean_tta, axis=1)\n",
"test_true = np.argmax(test_labels_true, axis=1)\n",
"tta_acc = np.mean(test_preds == test_true)\n",
"\n",
"print(f\"\\nTest Accuracy (TTA {TTA_STEPS}x): {tta_acc*100:.2f}%\")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "0a86c96a",
"metadata": {},
"source": [
"## 14. Evaluasi — Classification Report & Confusion Matrix"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 26,
"id": "cfd7a17d",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"\n",
"Classification Report:\n",
"\n",
" precision recall f1-score support\n",
"\n",
" Bercak Daun 0.98 0.96 0.97 226\n",
" Daun Sehat 1.00 1.00 1.00 325\n",
" Hawar Daun 0.98 1.00 0.99 242\n",
" Karat Daun 0.98 0.99 0.99 259\n",
"\n",
" accuracy 0.99 1052\n",
" macro avg 0.99 0.99 0.99 1052\n",
"weighted avg 0.99 0.99 0.99 1052\n",
"\n"
]
},
{
"data": {
"image/png": "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
"text/plain": [
"<Figure size 1000x800 with 2 Axes>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"print(\"\\nClassification Report:\\n\")\n",
"print(classification_report(test_true, test_preds, target_names=class_names))\n",
"\n",
"cm = confusion_matrix(test_true, test_preds)\n",
"plt.figure(figsize=(10, 8))\n",
"sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',\n",
" xticklabels=class_names, yticklabels=class_names)\n",
"plt.title('Confusion Matrix', fontsize=14)\n",
"plt.xlabel('Predicted', fontsize=12)\n",
"plt.ylabel('True', fontsize=12)\n",
"plt.tight_layout()\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "0bda6bdb",
"metadata": {},
"source": [
"## 15. Simpan Model Akhir"
]
},
{
"cell_type": "code",
2026-06-11 19:42:02 +00:00
"execution_count": 27,
"id": "6059a3f9",
"metadata": {},
2026-06-11 19:42:02 +00:00
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Model saved to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras\n",
"Final model saved.\n"
]
}
],
"source": [
"# Simpan model training final (dengan EMA weights)\n",
"final_path = os.path.join(ckpt_dir, 'best_model.keras')\n",
"model.save(final_path)\n",
"print(f\"Model saved to {final_path}\")\n",
"\n",
"# Simpan juga versi tanpa EMA untuk fallback\n",
"model.save(os.path.join(ckpt_dir, 'final_model.keras'))\n",
"print(\"Final model saved.\")"
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "fced1ec4",
"metadata": {},
"source": [
"## 16. Export Model untuk Produksi\n",
"\n",
"Setelah training selesai, jalankan pipeline ekspor secara berurutan:\n",
"\n",
"### 1. SavedModel + TFLite\n",
"```bash\n",
"python save_model.py\n",
"```\n",
"Memuat `best_model/best_model.keras`, membangun arsitektur bersih (tanpa augmentasi), dan mengekspor ke:\n",
"- `model/saved_model/` — format produksi\n",
"- `model/model.tflite` — untuk perangkat mobile/edge\n",
"\n",
"### 2. ONNX (Rust ML Service)\n",
"```bash\n",
"python convert_onnx.py\n",
"```\n",
"Mengonversi SavedModel ke `model/model.onnx` untuk digunakan oleh Rust/Axum/ONNX Runtime.\n",
"\n",
"### 3. TensorFlow.js (Web)\n",
"```bash\n",
"export PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python\n",
"tensorflowjs_converter --input_format=tf_saved_model --output_format=tfjs_graph_model --signature_name=serving_default --saved_model_tags=serve model/saved_model model/tfjs_model\n",
"```\n",
"\n",
"> **Catatan**: Pipeline ekspor terpisah dari notebook karena `save_model.py` membangun ulang arsitektur tanpa layer training (GaussianNoise, augmentasi) untuk produksi."
]
},
{
"cell_type": "markdown",
2026-06-11 19:42:02 +00:00
"id": "32d6eac3",
"metadata": {},
"source": [
"## 17. Model Card — ZeaVis Edu Corn Disease Classifier\n",
"\n",
"| Atribut | Detail |\n",
"|---|---|\n",
"| **Nama Model** | ZeaVis Edu — EfficientNetV2B0 Classifier |\n",
"| **Versi** | 2.0 |\n",
"| **Arsitektur** | EfficientNetV2B0 (Transfer Learning) + GaussianNoise + Conv2D(512) + Conv2D(256) + Dense(1024) |\n",
"| **Framework** | TensorFlow 2.x / Keras (float32) |\n",
"| **Dataset** | ~6000-8000 gambar daun jagung (4 kelas) |\n",
"| **Kelas** | Bercak Daun, Hawar Daun, Karat Daun, Daun Sehat |\n",
"| **Input** | Gambar RGB 224×224 piksel |\n",
"| **Output** | Probabilitas per kelas (softmax) |\n",
"| **Augmentasi** | Flip, Rotation, Zoom, Translation, Contrast, Brightness, MixUp, CutMix, RandomErasing, GaussianNoise |\n",
"| **Optimizer** | AdamW + EMA + Label Smoothing 0.2 |\n",
"| **Training** | 3 fase: Head (lr=1e-3) → Partial FT (lr=1e-4) → Full FT (lr=5e-5) |\n",
"| **Target Akurasi** | ≥95% test accuracy |\n",
"| **Cara Pakai** | Upload gambar daun jagung → model memprediksi kelas penyakit |\n",
"| **Etika** | Model ini hanya untuk tujuan edukasi/penelitian pertanian. Jangan gunakan sebagai satu-satunya alat diagnosis. Konsultasi dengan ahli pertanian tetap diperlukan. |\n",
"\n",
"---\n",
"\n",
"© ZeaVis Edu — Proyek klasifikasi penyakit daun jagung"
]
2026-06-11 19:42:02 +00:00
},
{
"cell_type": "markdown",
"id": "790a7bab",
"metadata": {},
"source": [
"## 18. Upload ke Hugging Face\n",
"\n",
"Upload model, TFLite, ONNX, dan TF.js ke Hugging Face Hub repo `zeavis-edu/corn-leaf-disease-classifier`.\n",
"\n",
"**Persyaratan**: Token Hugging Face harus disetel sebagai environment variable `HF_TOKEN`.\n",
"- **Di Colab**: buka Secrets manager (ikon 🔑 di panel kiri), tambahkan secret dengan nama `HF_TOKEN` dan isi dengan token Anda, lalu aktifkan akses Notebook.\n",
"- **Di lokal**: `export HF_TOKEN=hf_...` atau simpan di `.env`.\n",
"\n",
"Jalankan cell berikut untuk memulai pipeline upload otomatis."
]
}
],
"metadata": {
"kernelspec": {
2026-06-11 16:39:04 +00:00
"display_name": ".venv",
"language": "python",
"name": "python3"
},
"language_info": {
2026-06-11 16:39:04 +00:00
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
2026-06-11 16:39:04 +00:00
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 5
}