2.1 MiB
2.1 MiB
In [1]:
!pip install -r requirements.txt
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) 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) Requirement already satisfied: gdown in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 3)) (6.1.0) Requirement already satisfied: kagglehub in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 4)) (1.0.2) Requirement already satisfied: numpy in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 5)) (2.1.3) Requirement already satisfied: matplotlib in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 6)) (3.10.9) Requirement already satisfied: seaborn in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 7)) (0.13.2) Requirement already satisfied: pillow in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 8)) (12.2.0) Requirement already satisfied: split-folders in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 9)) (0.6.1) Requirement already satisfied: scikit-learn in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 10)) (1.9.0) Requirement already satisfied: tf2onnx in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 11)) (1.17.0) Requirement already satisfied: onnxruntime in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 12)) (1.26.0) Requirement already satisfied: huggingface_hub in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from -r requirements.txt (line 13)) (1.19.0) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) Requirement already satisfied: kagglesdk<1.0,>=0.1.22 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from kagglehub->-r requirements.txt (line 4)) (0.1.29) Requirement already satisfied: pyyaml in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from kagglehub->-r requirements.txt (line 4)) (6.0.3) Requirement already satisfied: contourpy>=1.0.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (1.3.3) Requirement already satisfied: cycler>=0.10 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (0.12.1) Requirement already satisfied: fonttools>=4.22.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (4.63.0) Requirement already satisfied: kiwisolver>=1.3.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (1.5.0) Requirement already satisfied: pyparsing>=3 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (3.3.2) Requirement already satisfied: python-dateutil>=2.7 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from matplotlib->-r requirements.txt (line 6)) (2.9.0.post0) Requirement already satisfied: pandas>=1.2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from seaborn->-r requirements.txt (line 7)) (3.0.3) 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 10)) (1.17.1) 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 10)) (1.5.3) 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 10)) (2.22.1) 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 10)) (3.6.0) Requirement already satisfied: onnx>=1.14.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from tf2onnx->-r requirements.txt (line 11)) (1.21.0) Requirement already satisfied: click>=8.4.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from huggingface_hub->-r requirements.txt (line 13)) (8.4.1) Requirement already satisfied: fsspec>=2023.5.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from huggingface_hub->-r requirements.txt (line 13)) (2026.4.0) Requirement already satisfied: hf-xet<2.0.0,>=1.5.1 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from huggingface_hub->-r requirements.txt (line 13)) (1.5.1) Requirement already satisfied: httpx<1,>=0.23.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from huggingface_hub->-r requirements.txt (line 13)) (0.28.1) Requirement already satisfied: typer<0.26.0,>=0.20.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from huggingface_hub->-r requirements.txt (line 13)) (0.25.1) Requirement already satisfied: anyio in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from httpx<1,>=0.23.0->huggingface_hub->-r requirements.txt (line 13)) (4.13.0) Requirement already satisfied: httpcore==1.* in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from httpx<1,>=0.23.0->huggingface_hub->-r requirements.txt (line 13)) (1.0.9) Requirement already satisfied: h11>=0.16 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from httpcore==1.*->httpx<1,>=0.23.0->huggingface_hub->-r requirements.txt (line 13)) (0.16.0) Requirement already satisfied: shellingham>=1.3.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (1.5.4) Requirement already satisfied: rich>=13.8.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (15.0.0) Requirement already satisfied: annotated-doc>=0.0.2 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (0.0.4) 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) 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) 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) 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) 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) 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) 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) 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) Requirement already satisfied: markdown-it-py>=2.2.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from rich>=13.8.0->typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (4.2.0) Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages (from rich>=13.8.0->typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (2.20.0) 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>=13.8.0->typer<0.26.0,>=0.20.0->huggingface_hub->-r requirements.txt (line 13)) (0.1.2) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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) 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)
In [2]:
import os, shutil, zipfile, random, time, json
from collections import Counter
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from PIL import Image
import tensorflow as tf
from tensorflow.keras import layers, models, callbacks
from tensorflow.keras.applications import EfficientNetV2B0
from tensorflow.keras.applications.efficientnet_v2 import preprocess_input
from tensorflow.keras.optimizers import AdamW
from tensorflow.keras.optimizers.schedules import CosineDecay
from sklearn.metrics import classification_report, confusion_matrix
from sklearn.utils.class_weight import compute_class_weight
from sklearn.model_selection import train_test_split
# Optional: perceptual hashing for dedup (pip install imagehash)
try:
import imagehash
HAS_IMAGEHASH = True
except ImportError:
HAS_IMAGEHASH = False
# Optional: scipy for temperature optimization
try:
from scipy.optimize import minimize_scalar
HAS_SCIPY = True
except ImportError:
HAS_SCIPY = False
# Detect environment
try:
from google.colab import drive
IS_COLAB = True
print("Running on Google Colab")
except ModuleNotFoundError:
IS_COLAB = False
print(f"Running locally (TF {tf.__version__}, GPU: {tf.config.list_physical_devices('GPU')})")
tf.keras.mixed_precision.set_global_policy('float32')
# Hyperparams
IMG_SIZE = (224, 224)
BATCH_SIZE = 32
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
tf.random.set_seed(SEED)
AUTOTUNE = tf.data.AUTOTUNE
print(f"Setup OK. IMG={IMG_SIZE}, BATCH={BATCH_SIZE}")
2026-06-12 14:16:23.410032: E external/local_xla/xla/stream_executor/cuda/cuda_fft.cc:467] Unable to register cuFFT factory: Attempting to register factory for plugin cuFFT when one has already been registered WARNING: All log messages before absl::InitializeLog() is called are written to STDERR E0000 00:00:1781273783.433173 1198901 cuda_dnn.cc:8579] Unable to register cuDNN factory: Attempting to register factory for plugin cuDNN when one has already been registered E0000 00:00:1781273783.440756 1198901 cuda_blas.cc:1407] Unable to register cuBLAS factory: Attempting to register factory for plugin cuBLAS when one has already been registered W0000 00:00:1781273783.459729 1198901 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1781273783.459748 1198901 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1781273783.459750 1198901 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. W0000 00:00:1781273783.459752 1198901 computation_placer.cc:177] computation placer already registered. Please check linkage and avoid linking the same target more than once. 2026-06-12 14:16:23.465375: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations. To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.
Running locally (TF 2.19.0, GPU: [PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU')]) Setup OK. IMG=(224, 224), BATCH=32
In [3]:
if IS_COLAB:
drive.mount('/content/drive')
archive_path = '/content/drive/MyDrive/jagung/dataset.zip'
destination_path = '/content/dataset.zip'
extract_path = '/content/dataset'
else:
base = os.getcwd()
archive_path = os.path.join(base, 'dataset.zip')
destination_path = archive_path
extract_path = os.path.join(base, 'dataset')
if os.path.exists(destination_path):
if not os.path.exists(extract_path) or len(os.listdir(extract_path)) == 0:
os.makedirs(extract_path, exist_ok=True)
print("Extracting dataset...")
try:
with zipfile.ZipFile(destination_path, 'r') as zip_ref:
zip_ref.extractall(path=extract_path)
print("Extraction completed!")
except Exception as e:
print(f"Extraction failed: {e}")
else:
print("Dataset ready.")
else:
print(f"dataset.zip not found at {destination_path}. Upload dataset.zip to Google Drive / MyDrive/jagung/")
print("Or run preprocessing.py locally and upload the resulting dataset.zip")Dataset ready.
In [4]:
# --- Determine dataset path ---
dataset_path = extract_path
print(f"Dataset path: {dataset_path}")
# Check if dataset already validated and split exists — skip if so
split_output_dir = "/content/dataset_split" if IS_COLAB else os.path.join(os.getcwd(), "dataset_split")
if os.path.exists(os.path.join(split_output_dir, 'train')):
print("Split dataset already exists. Skipping validation and split.")
# Still need class_names and counts for downstream cells
train_dir = os.path.join(split_output_dir, 'train')
val_dir = os.path.join(split_output_dir, 'val')
test_dir = os.path.join(split_output_dir, 'test')
print(f'Train: {sum(len(files) for _, _, files in os.walk(train_dir))} | '
f'Val: {sum(len(files) for _, _, files in os.walk(val_dir))} | '
f'Test: {sum(len(files) for _, _, files in os.walk(test_dir))}')
else:
MIN_FILE_SIZE = 512
MIN_DIM = 32
MAX_ASPECT = 5.0
def remove_augmented_duplicates(directory):
removed = 0
for root, dirs, files in os.walk(directory):
for file in files:
if file.startswith("augmented_"):
try:
os.remove(os.path.join(root, file))
removed += 1
except OSError:
pass
return removed
def clean_and_validate_images(directory):
stats = {"too_small": 0, "corrupt": 0, "small_dims": 0, "extreme_aspect": 0, "low_var": 0, "ok": 0}
for root, dirs, files in os.walk(directory):
for file in files:
fp = os.path.join(root, file)
try:
if os.path.getsize(fp) < MIN_FILE_SIZE:
os.remove(fp); stats["too_small"] += 1; continue
except OSError:
continue
try:
img = Image.open(fp); img.verify()
except Exception:
try: os.remove(fp); stats["corrupt"] += 1
except OSError: pass
continue
try:
img = Image.open(fp)
w, h = img.size
if w < MIN_DIM or h < MIN_DIM:
os.remove(fp); stats["small_dims"] += 1; continue
aspect = w / max(h, 1)
if aspect > MAX_ASPECT or aspect < 1.0 / MAX_ASPECT:
os.remove(fp); stats["extreme_aspect"] += 1; continue
if img.mode not in ('RGB', 'RGBA'):
img = img.convert('RGB'); img.save(fp)
arr = np.array(img).astype(np.float32)
if np.std(arr) < 2.0:
os.remove(fp); stats["low_var"] += 1; continue
stats["ok"] += 1
except Exception:
try: os.remove(fp); stats["corrupt"] += 1
except OSError: pass
return stats
print("1. Removing augmented duplicates...")
n_aug = remove_augmented_duplicates(dataset_path)
print(f" Removed {n_aug} augmented_* files")
print("2. Validating images...")
stats = clean_and_validate_images(dataset_path)
print(f" OK: {stats['ok']} | Removed: too_small={stats['too_small']} corrupt={stats['corrupt']} "
f"small_dims={stats['small_dims']} aspect={stats['extreme_aspect']} low_var={stats['low_var']}")
if HAS_IMAGEHASH:
print("3. Perceptual hash dedup...")
seen, removed = {}, 0
for cn in sorted(os.listdir(dataset_path)):
cp = os.path.join(dataset_path, cn)
if not os.path.isdir(cp): continue
for f in sorted(os.listdir(cp)):
fp = os.path.join(cp, f)
if not os.path.isfile(fp): continue
try:
ah = imagehash.average_hash(Image.open(fp).convert('RGB'))
for sk, (sp, sc) in seen.items():
if ah - imagehash.hex_to_hash(sk) <= 5:
try: os.remove(fp); removed += 1
except OSError: pass
break
else:
seen[str(ah)] = (fp, cn)
except Exception:
pass
print(f" Removed {removed} near-duplicates")
else:
print("3. Perceptual hash dedup SKIPPED (pip install imagehash)")
total = sum(len(files) for _, _, files in os.walk(dataset_path))
print(f"\nTotal clean images: {total}")Dataset path: /home/asephs/ZeaVis-Edu/Machine_Learning/dataset Split dataset already exists. Skipping validation and split. Train: 3526 | Val: 754 | Test: 758
In [5]:
def extract_source_prefix(filename):
f = os.path.splitext(filename)[0]
if f.startswith('IMG_'): return 'phone'
if f.startswith('Corn_'): return 'lab_corn'
for prefix in ['CBS', 'GLS', 'NLS', 'CLS']:
if f.startswith(prefix): return 'lab_disease'
for prefix in ['SCR', 'CR', 'NLB', 'SLB', 'SRS']:
if f.startswith(prefix): return 'lab_rust_blight'
return 'other'
def stratified_split_by_source(dataset_path, output_dir, ratios=(0.7, 0.15, 0.15), seed=42):
class_images = {}
for cn in sorted(os.listdir(dataset_path)):
cp = os.path.join(dataset_path, cn)
if not os.path.isdir(cp): continue
class_images[cn] = []
for f in os.listdir(cp):
fp = os.path.join(cp, f)
if os.path.isfile(fp):
class_images[cn].append((fp, f, extract_source_prefix(f)))
for split in ['train', 'val', 'test']:
for cn in class_images:
os.makedirs(os.path.join(output_dir, split, cn), exist_ok=True)
rng = np.random.RandomState(seed)
for cn, images in class_images.items():
by_source = {}
for fp, fn, src in images:
by_source.setdefault(src, []).append((fp, fn))
train_files, val_files, test_files = [], [], []
for src, src_images in by_source.items():
n = len(src_images)
rng.shuffle(src_images)
n_train = max(1, int(n * ratios[0]))
n_val = max(1, int(n * ratios[1]))
train_files.extend(src_images[:n_train])
val_files.extend(src_images[n_train:n_train + n_val])
test_files.extend(src_images[n_train + n_val:])
for fp, fn in train_files:
shutil.copy(fp, os.path.join(output_dir, 'train', cn, fn))
for fp, fn in val_files:
shutil.copy(fp, os.path.join(output_dir, 'val', cn, fn))
for fp, fn in test_files:
shutil.copy(fp, os.path.join(output_dir, 'test', cn, fn))
train_srcs = Counter(extract_source_prefix(fn) for _, fn in train_files)
print(f" {cn}: train={len(train_files)} val={len(val_files)} test={len(test_files)} | "
f"sources={dict(train_srcs)}")
output_dir = split_output_dir # Already defined in previous cell
if os.path.exists(os.path.join(output_dir, 'train')):
print("Split already exists. Skipping.")
else:
if os.path.exists(output_dir):
shutil.rmtree(output_dir)
print("Splitting dataset 70:15:15 (stratified by source)...")
stratified_split_by_source(dataset_path, output_dir, seed=SEED)
print("Done.")
train_dir = os.path.join(output_dir, 'train')
val_dir = os.path.join(output_dir, 'val')
test_dir = os.path.join(output_dir, 'test')
def count_images(path):
return sum(len(files) for _, _, files in os.walk(path))
print(f'Train: {count_images(train_dir)} | Val: {count_images(val_dir)} | Test: {count_images(test_dir)}')Split already exists. Skipping. Train: 3526 | Val: 754 | Test: 758
In [6]:
# ─── RandAugment Utilities ───
def sample_beta_distribution(size, a=0.2, b=0.2):
g1 = tf.random.gamma([size], a, dtype=tf.float32)
g2 = tf.random.gamma([size], b, dtype=tf.float32)
return g2 / (g1 + g2 + 1e-8)
def _apply_contrast(img, factor):
mean = tf.reduce_mean(tf.cast(img, tf.float32), axis=(0, 1), keepdims=True)
return mean + factor * (tf.cast(img, tf.float32) - mean)
def _apply_brightness(img, delta):
return tf.clip_by_value(tf.cast(img, tf.float32) + delta, 0.0, 255.0)
def _apply_hue(img, delta):
hsv = tf.image.rgb_to_hsv(tf.cast(img, tf.float32) / 255.0)
h = hsv[..., 0] + delta
h = h - tf.floor(h)
hsv_h = tf.stack([h, hsv[..., 1], hsv[..., 2]], axis=-1)
return tf.image.hsv_to_rgb(hsv_h) * 255.0
@tf.function(reduce_retracing=True)
def _randaug_select(images, ops_per_image=3, magnitude=0.7):
# Graph-mode-safe RandAugment. No tf.image.random_* or Keras layers
# (both trace as Python bool checks on tensor bounds internally).
def _zoom(img):
h = tf.cast(tf.shape(img)[0], tf.float32)
w = tf.cast(tf.shape(img)[1], tf.float32)
z = tf.random.uniform([], 1.0 - 0.2 * magnitude, 1.0 + 0.2 * magnitude)
zh = tf.cast(h / z, tf.int32); zw = tf.cast(w / z, tf.int32)
zoomed = tf.image.resize(tf.expand_dims(img, 0), [zh, zw], method='bilinear')[0]
return tf.image.resize_with_crop_or_pad(zoomed, tf.cast(h, tf.int32), tf.cast(w, tf.int32))
def _translate(img):
h, w = tf.shape(img)[0], tf.shape(img)[1]
tx = tf.cast(tf.random.uniform([], -0.15 * magnitude, 0.15 * magnitude) * tf.cast(w, tf.float32), tf.int32)
ty = tf.cast(tf.random.uniform([], -0.15 * magnitude, 0.15 * magnitude) * tf.cast(h, tf.float32), tf.int32)
return tf.roll(img, [ty, tx], axis=[0, 1])
def op_flip(img): return tf.image.random_flip_left_right(img)
def op_flip_v(img): return tf.image.random_flip_up_down(img)
def op_rotate_90(img):
k = tf.random.uniform([], 0, 4, dtype=tf.int32)
return tf.image.rot90(img, k)
def op_zoom(img): return _zoom(img)
def op_translate(img): return _translate(img)
def op_contrast(img):
f = tf.random.uniform([], 1.0 - 0.5 * magnitude, 1.0 + 0.5 * magnitude)
return _apply_contrast(img, f)
def op_brightness(img):
d = tf.random.uniform([], -0.3 * magnitude * 255.0, 0.3 * magnitude * 255.0)
return _apply_brightness(img, d)
def op_hue(img):
d = tf.random.uniform([], -0.08 * tf.maximum(magnitude, 0.01), 0.08 * tf.maximum(magnitude, 0.01))
return _apply_hue(img, d)
def op_saturation(img):
lo = tf.maximum(0.5, 1.0 - 0.8 * magnitude)
hi = 1.0 + 0.8 * magnitude
f = tf.random.uniform([], lo, hi)
hsv = tf.image.rgb_to_hsv(tf.cast(img, tf.float32) / 255.0)
s = tf.clip_by_value(hsv[..., 1] * f, 0.0, 1.0)
return tf.image.hsv_to_rgb(tf.stack([hsv[..., 0], s, hsv[..., 2]], axis=-1)) * 255.0
def op_solarize(img):
thresh = tf.random.uniform([], 0.3, 0.8) * 255.0
f = tf.cast(img, tf.float32)
return tf.where(f < thresh, f, 255.0 - f)
def op_blur(img):
h, w = tf.shape(img)[0], tf.shape(img)[1]
sf = tf.random.uniform([], 2, 4, dtype=tf.int32)
small = tf.image.resize(tf.expand_dims(tf.cast(img, tf.float32), 0), [h // sf, w // sf], method='bilinear')
return tf.image.resize(small, [h, w], method='bilinear')[0]
def op_fog(img):
fl = tf.random.uniform([], 0.1, 0.1 + 0.4 * magnitude)
fc = tf.random.uniform([3], 0.7, 1.0) * 255.0
return tf.cast(img, tf.float32) * (1.0 - fl) + tf.reshape(fc, [1, 1, 3]) * fl
def op_shadow(img):
op = tf.random.uniform([], 0.2, 0.2 + 0.5 * magnitude)
return tf.cast(img, tf.float32) * (1.0 - op * 0.6)
def op_resolution_drop(img):
h, w = tf.shape(img)[0], tf.shape(img)[1]
sf = tf.random.uniform([], 2, 5, dtype=tf.int32)
small = tf.image.resize(tf.expand_dims(tf.cast(img, tf.float32), 0), [h // sf, w // sf], method='bilinear')
return tf.image.resize(small, [h, w], method='nearest')[0]
def op_identity(img): return tf.cast(img, tf.float32)
ops = [op_flip, op_flip_v, op_rotate_90, op_zoom, op_translate,
op_contrast, op_brightness, op_hue, op_saturation,
op_solarize, op_blur, op_fog, op_shadow, op_resolution_drop, op_identity]
def apply_randaug_single(img3d):
indices = tf.random.shuffle(tf.range(15))[:3] # ops_per_image=3, static
result = tf.cast(img3d, tf.float32)
# Unrolled static 3 iterations — avoids TF shape invariance error from tf.range loop
def _apply_one(r, idx):
return tf.switch_case(idx, {j: lambda j=j: ops[j](r) for j in range(15)})
i0, i1, i2 = indices[0], indices[1], indices[2]
result = _apply_one(result, i0)
result = _apply_one(result, i1)
result = _apply_one(result, i2)
return tf.clip_by_value(result, 0.0, 255.0)
return tf.map_fn(apply_randaug_single, images, dtype=tf.float32, parallel_iterations=8)
# Compatibility wrapper using Keras Sequential for basic geometric ops (kept for visualization)
geo_aug = tf.keras.Sequential([
layers.RandomFlip("horizontal_and_vertical"),
layers.RandomRotation(0.15),
layers.RandomZoom(0.15),
layers.RandomTranslation(0.1, 0.1),
layers.RandomContrast(0.15),
layers.RandomBrightness(0.15),
], name="geo_aug")
# ─── MixUp & CutMix (unchanged from original) ───
def mix_up(images, labels, alpha=0.2):
bs = tf.shape(images)[0]
lam = sample_beta_distribution(bs, alpha, alpha)
lam_img = tf.reshape(lam, [bs, 1, 1, 1])
ri = tf.random.shuffle(tf.range(bs))
mixed_img = lam_img * images + (1 - lam_img) * tf.gather(images, ri)
labels = tf.cast(labels, tf.float32)
lam_lbl = tf.reshape(lam, [-1, 1])
mixed_lbl = lam_lbl * labels + (1 - lam_lbl) * tf.gather(labels, ri)
return mixed_img, mixed_lbl
def cut_mix(images, labels, alpha=0.2):
bs = tf.shape(images)[0]; h = tf.shape(images)[1]; w = tf.shape(images)[2]
lam = sample_beta_distribution(bs, alpha, alpha); ri = tf.random.shuffle(tf.range(bs))
cr = tf.sqrt(1.0 - lam)
rh = tf.cast(cr * tf.cast(h, tf.float32), tf.int32); rw = tf.cast(cr * tf.cast(w, tf.float32), tf.int32)
cx = tf.random.uniform([bs], 0, w, tf.int32); cy = tf.random.uniform([bs], 0, h, tf.int32)
hh = rh // 2; hw = rw // 2
x1 = tf.clip_by_value(cx - hw, 0, w); x2 = tf.clip_by_value(cx + hw, 0, w)
y1 = tf.clip_by_value(cy - hh, 0, h); y2 = tf.clip_by_value(cy + hh, 0, h)
col = tf.range(w, dtype=tf.int32); row = tf.range(h, dtype=tf.int32)
in_x = tf.logical_and(tf.reshape(col, [1, 1, w]) >= tf.reshape(x1, [bs, 1, 1]),
tf.reshape(col, [1, 1, w]) < tf.reshape(x2, [bs, 1, 1]))
in_y = tf.logical_and(tf.reshape(row, [1, h, 1]) >= tf.reshape(y1, [bs, 1, 1]),
tf.reshape(row, [1, h, 1]) < tf.reshape(y2, [bs, 1, 1]))
cm = tf.cast(tf.logical_and(in_y, in_x), tf.float32); cm = tf.expand_dims(cm, -1)
shuf = tf.gather(images, ri)
mi = (1.0 - cm) * images + cm * shuf
labels = tf.cast(labels, tf.float32); lr = tf.reshape(lam, [-1, 1])
ml = lr * labels + (1.0 - lr) * tf.gather(labels, ri)
return mi, ml
def random_erasing(images, probability=0.25, scale=(0.02, 0.25)):
bs = tf.shape(images)[0]; h = tf.shape(images)[1]; w = tf.shape(images)[2]
ta = tf.random.uniform([], scale[0], scale[1]) * tf.cast(h * w, tf.float32)
ar = tf.random.uniform([], 0.3, 3.3)
eh = tf.cast(tf.math.sqrt(ta / ar), tf.int32); ew = tf.cast(tf.math.sqrt(ta * ar), tf.int32)
eh = tf.clip_by_value(eh, 1, h - 1); ew = tf.clip_by_value(ew, 1, w - 1)
cx = tf.random.uniform([], 0, w - ew, tf.int32); cy = tf.random.uniform([], 0, h - eh, tf.int32)
col = tf.range(w, dtype=tf.int32); row = tf.range(h, dtype=tf.int32)
ix = tf.logical_and(col >= cx, col < cx + ew)
iy = tf.logical_and(row >= cy, row < cy + eh)
em = tf.cast(tf.expand_dims(iy, 1) & tf.expand_dims(ix, 0), tf.float32)
em = tf.expand_dims(tf.expand_dims(em, 0), -1)
noise = tf.random.uniform([bs, eh, ew, 3], 0.0, 255.0, dtype=tf.float32)
pads = [[0, 0], [cy, h - (cy + eh)], [cx, w - (cx + ew)], [0, 0]]
npad = tf.pad(noise, pads, constant_values=0.0)
erased = images * (1.0 - em) + npad * em
return tf.cond(tf.random.uniform([]) < probability, lambda: erased, lambda: images)
# ─── Main augmentation pipeline ───
def augment_and_mix(images, labels):
# 1. RandAugment (geometric + color + weather + degradation)
images = tf.cast(images, tf.float32)
images = _randaug_select(images, ops_per_image=3, magnitude=0.7)
# 2. MixUp or CutMix (40% chance total: 20% MixUp, 20% CutMix)
choice = tf.random.uniform([])
labels_oh = tf.one_hot(labels, NUM_CLASSES)
images, labels_oh = tf.cond(
choice < 0.2, lambda: mix_up(images, labels_oh),
lambda: tf.cond(choice < 0.4, lambda: cut_mix(images, labels_oh),
lambda: (images, labels_oh)))
# 3. Random Erasing
images = random_erasing(images, probability=0.2)
return images, labels_oh
# ─── Preprocessing ───
def preprocess_fn(image, label):
return preprocess_input(image), label
# ─── Class weights ───
train_class_counts = Counter()
for cn in sorted(os.listdir(train_dir)):
p = os.path.join(train_dir, cn)
if os.path.isdir(p):
train_class_counts[cn] = len(os.listdir(p))
y_int = []
for i, cn in enumerate(sorted(os.listdir(train_dir))):
cp = os.path.join(train_dir, cn)
if os.path.isdir(cp):
y_int.extend([i] * len(os.listdir(cp)))
cw_array = compute_class_weight('balanced', classes=np.unique(y_int), y=y_int)
cw_capped = [min(w, 3.0) for w in cw_array]
class_weights_tensor = tf.constant(cw_capped, dtype=tf.float32)
def add_sample_weight(image, label):
ci = tf.argmax(label, axis=-1)
sw = tf.gather(class_weights_tensor, ci)
return image, label, sw
# ─── Build datasets ───
train_ds = tf.keras.utils.image_dataset_from_directory(
train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
val_ds = tf.keras.utils.image_dataset_from_directory(
val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
test_ds = tf.keras.utils.image_dataset_from_directory(
test_dir, shuffle=False, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
class_names = train_ds.class_names
NUM_CLASSES = len(class_names)
print(f"Classes ({NUM_CLASSES}): {class_names}")
train_ds = (train_ds
.map(augment_and_mix, num_parallel_calls=AUTOTUNE)
.map(preprocess_fn, num_parallel_calls=AUTOTUNE)
.map(add_sample_weight, num_parallel_calls=AUTOTUNE)
.prefetch(AUTOTUNE))
val_ds = (val_ds
.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)
.map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE)
.prefetch(AUTOTUNE))
test_ds = (test_ds
.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)
.map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE)
.prefetch(AUTOTUNE))
print("Class weights (capped at 3.0):")
for i, cn in enumerate(class_names):
if i < len(cw_capped):
print(f" {cn}: {cw_capped[i]:.4f}")
print("Data pipelines ready.")
Found 3526 files belonging to 4 classes.
I0000 00:00:1781273786.135481 1198901 gpu_device.cc:2019] Created device /job:localhost/replica:0/task:0/device:GPU:0 with 37480 MB memory: -> device: 0, name: NVIDIA A100-SXM4-40GB, pci bus id: 0000:05:00.0, compute capability: 8.0
Found 754 files belonging to 4 classes. Found 758 files belonging to 4 classes. Classes (4): ['Bercak Daun', 'Daun Sehat', 'Hawar Daun', 'Karat Daun'] WARNING:tensorflow:From /home/asephs/ZeaVis-Edu/.venv/lib/python3.12/site-packages/tensorflow/python/util/deprecation.py:660: calling map_fn_v2 (from tensorflow.python.ops.map_fn) with dtype is deprecated and will be removed in a future version. Instructions for updating: Use fn_output_signature instead Class weights (capped at 3.0): Bercak Daun: 2.1983 Daun Sehat: 0.5826 Hawar Daun: 1.2593 Karat Daun: 0.9666 Data pipelines ready.
In [7]:
vis_ds = tf.keras.utils.image_dataset_from_directory(
train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
plt.figure(figsize=(16, 10))
for images, labels in vis_ds.take(1):
# Original (4)
for i in range(4):
plt.subplot(3, 4, i + 1)
plt.imshow(images[i].numpy().astype("uint8"))
plt.title(f"Asli: {class_names[labels[i].numpy()]}", fontsize=11)
plt.axis("off")
# RandAugment (4)
aug = _randaug_select(tf.cast(images, tf.float32), ops_per_image=3, magnitude=0.7)
for i in range(4):
plt.subplot(3, 4, i + 5)
plt.imshow(tf.clip_by_value(aug[i], 0, 255).numpy().astype("uint8"))
plt.title(f"RandAug: {class_names[labels[i].numpy()]}", fontsize=11)
plt.axis("off")
# MixUp result (4)
aug_f = tf.cast(images, tf.float32)
mixed, _ = mix_up(aug_f, tf.one_hot(labels, NUM_CLASSES))
for i in range(4):
plt.subplot(3, 4, i + 9)
plt.imshow(tf.clip_by_value(mixed[i], 0, 255).numpy().astype("uint8"))
plt.title("MixUp/Weather", fontsize=11)
plt.axis("off")
plt.suptitle("RandAugment + MixUp — Real-World Simulation", fontsize=16)
plt.tight_layout()
plt.show()
Found 3526 files belonging to 4 classes.
2026-06-12 14:16:33.570217: I tensorflow/core/framework/local_rendezvous.cc:407] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence
In [ ]:
def cbam_block(x, ratio=8, name="cbam"):
# Convolutional Block Attention Module — ringan, fokus ke foreground.
channels = x.shape[-1]
# Channel Attention
avg_pool = layers.GlobalAveragePooling2D()(x)
max_pool = layers.GlobalMaxPooling2D()(x)
ca = layers.Dense(channels // ratio, activation='swish', name=f"{name}_ca1")(avg_pool)
ca = layers.Dense(channels, activation='sigmoid', name=f"{name}_ca2")(ca)
ca2 = layers.Dense(channels // ratio, activation='swish', name=f"{name}_ca3")(max_pool)
ca2 = layers.Dense(channels, activation='sigmoid', name=f"{name}_ca4")(ca2)
ca_out = layers.Add(name=f"{name}_ca_add")([ca, ca2])
ca_out = layers.Reshape((1, 1, channels), name=f"{name}_ca_reshape")(ca_out)
x = layers.Multiply(name=f"{name}_ca_mul")([x, ca_out])
# Spatial Attention — output_shape required for Keras 3 serialization
avg_sp = layers.Lambda(
lambda t: tf.reduce_mean(t, axis=-1, keepdims=True),
output_shape=lambda s: s[:-1] + (1,),
name=f"{name}_sa_avg",
)(x)
max_sp = layers.Lambda(
lambda t: tf.reduce_max(t, axis=-1, keepdims=True),
output_shape=lambda s: s[:-1] + (1,),
name=f"{name}_sa_max",
)(x)
sp = layers.Concatenate(name=f"{name}_sa_cat")([avg_sp, max_sp])
sp = layers.Conv2D(1, 7, padding='same', activation='sigmoid', name=f"{name}_sa_conv")(sp)
x = layers.Multiply(name=f"{name}_sa_mul")([x, sp])
return x
def build_model(num_classes, target_size=(224, 224)):
# Accept any input size via variable input; Resizing handles progressive resolution.
inputs = tf.keras.Input(shape=(None, None, 3), name="input")
x = layers.Resizing(target_size[0], target_size[1], interpolation='bilinear',
name="resize_input")(inputs)
base_model = EfficientNetV2B0(
input_shape=target_size + (3,),
include_top=False,
weights='imagenet',
)
base_model.trainable = False
# Gaussian noise untuk regularisasi
x = layers.GaussianNoise(0.05, name="gauss_noise")(x)
x = base_model(x, training=False)
# CBAM attention — fokus ke region daun
x = cbam_block(x, ratio=8, name="cbam")
x = layers.GlobalAveragePooling2D(name="gap")(x)
x = layers.Dropout(0.3, name="drop_gap")(x)
x = layers.Dense(512, activation='swish', name="dense_head")(x)
x = layers.BatchNormalization(name="bn_head")(x)
x = layers.Dropout(0.4, name="drop_head")(x)
outputs = layers.Dense(num_classes, activation='linear', dtype='float32', name="logits")(x)
return models.Model(inputs, outputs), base_model
# Checkpoint
ckpt_dir = '/content/best_model' if IS_COLAB else os.path.join(os.getcwd(), 'best_model')
checkpoint_path = os.path.join(ckpt_dir, 'best_model.keras')
# Hapus checkpoint lama (arsitektur berbeda — tidak kompatibel)
if os.path.exists(checkpoint_path):
print(f"Removing old checkpoint (incompatible architecture)...")
os.remove(checkpoint_path)
if os.path.exists(checkpoint_path):
print(f"Loading checkpoint: {checkpoint_path}")
try:
model = models.load_model(checkpoint_path, compile=False)
except Exception as e:
print(f"Load failed: {e}. Building fresh.")
model, base_model = build_model(NUM_CLASSES)
else:
print("No checkpoint. Building fresh model.")
model, base_model = build_model(NUM_CLASSES)
os.makedirs(ckpt_dir, exist_ok=True)
model.summary()In [9]:
class WarmupCosineDecay(tf.keras.optimizers.schedules.LearningRateSchedule):
# Cosine decay with linear warmup.
def __init__(self, warmup_steps, total_steps, peak_lr, min_lr=1e-7):
super().__init__()
self.warmup_steps = warmup_steps
self.total_steps = total_steps
self.peak_lr = peak_lr
self.min_lr = min_lr
def __call__(self, step):
step = tf.cast(step, tf.float32)
warmup_steps = tf.cast(self.warmup_steps, tf.float32)
total_steps = tf.cast(self.total_steps, tf.float32)
# Warmup phase
warmup_lr = self.peak_lr * (step / warmup_steps)
# Cosine decay phase
progress = (step - warmup_steps) / tf.maximum(total_steps - warmup_steps, 1.0)
cosine_lr = self.min_lr + 0.5 * (self.peak_lr - self.min_lr) * (1.0 + tf.cos(np.pi * progress))
return tf.where(step < warmup_steps, warmup_lr, cosine_lr)
def get_config(self):
return {
"warmup_steps": self.warmup_steps, "total_steps": self.total_steps,
"peak_lr": self.peak_lr, "min_lr": self.min_lr,
}
class SWACallback(tf.keras.callbacks.Callback):
# Stochastic Weight Averaging — averages weights over final epochs.
def __init__(self, start_epoch, swa_lr=1e-5):
super().__init__()
self.start_epoch = start_epoch
self.swa_lr = swa_lr
self.swa_weights = None
self.n_models = 0
def on_epoch_begin(self, epoch, logs=None):
if epoch >= self.start_epoch and self.swa_weights is None:
self.swa_weights = [w.numpy() for w in self.model.weights]
print(f"\nSWA: starting weight averaging at epoch {epoch+1}")
def on_epoch_end(self, epoch, logs=None):
if epoch >= self.start_epoch and self.swa_weights is not None:
for i, w in enumerate(self.model.weights):
self.swa_weights[i] = (self.swa_weights[i] * self.n_models + w.numpy()) / (self.n_models + 1)
self.n_models += 1
def apply_swa_weights(self):
if self.swa_weights is None:
print("SWA: no weights to average (skipped)")
return
for w, swa_w in zip(self.model.weights, self.swa_weights):
w.assign(swa_w)
print(f"SWA weights applied ({self.n_models} models averaged).")
# Shared callbacks
checkpoint_cb = callbacks.ModelCheckpoint(
checkpoint_path, save_best_only=True, monitor="val_accuracy",
mode="max", verbose=1)
csv_logger = callbacks.CSVLogger(os.path.join(ckpt_dir, 'training_log.csv'))
def make_callbacks(swa_start=None):
cbs = [checkpoint_cb, csv_logger]
if swa_start is not None:
cbs.append(SWACallback(swa_start))
return cbs
print("Callbacks ready.")
print(f"Checkpoint path: {checkpoint_path}")
Callbacks ready. Checkpoint path: /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras
In [10]:
IMG_128 = (128, 128)
# Rebuild datasets at 128x128
train_ds_128 = tf.keras.utils.image_dataset_from_directory(
train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)
val_ds_128 = tf.keras.utils.image_dataset_from_directory(
val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)
train_ds_128 = (train_ds_128.map(augment_and_mix, num_parallel_calls=AUTOTUNE)
.map(preprocess_fn, num_parallel_calls=AUTOTUNE)
.map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
val_ds_128 = (val_ds_128.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)
.map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
EPOCHS_P1 = 25
card = tf.data.experimental.cardinality(train_ds_128).numpy()
steps_per_epoch = card if card > 0 else 100
total_steps = steps_per_epoch * EPOCHS_P1
warmup_steps = steps_per_epoch * 3 # 3 epoch warmup
lr_schedule_p1 = WarmupCosineDecay(warmup_steps, total_steps, peak_lr=1e-3, min_lr=1e-5)
model.compile(
optimizer=AdamW(
learning_rate=lr_schedule_p1, weight_decay=1e-4),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),
metrics=['accuracy']
)
print("Phase 1: Head training at 128×128...")
history_1 = model.fit(train_ds_128, validation_data=val_ds_128,
epochs=EPOCHS_P1, callbacks=make_callbacks())Found 3526 files belonging to 4 classes.
Found 754 files belonging to 4 classes.
Phase 1: Head training at 128×128...
Epoch 1/25
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR I0000 00:00:1781273809.189453 1199382 service.cc:152] XLA service 0x757cd4001ab0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices: I0000 00:00:1781273809.189482 1199382 service.cc:160] StreamExecutor device (0): NVIDIA A100-SXM4-40GB, Compute Capability 8.0 2026-06-12 14:16:50.547970: I tensorflow/compiler/mlir/tensorflow/utils/dump_mlir_util.cc:269] disabling MLIR crash reproducer, set env var `MLIR_CRASH_REPRODUCER_DIRECTORY` to enable. I0000 00:00:1781273813.442292 1199382 cuda_dnn.cc:529] Loaded cuDNN version 92301 2026-06-12 14:16:56.177029: 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_9080', 12 bytes spill stores, 12 bytes spill loads 2026-06-12 14:16:56.187342: 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_9080', 232 bytes spill stores, 232 bytes spill loads 2026-06-12 14:16:56.224294: 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_9080_0', 428 bytes spill stores, 1360 bytes spill loads 2026-06-12 14:16:56.985744: 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_9080', 5372 bytes spill stores, 5348 bytes spill loads 2026-06-12 14:16:57.807703: 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_9080', 6000 bytes spill stores, 5952 bytes spill loads 2026-06-12 14:17:00.117091: 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. 2026-06-12 14:17:00.273419: 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. 2026-06-12 14:17:01.074555: 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. 2026-06-12 14:17:01.238208: 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. 2026-06-12 14:17:01.856060: 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. 2026-06-12 14:17:02.007414: 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. 2026-06-12 14:17:02.380303: 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. 2026-06-12 14:17:02.547537: 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. 2026-06-12 14:17:03.217188: 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. 2026-06-12 14:17:03.384704: 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. 2026-06-12 14:17:03.827983: 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. 2026-06-12 14:17:03.984354: 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. 2026-06-12 14:17:04.179865: 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. 2026-06-12 14:17:04.337508: 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.
[1m 11/111[0m [32m━[0m[37m━━━━━━━━━━━━━━━━━━━[0m [1m1s[0m 12ms/step - accuracy: 0.2155 - loss: 2.4408
I0000 00:00:1781273833.778844 1199382 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.
[1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 46ms/step - accuracy: 0.4442 - loss: 1.7988
2026-06-12 14:17:23.251739: 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_9080', 156 bytes spill stores, 156 bytes spill loads 2026-06-12 14:17:23.700939: 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_9080', 5100 bytes spill stores, 5108 bytes spill loads 2026-06-12 14:17:24.225262: 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_9080', 4500 bytes spill stores, 4492 bytes spill loads 2026-06-12 14:17:25.737787: 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. 2026-06-12 14:17:25.891964: 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. 2026-06-12 14:17:26.674550: 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. 2026-06-12 14:17:26.835098: 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. 2026-06-12 14:17:27.310738: 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. 2026-06-12 14:17:27.461542: 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.
[1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 209ms/step - accuracy: 0.4475 - loss: 1.7909
2026-06-12 14:17:42.009559: 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_2591', 232 bytes spill stores, 232 bytes spill loads 2026-06-12 14:17:42.164736: 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_2591_0', 496 bytes spill stores, 1400 bytes spill loads 2026-06-12 14:17:42.197096: 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_2591', 12 bytes spill stores, 12 bytes spill loads 2026-06-12 14:17:42.810303: 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_2591', 6000 bytes spill stores, 5952 bytes spill loads 2026-06-12 14:17:43.028755: 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_2591', 5372 bytes spill stores, 5348 bytes spill loads 2026-06-12 14:17:47.498104: 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_2484', 252 bytes spill stores, 252 bytes spill loads 2026-06-12 14:17:47.518030: 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_2484', 16 bytes spill stores, 16 bytes spill loads 2026-06-12 14:17:47.830502: 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_2591', 252 bytes spill stores, 252 bytes spill loads 2026-06-12 14:17:47.831081: 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_2591_0', 492 bytes spill stores, 1464 bytes spill loads 2026-06-12 14:17:47.902990: 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_2591', 16 bytes spill stores, 16 bytes spill loads 2026-06-12 14:17:48.086926: 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_2484', 5912 bytes spill stores, 5980 bytes spill loads 2026-06-12 14:17:48.392613: 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_2484', 5356 bytes spill stores, 5344 bytes spill loads 2026-06-12 14:17:48.398217: 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_2591', 5356 bytes spill stores, 5344 bytes spill loads 2026-06-12 14:17:48.749904: 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_2591', 5912 bytes spill stores, 5980 bytes spill loads 2026-06-12 14:17:50.146437: 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. 2026-06-12 14:17:50.302796: 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. 2026-06-12 14:17:51.093951: 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. 2026-06-12 14:17:51.257390: 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. 2026-06-12 14:17:51.861787: 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. 2026-06-12 14:17:52.013103: 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. 2026-06-12 14:17:52.381425: 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. 2026-06-12 14:17:52.548282: 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. 2026-06-12 14:17:53.461750: 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. 2026-06-12 14:17:53.617936: 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. 2026-06-12 14:17:53.814377: 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. 2026-06-12 14:17:53.972623: 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.
Epoch 1: val_accuracy improved from None to 0.97215, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 1: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m80s[0m 400ms/step - accuracy: 0.6322 - loss: 1.3592 - val_accuracy: 0.9721 - val_loss: 0.8272 Epoch 2/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 70ms/step - accuracy: 0.8167 - loss: 0.9964 Epoch 2: val_accuracy improved from 0.97215 to 0.98276, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 2: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 100ms/step - accuracy: 0.8267 - loss: 0.9727 - val_accuracy: 0.9828 - val_loss: 0.7051 Epoch 3/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 73ms/step - accuracy: 0.8284 - loss: 0.9292 Epoch 3: val_accuracy did not improve from 0.98276 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 96ms/step - accuracy: 0.8542 - loss: 0.8379 - val_accuracy: 0.7599 - val_loss: 1.0449 Epoch 4/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 74ms/step - accuracy: 0.8979 - loss: 0.7535 Epoch 4: val_accuracy did not improve from 0.98276 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 95ms/step - accuracy: 0.9058 - loss: 0.7323 - val_accuracy: 0.9668 - val_loss: 0.8505 Epoch 5/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 75ms/step - accuracy: 0.9256 - loss: 0.7010 Epoch 5: val_accuracy did not improve from 0.98276 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 98ms/step - accuracy: 0.9280 - loss: 0.6952 - val_accuracy: 0.9814 - val_loss: 0.6596 Epoch 6/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 72ms/step - accuracy: 0.9273 - loss: 0.6984 Epoch 6: val_accuracy improved from 0.98276 to 0.98806, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 6: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 105ms/step - accuracy: 0.9348 - loss: 0.6864 - val_accuracy: 0.9881 - val_loss: 0.5717 Epoch 7/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 75ms/step - accuracy: 0.9340 - loss: 0.6884 Epoch 7: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 98ms/step - accuracy: 0.9317 - loss: 0.6804 - val_accuracy: 0.9867 - val_loss: 0.5296 Epoch 8/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 69ms/step - accuracy: 0.9318 - loss: 0.6772 Epoch 8: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 92ms/step - accuracy: 0.9305 - loss: 0.6687 - val_accuracy: 0.9854 - val_loss: 0.5359 Epoch 9/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 74ms/step - accuracy: 0.9356 - loss: 0.6738 Epoch 9: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 97ms/step - accuracy: 0.9393 - loss: 0.6683 - val_accuracy: 0.9841 - val_loss: 0.5261 Epoch 10/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 73ms/step - accuracy: 0.9334 - loss: 0.6756 Epoch 10: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 96ms/step - accuracy: 0.9348 - loss: 0.6637 - val_accuracy: 0.9867 - val_loss: 0.5263 Epoch 11/25 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 67ms/step - accuracy: 0.9426 - loss: 0.6642 Epoch 11: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 90ms/step - accuracy: 0.9433 - loss: 0.6501 - val_accuracy: 0.9854 - val_loss: 0.5230 Epoch 12/25 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 66ms/step - accuracy: 0.9521 - loss: 0.6532 Epoch 12: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 91ms/step - accuracy: 0.9472 - loss: 0.6467 - val_accuracy: 0.9867 - val_loss: 0.5194 Epoch 13/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 66ms/step - accuracy: 0.9477 - loss: 0.6544 Epoch 13: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 89ms/step - accuracy: 0.9475 - loss: 0.6505 - val_accuracy: 0.9841 - val_loss: 0.5208 Epoch 14/25 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 76ms/step - accuracy: 0.9464 - loss: 0.6560 Epoch 14: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 97ms/step - accuracy: 0.9444 - loss: 0.6519 - val_accuracy: 0.9854 - val_loss: 0.5189 Epoch 15/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 69ms/step - accuracy: 0.9446 - loss: 0.6534 Epoch 15: val_accuracy did not improve from 0.98806 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 91ms/step - accuracy: 0.9467 - loss: 0.6435 - val_accuracy: 0.9828 - val_loss: 0.5195 Epoch 16/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 69ms/step - accuracy: 0.9448 - loss: 0.6475 Epoch 16: val_accuracy improved from 0.98806 to 0.98939, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 16: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 97ms/step - accuracy: 0.9433 - loss: 0.6397 - val_accuracy: 0.9894 - val_loss: 0.5242 Epoch 17/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 70ms/step - accuracy: 0.9541 - loss: 0.6491 Epoch 17: val_accuracy improved from 0.98939 to 0.99072, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 17: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 100ms/step - accuracy: 0.9535 - loss: 0.6364 - val_accuracy: 0.9907 - val_loss: 0.5150 Epoch 18/25 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 75ms/step - accuracy: 0.9404 - loss: 0.6535 Epoch 18: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 96ms/step - accuracy: 0.9427 - loss: 0.6423 - val_accuracy: 0.9894 - val_loss: 0.5153 Epoch 19/25 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 66ms/step - accuracy: 0.9530 - loss: 0.6359 Epoch 19: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 88ms/step - accuracy: 0.9492 - loss: 0.6301 - val_accuracy: 0.9881 - val_loss: 0.5137 Epoch 20/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 62ms/step - accuracy: 0.9509 - loss: 0.6385 Epoch 20: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m10s[0m 83ms/step - accuracy: 0.9535 - loss: 0.6307 - val_accuracy: 0.9881 - val_loss: 0.5132 Epoch 21/25 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 62ms/step - accuracy: 0.9476 - loss: 0.6314 Epoch 21: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m10s[0m 87ms/step - accuracy: 0.9512 - loss: 0.6277 - val_accuracy: 0.9894 - val_loss: 0.5152 Epoch 22/25 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 67ms/step - accuracy: 0.9507 - loss: 0.6502 Epoch 22: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 92ms/step - accuracy: 0.9538 - loss: 0.6294 - val_accuracy: 0.9867 - val_loss: 0.5134 Epoch 23/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 66ms/step - accuracy: 0.9501 - loss: 0.6412 Epoch 23: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 88ms/step - accuracy: 0.9509 - loss: 0.6314 - val_accuracy: 0.9867 - val_loss: 0.5125 Epoch 24/25 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 78ms/step - accuracy: 0.9551 - loss: 0.6356 Epoch 24: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m12s[0m 99ms/step - accuracy: 0.9546 - loss: 0.6216 - val_accuracy: 0.9867 - val_loss: 0.5123 Epoch 25/25 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 68ms/step - accuracy: 0.9517 - loss: 0.6328 Epoch 25: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 93ms/step - accuracy: 0.9546 - loss: 0.6220 - val_accuracy: 0.9867 - val_loss: 0.5126
In [11]:
IMG_192 = (192, 192)
train_ds_192 = tf.keras.utils.image_dataset_from_directory(
train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)
val_ds_192 = tf.keras.utils.image_dataset_from_directory(
val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)
train_ds_192 = (train_ds_192.map(augment_and_mix, num_parallel_calls=AUTOTUNE)
.map(preprocess_fn, num_parallel_calls=AUTOTUNE)
.map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
val_ds_192 = (val_ds_192.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)
.map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
# Unfreeze top 100 layers
base_model.trainable = True
for layer in base_model.layers[:-100]:
layer.trainable = False
EPOCHS_P2 = 30
card_p2 = tf.data.experimental.cardinality(train_ds_192).numpy()
steps_p2 = card_p2 if card_p2 > 0 else 100
total_p2 = steps_p2 * EPOCHS_P2
warmup_p2 = steps_p2 * 2
lr_schedule_p2 = WarmupCosineDecay(warmup_p2, total_p2, peak_lr=5e-4, min_lr=1e-6)
model.compile(
optimizer=AdamW(
learning_rate=lr_schedule_p2, weight_decay=1e-4),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),
metrics=['accuracy']
)
print("Phase 2: Fine-tuning top 100 layers at 192×192...")
history_2 = model.fit(train_ds_192, validation_data=val_ds_192,
epochs=EPOCHS_P1 + EPOCHS_P2, initial_epoch=history_1.epoch[-1] + 1,
callbacks=make_callbacks())Found 3526 files belonging to 4 classes.
Found 754 files belonging to 4 classes.
Phase 2: Fine-tuning top 100 layers at 192×192...
Epoch 26/55
2026-06-12 14:23:00.868983: 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_20707', 380 bytes spill stores, 380 bytes spill loads 2026-06-12 14:23:00.892104: 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_20707', 532 bytes spill stores, 532 bytes spill loads 2026-06-12 14:23:02.414776: 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. 2026-06-12 14:23:02.572580: 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.
[1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 37ms/step - accuracy: 0.8958 - loss: 0.8296
2026-06-12 14:23:26.656239: 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_20707', 284 bytes spill stores, 284 bytes spill loads 2026-06-12 14:23:26.707546: 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_20707', 204 bytes spill stores, 204 bytes spill loads 2026-06-12 14:23:28.284698: 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. 2026-06-12 14:23:28.442489: 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.
[1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 227ms/step - accuracy: 0.8959 - loss: 0.8289 Epoch 26: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m83s[0m 324ms/step - accuracy: 0.9141 - loss: 0.7556 - val_accuracy: 0.9854 - val_loss: 0.5342 Epoch 27/55 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 49ms/step - accuracy: 0.9321 - loss: 0.6812 Epoch 27: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9353 - loss: 0.6634 - val_accuracy: 0.9867 - val_loss: 0.5301 Epoch 28/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 50ms/step - accuracy: 0.9360 - loss: 0.6741 Epoch 28: val_accuracy did not improve from 0.99072 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9419 - loss: 0.6621 - val_accuracy: 0.9828 - val_loss: 0.5267 Epoch 29/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 49ms/step - accuracy: 0.9351 - loss: 0.6449 Epoch 29: val_accuracy improved from 0.99072 to 0.99469, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 29: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 75ms/step - accuracy: 0.9433 - loss: 0.6353 - val_accuracy: 0.9947 - val_loss: 0.5227 Epoch 30/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 48ms/step - accuracy: 0.9405 - loss: 0.6331 Epoch 30: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 65ms/step - accuracy: 0.9498 - loss: 0.6274 - val_accuracy: 0.9894 - val_loss: 0.5211 Epoch 31/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 43ms/step - accuracy: 0.9568 - loss: 0.6301 Epoch 31: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 59ms/step - accuracy: 0.9563 - loss: 0.6217 - val_accuracy: 0.9947 - val_loss: 0.5088 Epoch 32/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 44ms/step - accuracy: 0.9485 - loss: 0.6269 Epoch 32: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 62ms/step - accuracy: 0.9532 - loss: 0.6204 - val_accuracy: 0.9920 - val_loss: 0.5113 Epoch 33/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 51ms/step - accuracy: 0.9529 - loss: 0.6155 Epoch 33: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 66ms/step - accuracy: 0.9566 - loss: 0.6145 - val_accuracy: 0.9920 - val_loss: 0.5079 Epoch 34/55 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 42ms/step - accuracy: 0.9579 - loss: 0.6217 Epoch 34: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 58ms/step - accuracy: 0.9609 - loss: 0.6066 - val_accuracy: 0.9947 - val_loss: 0.5062 Epoch 35/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 46ms/step - accuracy: 0.9488 - loss: 0.6275 Epoch 35: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 62ms/step - accuracy: 0.9569 - loss: 0.6065 - val_accuracy: 0.9947 - val_loss: 0.5055 Epoch 36/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 46ms/step - accuracy: 0.9513 - loss: 0.6225 Epoch 36: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 64ms/step - accuracy: 0.9589 - loss: 0.6180 - val_accuracy: 0.9934 - val_loss: 0.5105 Epoch 37/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 51ms/step - accuracy: 0.9574 - loss: 0.6120 Epoch 37: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 67ms/step - accuracy: 0.9626 - loss: 0.6054 - val_accuracy: 0.9920 - val_loss: 0.5078 Epoch 38/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 41ms/step - accuracy: 0.9620 - loss: 0.6133 Epoch 38: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 56ms/step - accuracy: 0.9637 - loss: 0.6065 - val_accuracy: 0.9934 - val_loss: 0.5003 Epoch 39/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 44ms/step - accuracy: 0.9657 - loss: 0.6051 Epoch 39: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 62ms/step - accuracy: 0.9657 - loss: 0.5989 - val_accuracy: 0.9920 - val_loss: 0.5097 Epoch 40/55 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 42ms/step - accuracy: 0.9592 - loss: 0.5924 Epoch 40: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 60ms/step - accuracy: 0.9631 - loss: 0.5926 - val_accuracy: 0.9934 - val_loss: 0.5028 Epoch 41/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 44ms/step - accuracy: 0.9630 - loss: 0.6003 Epoch 41: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 59ms/step - accuracy: 0.9682 - loss: 0.5915 - val_accuracy: 0.9947 - val_loss: 0.4992 Epoch 42/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 44ms/step - accuracy: 0.9668 - loss: 0.5889 Epoch 42: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 59ms/step - accuracy: 0.9688 - loss: 0.5840 - val_accuracy: 0.9947 - val_loss: 0.4995 Epoch 43/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 46ms/step - accuracy: 0.9640 - loss: 0.6092 Epoch 43: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 61ms/step - accuracy: 0.9640 - loss: 0.5933 - val_accuracy: 0.9947 - val_loss: 0.4971 Epoch 44/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 48ms/step - accuracy: 0.9562 - loss: 0.6077 Epoch 44: val_accuracy did not improve from 0.99469 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 66ms/step - accuracy: 0.9594 - loss: 0.6028 - val_accuracy: 0.9947 - val_loss: 0.5002 Epoch 45/55 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 43ms/step - accuracy: 0.9620 - loss: 0.5919 Epoch 45: val_accuracy improved from 0.99469 to 0.99602, saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Epoch 45: finished saving model to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 67ms/step - accuracy: 0.9697 - loss: 0.5841 - val_accuracy: 0.9960 - val_loss: 0.4982 Epoch 46/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 47ms/step - accuracy: 0.9607 - loss: 0.5942 Epoch 46: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 62ms/step - accuracy: 0.9702 - loss: 0.5871 - val_accuracy: 0.9960 - val_loss: 0.4972 Epoch 47/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 48ms/step - accuracy: 0.9634 - loss: 0.5912 Epoch 47: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 64ms/step - accuracy: 0.9680 - loss: 0.5859 - val_accuracy: 0.9960 - val_loss: 0.4970 Epoch 48/55 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 47ms/step - accuracy: 0.9643 - loss: 0.5886 Epoch 48: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 61ms/step - accuracy: 0.9680 - loss: 0.5828 - val_accuracy: 0.9947 - val_loss: 0.4962 Epoch 49/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 45ms/step - accuracy: 0.9689 - loss: 0.5773 Epoch 49: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 63ms/step - accuracy: 0.9733 - loss: 0.5714 - val_accuracy: 0.9947 - val_loss: 0.4984 Epoch 50/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 47ms/step - accuracy: 0.9692 - loss: 0.5851 Epoch 50: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 62ms/step - accuracy: 0.9722 - loss: 0.5835 - val_accuracy: 0.9947 - val_loss: 0.4955 Epoch 51/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 43ms/step - accuracy: 0.9720 - loss: 0.5699 Epoch 51: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 58ms/step - accuracy: 0.9716 - loss: 0.5712 - val_accuracy: 0.9960 - val_loss: 0.4965 Epoch 52/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 52ms/step - accuracy: 0.9703 - loss: 0.5732 Epoch 52: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 69ms/step - accuracy: 0.9688 - loss: 0.5746 - val_accuracy: 0.9947 - val_loss: 0.4965 Epoch 53/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 42ms/step - accuracy: 0.9713 - loss: 0.5905 Epoch 53: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m7s[0m 58ms/step - accuracy: 0.9711 - loss: 0.5873 - val_accuracy: 0.9947 - val_loss: 0.4969 Epoch 54/55 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 45ms/step - accuracy: 0.9729 - loss: 0.5757 Epoch 54: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 60ms/step - accuracy: 0.9736 - loss: 0.5732 - val_accuracy: 0.9960 - val_loss: 0.4953 Epoch 55/55 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 44ms/step - accuracy: 0.9723 - loss: 0.5850 Epoch 55: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 60ms/step - accuracy: 0.9759 - loss: 0.5766 - val_accuracy: 0.9947 - val_loss: 0.4956
In [12]:
img_size = IMG_SIZE # (224, 224)
train_ds_full = tf.keras.utils.image_dataset_from_directory(
train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)
val_ds_full = tf.keras.utils.image_dataset_from_directory(
val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)
train_ds_full = (train_ds_full.map(augment_and_mix, num_parallel_calls=AUTOTUNE)
.map(preprocess_fn, num_parallel_calls=AUTOTUNE)
.map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
val_ds_full = (val_ds_full.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)
.map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))
# Full unfreeze
for layer in base_model.layers:
layer.trainable = True
EPOCHS_P3 = 30
card_p3 = tf.data.experimental.cardinality(train_ds_full).numpy()
steps_p3 = card_p3 if card_p3 > 0 else 100
total_p3 = steps_p3 * EPOCHS_P3
warmup_p3 = steps_p3 * 2
lr_schedule_p3 = WarmupCosineDecay(warmup_p3, total_p3, peak_lr=1e-4, min_lr=1e-7)
model.compile(
optimizer=AdamW(
learning_rate=lr_schedule_p3, weight_decay=1e-4),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.10),
metrics=['accuracy']
)
print("Phase 3: Full fine-tuning at 224×224...")
history_3 = model.fit(train_ds_full, validation_data=val_ds_full,
epochs=EPOCHS_P1 + EPOCHS_P2 + EPOCHS_P3, initial_epoch=(history_2.epoch[-1] + 1) if history_2.epoch else EPOCHS_P1 + EPOCHS_P2,
callbacks=make_callbacks())Found 3526 files belonging to 4 classes.
Found 754 files belonging to 4 classes.
Phase 3: Full fine-tuning at 224×224...
Epoch 56/85
2026-06-12 14:28:37.646510: 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. 2026-06-12 14:28:37.797973: 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. 2026-06-12 14:28:38.289799: 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. 2026-06-12 14:28:38.456772: 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. 2026-06-12 14:28:42.979933: 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. 2026-06-12 14:28:43.131707: 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.
[1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 43ms/step - accuracy: 0.9166 - loss: 0.5839
2026-06-12 14:29:24.609560: 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. 2026-06-12 14:29:24.760438: 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. 2026-06-12 14:29:28.524940: 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. 2026-06-12 14:29:28.675667: 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.
[1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 414ms/step - accuracy: 0.9166 - loss: 0.5834 Epoch 56: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m144s[0m 515ms/step - accuracy: 0.9209 - loss: 0.5566 - val_accuracy: 0.9841 - val_loss: 0.4012 Epoch 57/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 51ms/step - accuracy: 0.9491 - loss: 0.5064 Epoch 57: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 67ms/step - accuracy: 0.9552 - loss: 0.5008 - val_accuracy: 0.9881 - val_loss: 0.3947 Epoch 58/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 59ms/step - accuracy: 0.9571 - loss: 0.5114 Epoch 58: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 75ms/step - accuracy: 0.9552 - loss: 0.5000 - val_accuracy: 0.9907 - val_loss: 0.3781 Epoch 59/85 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 54ms/step - accuracy: 0.9583 - loss: 0.5124 Epoch 59: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 72ms/step - accuracy: 0.9569 - loss: 0.4984 - val_accuracy: 0.9907 - val_loss: 0.3811 Epoch 60/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 48ms/step - accuracy: 0.9524 - loss: 0.4857 Epoch 60: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 67ms/step - accuracy: 0.9594 - loss: 0.4783 - val_accuracy: 0.9934 - val_loss: 0.3730 Epoch 61/85 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 58ms/step - accuracy: 0.9712 - loss: 0.4700 Epoch 61: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 77ms/step - accuracy: 0.9722 - loss: 0.4640 - val_accuracy: 0.9947 - val_loss: 0.3712 Epoch 62/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 53ms/step - accuracy: 0.9667 - loss: 0.4793 Epoch 62: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9654 - loss: 0.4779 - val_accuracy: 0.9934 - val_loss: 0.3734 Epoch 63/85 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 52ms/step - accuracy: 0.9632 - loss: 0.4863 Epoch 63: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9657 - loss: 0.4826 - val_accuracy: 0.9947 - val_loss: 0.3709 Epoch 64/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 53ms/step - accuracy: 0.9634 - loss: 0.4818 Epoch 64: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9665 - loss: 0.4714 - val_accuracy: 0.9947 - val_loss: 0.3725 Epoch 65/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 53ms/step - accuracy: 0.9695 - loss: 0.4804 Epoch 65: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9688 - loss: 0.4724 - val_accuracy: 0.9947 - val_loss: 0.3707 Epoch 66/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 58ms/step - accuracy: 0.9651 - loss: 0.4806 Epoch 66: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 74ms/step - accuracy: 0.9697 - loss: 0.4700 - val_accuracy: 0.9934 - val_loss: 0.3715 Epoch 67/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 55ms/step - accuracy: 0.9713 - loss: 0.4724 Epoch 67: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9736 - loss: 0.4611 - val_accuracy: 0.9920 - val_loss: 0.3733 Epoch 68/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 55ms/step - accuracy: 0.9668 - loss: 0.4699 Epoch 68: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9711 - loss: 0.4644 - val_accuracy: 0.9920 - val_loss: 0.3741 Epoch 69/85 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 50ms/step - accuracy: 0.9699 - loss: 0.4646 Epoch 69: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 69ms/step - accuracy: 0.9736 - loss: 0.4569 - val_accuracy: 0.9947 - val_loss: 0.3703 Epoch 70/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 54ms/step - accuracy: 0.9680 - loss: 0.4670 Epoch 70: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9748 - loss: 0.4617 - val_accuracy: 0.9947 - val_loss: 0.3716 Epoch 71/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 56ms/step - accuracy: 0.9709 - loss: 0.4679 Epoch 71: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9756 - loss: 0.4645 - val_accuracy: 0.9947 - val_loss: 0.3694 Epoch 72/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 55ms/step - accuracy: 0.9719 - loss: 0.4562 Epoch 72: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9725 - loss: 0.4569 - val_accuracy: 0.9947 - val_loss: 0.3692 Epoch 73/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 56ms/step - accuracy: 0.9634 - loss: 0.4767 Epoch 73: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 74ms/step - accuracy: 0.9716 - loss: 0.4705 - val_accuracy: 0.9934 - val_loss: 0.3697 Epoch 74/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 51ms/step - accuracy: 0.9743 - loss: 0.4731 Epoch 74: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 68ms/step - accuracy: 0.9745 - loss: 0.4600 - val_accuracy: 0.9947 - val_loss: 0.3685 Epoch 75/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 54ms/step - accuracy: 0.9716 - loss: 0.4807 Epoch 75: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 75ms/step - accuracy: 0.9748 - loss: 0.4649 - val_accuracy: 0.9947 - val_loss: 0.3684 Epoch 76/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 54ms/step - accuracy: 0.9691 - loss: 0.4631 Epoch 76: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9702 - loss: 0.4566 - val_accuracy: 0.9947 - val_loss: 0.3695 Epoch 77/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 53ms/step - accuracy: 0.9679 - loss: 0.4810 Epoch 77: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9691 - loss: 0.4593 - val_accuracy: 0.9947 - val_loss: 0.3695 Epoch 78/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 62ms/step - accuracy: 0.9734 - loss: 0.4507 Epoch 78: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m10s[0m 79ms/step - accuracy: 0.9750 - loss: 0.4460 - val_accuracy: 0.9947 - val_loss: 0.3689 Epoch 79/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 54ms/step - accuracy: 0.9643 - loss: 0.4710 Epoch 79: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 71ms/step - accuracy: 0.9674 - loss: 0.4633 - val_accuracy: 0.9947 - val_loss: 0.3702 Epoch 80/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 48ms/step - accuracy: 0.9741 - loss: 0.4674 Epoch 80: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 67ms/step - accuracy: 0.9736 - loss: 0.4600 - val_accuracy: 0.9947 - val_loss: 0.3690 Epoch 81/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 53ms/step - accuracy: 0.9678 - loss: 0.4531 Epoch 81: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9714 - loss: 0.4485 - val_accuracy: 0.9947 - val_loss: 0.3692 Epoch 82/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 57ms/step - accuracy: 0.9779 - loss: 0.4602 Epoch 82: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m11s[0m 87ms/step - accuracy: 0.9776 - loss: 0.4540 - val_accuracy: 0.9947 - val_loss: 0.3694 Epoch 83/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 56ms/step - accuracy: 0.9658 - loss: 0.4708 Epoch 83: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 76ms/step - accuracy: 0.9711 - loss: 0.4630 - val_accuracy: 0.9947 - val_loss: 0.3680 Epoch 84/85 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 54ms/step - accuracy: 0.9782 - loss: 0.4492 Epoch 84: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9770 - loss: 0.4565 - val_accuracy: 0.9947 - val_loss: 0.3693 Epoch 85/85 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 56ms/step - accuracy: 0.9662 - loss: 0.4719 Epoch 85: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 78ms/step - accuracy: 0.9716 - loss: 0.4616 - val_accuracy: 0.9947 - val_loss: 0.3699
In [13]:
EPOCHS_SWA = 15
swa_start_epoch = (history_3.epoch[-1] + 1) if history_3.epoch else EPOCHS_P1 + EPOCHS_P2 + EPOCHS_P3
swa_cb = SWACallback(start_epoch=swa_start_epoch, swa_lr=1e-5)
model.compile(
optimizer=AdamW(
learning_rate=1e-5, weight_decay=1e-4),
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.10),
metrics=['accuracy']
)
print(f"SWA: {EPOCHS_SWA} epochs starting at epoch {swa_start_epoch + 1}...")
history_swa = model.fit(train_ds_full, validation_data=val_ds_full,
epochs=swa_start_epoch + EPOCHS_SWA, initial_epoch=swa_start_epoch,
callbacks=make_callbacks() + [swa_cb])
# Apply SWA weights
swa_cb.apply_swa_weights()
print(f"SWA complete. Final model has SWA weights applied.")
SWA: 15 epochs starting at epoch 86... SWA: starting weight averaging at epoch 86 Epoch 86/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 359ms/step - accuracy: 0.9738 - loss: 0.4644 Epoch 86: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m123s[0m 458ms/step - accuracy: 0.9748 - loss: 0.4571 - val_accuracy: 0.9947 - val_loss: 0.3677 Epoch 87/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 51ms/step - accuracy: 0.9741 - loss: 0.4651 Epoch 87: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 74ms/step - accuracy: 0.9748 - loss: 0.4565 - val_accuracy: 0.9947 - val_loss: 0.3696 Epoch 88/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 55ms/step - accuracy: 0.9735 - loss: 0.4576 Epoch 88: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 72ms/step - accuracy: 0.9762 - loss: 0.4529 - val_accuracy: 0.9947 - val_loss: 0.3684 Epoch 89/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 52ms/step - accuracy: 0.9681 - loss: 0.4679 Epoch 89: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 75ms/step - accuracy: 0.9719 - loss: 0.4654 - val_accuracy: 0.9947 - val_loss: 0.3695 Epoch 90/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 52ms/step - accuracy: 0.9753 - loss: 0.4659 Epoch 90: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 72ms/step - accuracy: 0.9767 - loss: 0.4555 - val_accuracy: 0.9947 - val_loss: 0.3697 Epoch 91/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 58ms/step - accuracy: 0.9782 - loss: 0.4525 Epoch 91: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 76ms/step - accuracy: 0.9773 - loss: 0.4555 - val_accuracy: 0.9947 - val_loss: 0.3684 Epoch 92/100 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 58ms/step - accuracy: 0.9730 - loss: 0.4624 Epoch 92: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 76ms/step - accuracy: 0.9773 - loss: 0.4534 - val_accuracy: 0.9947 - val_loss: 0.3691 Epoch 93/100 [1m109/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 51ms/step - accuracy: 0.9726 - loss: 0.4550 Epoch 93: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 68ms/step - accuracy: 0.9739 - loss: 0.4524 - val_accuracy: 0.9947 - val_loss: 0.3701 Epoch 94/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 51ms/step - accuracy: 0.9751 - loss: 0.4596 Epoch 94: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9759 - loss: 0.4537 - val_accuracy: 0.9947 - val_loss: 0.3686 Epoch 95/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 55ms/step - accuracy: 0.9763 - loss: 0.4528 Epoch 95: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 74ms/step - accuracy: 0.9793 - loss: 0.4439 - val_accuracy: 0.9947 - val_loss: 0.3688 Epoch 96/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 52ms/step - accuracy: 0.9757 - loss: 0.4581 Epoch 96: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 70ms/step - accuracy: 0.9773 - loss: 0.4437 - val_accuracy: 0.9947 - val_loss: 0.3672 Epoch 97/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 52ms/step - accuracy: 0.9660 - loss: 0.4680 Epoch 97: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 73ms/step - accuracy: 0.9697 - loss: 0.4596 - val_accuracy: 0.9947 - val_loss: 0.3704 Epoch 98/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 57ms/step - accuracy: 0.9780 - loss: 0.4543 Epoch 98: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m9s[0m 76ms/step - accuracy: 0.9765 - loss: 0.4490 - val_accuracy: 0.9947 - val_loss: 0.3706 Epoch 99/100 [1m110/111[0m [32m━━━━━━━━━━━━━━━━━━━[0m[37m━[0m [1m0s[0m 50ms/step - accuracy: 0.9711 - loss: 0.4666 Epoch 99: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m8s[0m 68ms/step - accuracy: 0.9745 - loss: 0.4585 - val_accuracy: 0.9947 - val_loss: 0.3691 Epoch 100/100 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m0s[0m 57ms/step - accuracy: 0.9722 - loss: 0.4747 Epoch 100: val_accuracy did not improve from 0.99602 [1m111/111[0m [32m━━━━━━━━━━━━━━━━━━━━[0m[37m[0m [1m10s[0m 77ms/step - accuracy: 0.9748 - loss: 0.4610 - val_accuracy: 0.9947 - val_loss: 0.3687 SWA weights applied (15 models averaged). SWA complete. Final model has SWA weights applied.
In [16]:
# Gabungkan semua history
acc = (history_1.history['accuracy'] + history_2.history['accuracy'] +
history_3.history['accuracy'] + history_swa.history['accuracy'])
val_acc = (history_1.history['val_accuracy'] + history_2.history['val_accuracy'] +
history_3.history['val_accuracy'] + history_swa.history['val_accuracy'])
loss = (history_1.history['loss'] + history_2.history['loss'] +
history_3.history['loss'] + history_swa.history['loss'])
val_loss = (history_1.history['val_loss'] + history_2.history['val_loss'] +
history_3.history['val_loss'] + history_swa.history['val_loss'])
b1 = len(history_1.history['accuracy']) - 1
b2 = b1 + len(history_2.history['accuracy'])
b3 = b2 + len(history_3.history['accuracy'])
plt.figure(figsize=(16, 6))
plt.subplot(1, 2, 1)
plt.plot(acc, label='Training Accuracy', linewidth=2)
plt.plot(val_acc, label='Validation Accuracy', linewidth=2)
plt.axvline(x=b1, color='gray', linestyle='--', alpha=0.7, label='P2 (192)')
plt.axvline(x=b2, color='black', linestyle='--', alpha=0.7, label='P3 (224)')
plt.axvline(x=b3, color='blue', linestyle='--', alpha=0.7, label='SWA start')
plt.legend(fontsize=10)
plt.title('Training & Validation Accuracy', fontsize=14)
plt.xlabel('Epoch'); plt.ylabel('Accuracy'); plt.grid(alpha=0.3)
plt.subplot(1, 2, 2)
plt.plot(loss, label='Training Loss', linewidth=2)
plt.plot(val_loss, label='Validation Loss', linewidth=2)
plt.axvline(x=b1, color='gray', linestyle='--', alpha=0.7, label='P2 (192)')
plt.axvline(x=b2, color='black', linestyle='--', alpha=0.7, label='P3 (224)')
plt.axvline(x=b3, color='blue', linestyle='--', alpha=0.7, label='SWA start')
plt.legend(fontsize=10)
plt.title('Training & Validation Loss', fontsize=14)
plt.xlabel('Epoch'); plt.ylabel('Loss'); plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()
In [17]:
def compute_ece(probs, true_labels, n_bins=15):
# Expected Calibration Error.
confs = np.max(probs, axis=1)
preds = np.argmax(probs, axis=1)
true = np.argmax(true_labels, axis=1)
accs = (preds == true).astype(np.float32)
bins = np.linspace(0, 1, n_bins + 1)
ece = 0.0
bin_stats = []
for i in range(n_bins):
in_bin = (confs > bins[i]) & (confs <= bins[i + 1])
n = np.sum(in_bin)
if n > 0:
bin_acc = np.mean(accs[in_bin])
bin_conf = np.mean(confs[in_bin])
ece += (n / len(confs)) * np.abs(bin_acc - bin_conf)
bin_stats.append((bins[i], n, bin_acc, bin_conf))
return ece, bin_stats
# Collect logits and labels from validation set
print("Collecting validation logits...")
logits_model = tf.keras.Model(model.input, model.output)
all_logits = []
all_labels = []
for images, labels in val_ds_full.unbatch().batch(BATCH_SIZE):
all_logits.append(logits_model.predict_on_batch(images))
all_labels.append(labels.numpy())
all_logits = np.concatenate(all_logits, axis=0)
all_labels = np.concatenate(all_labels, axis=0)
# ECE before scaling (T=1)
probs_raw = tf.nn.softmax(all_logits).numpy()
ece_raw, _ = compute_ece(probs_raw, all_labels)
print(f"ECE before scaling (T=1.0): {ece_raw:.4f}")
# Optimize T on validation set
if HAS_SCIPY:
def nll_temperature(T):
scaled = all_logits / float(T)
probs = tf.nn.softmax(scaled).numpy()
probs = np.clip(probs, 1e-7, 1.0 - 1e-7)
return -np.mean(np.log(np.sum(all_labels * probs, axis=1)))
result = minimize_scalar(nll_temperature, bounds=(0.1, 5.0), method='bounded')
T_opt = result.x
print(f"Optimal temperature: T = {T_opt:.4f}")
else:
# Grid search fallback
best_nll, T_opt = float('inf'), 1.0
for T in np.linspace(0.5, 4.0, 36):
scaled = all_logits / T
probs = tf.nn.softmax(scaled).numpy()
probs = np.clip(probs, 1e-7, 1.0 - 1e-7)
nll = -np.mean(np.log(np.sum(all_labels * probs, axis=1)))
if nll < best_nll:
best_nll = nll
T_opt = T
print(f"Optimal temperature (grid): T = {T_opt:.4f}")
# ECE after scaling
probs_cal = tf.nn.softmax(all_logits / T_opt).numpy()
ece_cal, bin_stats = compute_ece(probs_cal, all_labels)
print(f"ECE after scaling (T={T_opt:.4f}): {ece_cal:.4f}")
# Save calibration metadata
calibration_meta = {
"temperature": float(T_opt),
"conf_threshold_high": 0.70,
"conf_threshold_low": 0.45,
"ece_raw": float(ece_raw),
"ece_calibrated": float(ece_cal),
}
with open(os.path.join(ckpt_dir, "calibration.json"), "w") as f:
json.dump(calibration_meta, f, indent=2)
print(f"Calibration metadata saved to {os.path.join(ckpt_dir, 'calibration.json')}")
# Reliability diagram
n_bins = 15
plt.figure(figsize=(12, 5))
plt.subplot(1, 2, 1)
if bin_stats:
bin_mids = [(s[0] + s[0] + 1/n_bins)/2 for s in bin_stats]
bin_accs = [s[2] for s in bin_stats]
bin_confs = [s[3] for s in bin_stats]
plt.bar(bin_mids, bin_accs, width=0.05, alpha=0.5, label='Accuracy')
plt.bar(bin_mids, bin_confs, width=0.05, alpha=0.3, label='Confidence')
plt.plot([0, 1], [0, 1], 'k--', alpha=0.3)
plt.xlabel('Confidence'); plt.ylabel('Accuracy')
plt.title(f'Reliability Diagram (T={T_opt:.2f})')
plt.legend(); plt.grid(alpha=0.3)
plt.subplot(1, 2, 2)
conf_raw = np.max(probs_raw, axis=1)
conf_cal = np.max(probs_cal, axis=1)
plt.hist(conf_raw, bins=30, alpha=0.5, label='Before scaling', density=True)
plt.hist(conf_cal, bins=30, alpha=0.5, label='After scaling', density=True)
plt.xlabel('Max Confidence'); plt.ylabel('Density')
plt.title('Confidence Distribution')
plt.legend(); plt.grid(alpha=0.3)
plt.tight_layout()
plt.show()Collecting validation logits... ECE before scaling (T=1.0): 0.0661 Optimal temperature: T = 0.5303 ECE after scaling (T=0.5303): 0.0031 Calibration metadata saved to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/calibration.json
In [20]:
# Gunakan model dari memory (sudah SWA weights applied dari Cell 12)
# Tidak perlu load checkpoint — model sudah siap di kernel.
best_model = model
# Collect test images
raw_test_ds = tf.keras.utils.image_dataset_from_directory(
test_dir, shuffle=False, batch_size=BATCH_SIZE, image_size=IMG_SIZE)
test_images = []
test_labels_raw = []
for images, labels in raw_test_ds.unbatch():
test_images.append(images.numpy())
test_labels_raw.append(labels.numpy())
test_images = np.array(test_images)
test_labels_true = tf.one_hot(np.array(test_labels_raw), NUM_CLASSES).numpy()
# ── TTA 5x ──
TTA_STEPS = 5
tta_logits = []
for i in range(TTA_STEPS):
aug_images = geo_aug(test_images, training=True)
aug_images = preprocess_input(aug_images)
logits = best_model.predict(aug_images, batch_size=BATCH_SIZE, verbose=0)
tta_logits.append(logits)
print(f" TTA step {i+1}/{TTA_STEPS}")
mean_logits = np.mean(tta_logits, axis=0)
# Apply temperature scaling
mean_cal_probs = tf.nn.softmax(mean_logits / T_opt).numpy()
test_preds = np.argmax(mean_cal_probs, axis=1)
test_true = np.argmax(test_labels_true, axis=1)
tta_acc = np.mean(test_preds == test_true)
print(f"\nTest Accuracy (TTA {TTA_STEPS}x, T={T_opt:.2f}): {tta_acc*100:.2f}%")
# ECE on test set
ece_test, _ = compute_ece(mean_cal_probs, test_labels_true)
print(f"ECE on test set: {ece_test:.4f}")Found 758 files belonging to 4 classes.
2026-06-12 14:58:18.264137: I tensorflow/core/framework/local_rendezvous.cc:407] Local rendezvous is aborting with status: OUT_OF_RANGE: End of sequence 2026-06-12 14:58:29.241715: 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_2424', 252 bytes spill stores, 252 bytes spill loads 2026-06-12 14:58:29.245951: 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_2424', 16 bytes spill stores, 16 bytes spill loads 2026-06-12 14:58:29.395233: 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_2531', 252 bytes spill stores, 252 bytes spill loads 2026-06-12 14:58:29.456816: 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_2531_0', 492 bytes spill stores, 1464 bytes spill loads 2026-06-12 14:58:29.498326: 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_2531', 16 bytes spill stores, 16 bytes spill loads 2026-06-12 14:58:29.825599: 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_2424', 5912 bytes spill stores, 5980 bytes spill loads 2026-06-12 14:58:29.891163: 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_2424', 5356 bytes spill stores, 5344 bytes spill loads 2026-06-12 14:58:30.050037: 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_2531', 5356 bytes spill stores, 5344 bytes spill loads 2026-06-12 14:58:30.128273: 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_2531', 5912 bytes spill stores, 5980 bytes spill loads 2026-06-12 14:58:31.572783: 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. 2026-06-12 14:58:31.729121: 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. 2026-06-12 14:58:32.521772: 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. 2026-06-12 14:58:32.685014: 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. 2026-06-12 14:58:33.300056: 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. 2026-06-12 14:58:33.451394: 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. 2026-06-12 14:58:33.822116: 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. 2026-06-12 14:58:33.989295: 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. 2026-06-12 14:58:34.912339: 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. 2026-06-12 14:58:35.068434: 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. 2026-06-12 14:58:35.265910: 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. 2026-06-12 14:58:35.424360: 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.
TTA step 1/5 TTA step 2/5 TTA step 3/5 TTA step 4/5 TTA step 5/5 Test Accuracy (TTA 5x, T=0.53): 99.34% ECE on test set: 0.0028
In [21]:
def get_source(filename):
f = os.path.splitext(filename)[0]
if f.startswith('IMG_'): return 'Phone'
if f.startswith('Corn_'): return 'Lab_Corn'
for p in ['CBS', 'GLS', 'NLS', 'CLS']:
if f.startswith(p): return 'Lab_Disease'
for p in ['SCR', 'CR', 'NLB', 'SLB', 'SRS']:
if f.startswith(p): return 'Lab_RustBlight'
return 'Other'
# Map each test image to its source
test_files = []
for cn in class_names:
cp = os.path.join(test_dir, cn)
if os.path.isdir(cp):
test_files.extend([(f, cn, get_source(f)) for f in sorted(os.listdir(cp))])
sources = set(s for _, _, s in test_files)
print(f"Sources found: {sorted(sources)}")
print(f"{'Source':<18} {'Count':>6} {'Accuracy':>10}")
print("-" * 38)
for src in sorted(sources):
indices = [i for i, (_, _, s) in enumerate(test_files) if s == src]
if not indices: continue
n = len(indices)
acc = np.mean(test_preds[indices] == test_true[indices])
print(f"{src:<18} {n:>6} {acc*100:>9.1f}%")
# Overall with count
overall_acc = np.mean(test_preds == test_true)
print("-" * 38)
print(f"{'ALL':<18} {len(test_preds):>6} {overall_acc*100:>9.1f}%")
Sources found: ['Lab_Corn', 'Phone'] Source Count Accuracy -------------------------------------- Lab_Corn 458 99.1% Phone 300 99.7% -------------------------------------- ALL 758 99.3%
In [22]:
print("\nClassification Report:\n")
print(classification_report(test_true, test_preds, target_names=class_names))
cm = confusion_matrix(test_true, test_preds)
plt.figure(figsize=(10, 8))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_names, yticklabels=class_names)
plt.title(f'Confusion Matrix (TTA {TTA_STEPS}x)', fontsize=14)
plt.xlabel('Predicted', fontsize=12)
plt.ylabel('True', fontsize=12)
plt.tight_layout()
plt.show()
Classification Report:
precision recall f1-score support
Bercak Daun 0.98 0.98 0.98 87
Daun Sehat 1.00 1.00 1.00 325
Hawar Daun 0.99 1.00 1.00 150
Karat Daun 0.99 0.99 0.99 196
accuracy 0.99 758
macro avg 0.99 0.99 0.99 758
weighted avg 0.99 0.99 0.99 758
In [23]:
# Save final model (keras format — mungkin tidak bisa di-load karena Lambda)
model.save(final_path := os.path.join(ckpt_dir, 'best_model.keras'))
# Save weights H5 (portable — used by save_model.py for export)
model.save_weights(os.path.join(ckpt_dir, 'model.weights.h5'))
print(f"Model saved to {final_path}")
print(f"Weights saved to {os.path.join(ckpt_dir, 'model.weights.h5')}")
# Copy calibration metadata to model directory
model_export_dir = os.path.join(os.getcwd(), 'model')
os.makedirs(model_export_dir, exist_ok=True)
# Export labels.json with calibration metadata
cal_path = os.path.join(ckpt_dir, 'calibration.json')
if os.path.exists(cal_path):
with open(cal_path) as f:
cal_meta = json.load(f)
labels_json = {
"version": "3.0",
"labels": class_names,
"temperature": cal_meta["temperature"],
"conf_threshold_high": cal_meta["conf_threshold_high"],
"conf_threshold_low": cal_meta["conf_threshold_low"],
"input_size": [224, 224],
"input_range": [0, 255],
"preprocessing": "resize_bilinear_224x224_no_normalization",
"architecture": "EfficientNetV2B0 + CBAM + Dense(512)",
"output_type": "logits",
}
else:
labels_json = {
"version": "3.0",
"labels": class_names,
"temperature": 1.0,
"input_size": [224, 224],
"input_range": [0, 255],
"output_type": "logits",
}
with open(os.path.join(model_export_dir, 'labels.json'), 'w') as f:
json.dump(labels_json, f, indent=2)
print("Labels + calibration metadata saved to model/labels.json")
# Export class names list (legacy)
with open(os.path.join(model_export_dir, 'labels.json'), 'r') as f:
pass # already written above
print(f"Classes: {class_names}")
print(f"Temperature: {labels_json['temperature']:.4f}")Model saved to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/best_model.keras Weights saved to /home/asephs/ZeaVis-Edu/Machine_Learning/best_model/model.weights.h5 Labels + calibration metadata saved to model/labels.json Classes: ['Bercak Daun', 'Daun Sehat', 'Hawar Daun', 'Karat Daun'] Temperature: 0.5303