diff --git a/notebooks/training.ipynb b/notebooks/training.ipynb
index 957b283..d6b270b 100644
--- a/notebooks/training.ipynb
+++ b/notebooks/training.ipynb
@@ -1 +1 @@
-{"cells":[{"source":" ","metadata":{},"cell_type":"markdown"},{"cell_type":"markdown","id":"a01cdf54","metadata":{"id":"0goBcwsXEl7q","papermill":{"duration":0.00558,"end_time":"2024-12-07T19:22:48.016797","exception":false,"start_time":"2024-12-07T19:22:48.011217","status":"completed"},"tags":[]},"source":["# Training"]},{"cell_type":"markdown","id":"5c57ad82","metadata":{"id":"_AciCyGkEpkC","papermill":{"duration":0.005853,"end_time":"2024-12-07T19:22:48.027518","exception":false,"start_time":"2024-12-07T19:22:48.021665","status":"completed"},"tags":[]},"source":["## Setup"]},{"cell_type":"code","execution_count":1,"id":"41b18fb0","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:22:48.038604Z","iopub.status.busy":"2024-12-07T19:22:48.037721Z","iopub.status.idle":"2024-12-07T19:22:59.264516Z","shell.execute_reply":"2024-12-07T19:22:59.26332Z"},"id":"KVoOmsrBExwK","outputId":"266204f1-044a-49f4-cf32-5ce95a872f9b","papermill":{"duration":11.23476,"end_time":"2024-12-07T19:22:59.266901","exception":false,"start_time":"2024-12-07T19:22:48.032141","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: keras in /opt/conda/lib/python3.10/site-packages (3.3.3)\r\n","Collecting keras\r\n"," Downloading keras-3.7.0-py3-none-any.whl.metadata (5.8 kB)\r\n","Collecting kimm\r\n"," Downloading kimm-0.2.5-py3-none-any.whl.metadata (12 kB)\r\n","Requirement already satisfied: absl-py in /opt/conda/lib/python3.10/site-packages (from keras) (1.4.0)\r\n","Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from keras) (1.26.4)\r\n","Requirement already satisfied: rich in /opt/conda/lib/python3.10/site-packages (from keras) (13.7.1)\r\n","Requirement already satisfied: namex in /opt/conda/lib/python3.10/site-packages (from keras) (0.0.8)\r\n","Requirement already satisfied: h5py in /opt/conda/lib/python3.10/site-packages (from keras) (3.11.0)\r\n","Requirement already satisfied: optree in /opt/conda/lib/python3.10/site-packages (from keras) (0.11.0)\r\n","Requirement already satisfied: ml-dtypes in /opt/conda/lib/python3.10/site-packages (from keras) (0.3.2)\r\n","Requirement already satisfied: packaging in /opt/conda/lib/python3.10/site-packages (from keras) (21.3)\r\n","Requirement already satisfied: typing-extensions>=4.0.0 in /opt/conda/lib/python3.10/site-packages (from optree->keras) (4.12.2)\r\n","Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /opt/conda/lib/python3.10/site-packages (from packaging->keras) (3.1.2)\r\n","Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/conda/lib/python3.10/site-packages (from rich->keras) (3.0.0)\r\n","Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/conda/lib/python3.10/site-packages (from rich->keras) (2.18.0)\r\n","Requirement already satisfied: mdurl~=0.1 in /opt/conda/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich->keras) (0.1.2)\r\n","Downloading keras-3.7.0-py3-none-any.whl (1.2 MB)\r\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m15.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n","\u001b[?25hDownloading kimm-0.2.5-py3-none-any.whl (123 kB)\r\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m123.4/123.4 kB\u001b[0m \u001b[31m7.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n","\u001b[?25hInstalling collected packages: keras, kimm\r\n"," Attempting uninstall: keras\r\n"," Found existing installation: keras 3.3.3\r\n"," Uninstalling keras-3.3.3:\r\n"," Successfully uninstalled keras-3.3.3\r\n","Successfully installed keras-3.7.0 kimm-0.2.5\r\n"]}],"source":["!pip install keras kimm -U"]},{"cell_type":"code","execution_count":2,"id":"98bdcda3","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:22:59.281705Z","iopub.status.busy":"2024-12-07T19:22:59.281388Z","iopub.status.idle":"2024-12-07T19:22:59.287978Z","shell.execute_reply":"2024-12-07T19:22:59.28706Z"},"papermill":{"duration":0.016167,"end_time":"2024-12-07T19:22:59.289944","exception":false,"start_time":"2024-12-07T19:22:59.273777","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["/\n"]}],"source":["%cd ../../"]},{"cell_type":"code","execution_count":3,"id":"6f602cf4","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:22:59.303987Z","iopub.status.busy":"2024-12-07T19:22:59.303669Z","iopub.status.idle":"2024-12-07T19:23:02.317243Z","shell.execute_reply":"2024-12-07T19:23:02.315962Z"},"id":"4bedI2X2QDdf","papermill":{"duration":3.022795,"end_time":"2024-12-07T19:23:02.319276","exception":false,"start_time":"2024-12-07T19:22:59.296481","status":"completed"},"tags":[]},"outputs":[],"source":["# set seed\n","seed = 42\n","\n","# set n train and test images\n","n_train_images = 4000\n","n_test_images = 300\n","\n","# set batch size\n","batch_size = 16\n","\n","# set num classes\n","num_classes = 5\n","\n","# set class names\n","class_names = ['tiger', 'lynx', 'bear', 'deer', 'bird']\n","\n","# define paths to train and test images\n","images_input_dir = 'kaggle/input/preprocess-images/images'\n","images_sampled_dir = 'images'\n","!mkdir -p \"$images_sampled_dir\"\n","train_dir = images_input_dir + '/train'\n","train_dir_sampled = images_sampled_dir + '/train_sampled'\n","test_dir = images_input_dir + '/test'\n","test_dir_sampled = images_sampled_dir + '/test_sampled'\n","test2_dir = images_input_dir + '/test2'\n","\n","# define path to model dir\n","model_dir = 'kaggle/working/model'\n","!mkdir -p \"$model_dir\"\n","model_path = model_dir + '/model.keras'\n","model_constructor = 'EfficientNetV2S'\n","\n","# define path to media dir\n","media_dir = 'kaggle/working/media'\n","!mkdir -p \"$media_dir\"\n","\n","# decide whether to log run or not\n","logging = True"]},{"cell_type":"code","execution_count":4,"id":"35997ae0","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:23:02.332315Z","iopub.status.busy":"2024-12-07T19:23:02.332011Z","iopub.status.idle":"2024-12-07T19:23:17.216174Z","shell.execute_reply":"2024-12-07T19:23:17.215511Z"},"id":"WNSWKPrzEzy_","papermill":{"duration":14.892974,"end_time":"2024-12-07T19:23:17.21819","exception":false,"start_time":"2024-12-07T19:23:02.325216","status":"completed"},"tags":[]},"outputs":[],"source":["import os\n","import time\n","import shutil\n","import random\n","import numpy as np\n","\n","import keras\n","from keras import layers, optimizers, losses, callbacks, saving\n","import kimm\n","import tensorflow as tf\n","import tensorflow_datasets as tfds\n","from sklearn.metrics import precision_score, recall_score, f1_score, confusion_matrix, classification_report\n","\n","import matplotlib.pyplot as plt\n","import seaborn as sns\n","\n","import wandb\n","from kaggle_secrets import UserSecretsClient"]},{"cell_type":"code","execution_count":5,"id":"da7142a4","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:23:17.231242Z","iopub.status.busy":"2024-12-07T19:23:17.230617Z","iopub.status.idle":"2024-12-07T19:23:17.23753Z","shell.execute_reply":"2024-12-07T19:23:17.236892Z"},"id":"RjGj2LDNR15z","papermill":{"duration":0.014797,"end_time":"2024-12-07T19:23:17.238976","exception":false,"start_time":"2024-12-07T19:23:17.224179","status":"completed"},"tags":[]},"outputs":[],"source":["def sample_images(source_dir, target_dir, samples_per_class, seed=42):\n"," \"\"\"\n"," Samples a fixed number of images per class from a directory structure.\n","\n"," Args:\n"," source_dir (str): Path to the source dataset directory.\n"," target_dir (str): Path to the target dataset directory to store sampled data.\n"," samples_per_class (int): Number of images to sample per class.\n"," seed (int): Random seed for reproducibility.\n"," \"\"\"\n"," random.seed(seed)\n","\n"," if not os.path.exists(target_dir):\n"," os.makedirs(target_dir)\n","\n"," for class_name in os.listdir(source_dir):\n"," class_path = os.path.join(source_dir, class_name)\n"," if os.path.isdir(class_path):\n"," sampled_class_dir = os.path.join(target_dir, class_name)\n"," os.makedirs(sampled_class_dir, exist_ok=True)\n","\n"," # list and shuffle all files in class directory\n"," all_images = os.listdir(class_path)\n"," random.shuffle(all_images)\n","\n"," # select desired number of samples\n"," sampled_images = all_images[:samples_per_class]\n","\n"," # copy sampled images to new directory\n"," for image_name in sampled_images:\n"," source_image_path = os.path.join(class_path, image_name)\n"," target_image_path = os.path.join(sampled_class_dir, image_name)\n"," shutil.copy(source_image_path, target_image_path)"]},{"cell_type":"code","execution_count":6,"id":"17442848","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:23:17.250584Z","iopub.status.busy":"2024-12-07T19:23:17.250334Z","iopub.status.idle":"2024-12-07T19:23:20.099866Z","shell.execute_reply":"2024-12-07T19:23:20.098637Z"},"papermill":{"duration":2.857779,"end_time":"2024-12-07T19:23:20.102151","exception":false,"start_time":"2024-12-07T19:23:17.244372","status":"completed"},"tags":[]},"outputs":[{"name":"stderr","output_type":"stream","text":["/opt/conda/lib/python3.10/pty.py:89: RuntimeWarning: os.fork() was called. os.fork() is incompatible with multithreaded code, and JAX is multithreaded, so this will likely lead to a deadlock.\n"," pid, fd = os.forkpty()\n"]},{"name":"stdout","output_type":"stream","text":["\u001b[34m\u001b[1mwandb\u001b[0m: \u001b[33mWARNING\u001b[0m If you're specifying your api key in code, ensure this code is not shared publicly.\r\n","\u001b[34m\u001b[1mwandb\u001b[0m: \u001b[33mWARNING\u001b[0m Consider setting the WANDB_API_KEY environment variable, or running `wandb login` from the command line.\r\n","\u001b[34m\u001b[1mwandb\u001b[0m: Appending key for api.wandb.ai to your netrc file: /root/.netrc\r\n"]}],"source":["# log in to w&b using api key\n","if logging:\n"," user_secrets = UserSecretsClient()\n"," key = user_secrets.get_secret('wandb')\n"," !wandb login $key"]},{"cell_type":"markdown","id":"e3f5cf4a","metadata":{"id":"o-oFY9SuE8dT","papermill":{"duration":0.00566,"end_time":"2024-12-07T19:23:20.114694","exception":false,"start_time":"2024-12-07T19:23:20.109034","status":"completed"},"tags":[]},"source":["## Prepare train and test datasets"]},{"cell_type":"code","execution_count":7,"id":"0f5c4ce9","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:23:20.127095Z","iopub.status.busy":"2024-12-07T19:23:20.126765Z","iopub.status.idle":"2024-12-07T19:26:23.35635Z","shell.execute_reply":"2024-12-07T19:26:23.355619Z"},"id":"KewO2flaRgLu","papermill":{"duration":183.238269,"end_time":"2024-12-07T19:26:23.358449","exception":false,"start_time":"2024-12-07T19:23:20.12018","status":"completed"},"tags":[]},"outputs":[],"source":["# create new directory with sampled train images\n","sample_images(train_dir, train_dir_sampled, n_train_images)"]},{"cell_type":"code","execution_count":8,"id":"31e44e0a","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:23.371441Z","iopub.status.busy":"2024-12-07T19:26:23.371181Z","iopub.status.idle":"2024-12-07T19:26:36.621111Z","shell.execute_reply":"2024-12-07T19:26:36.620372Z"},"id":"feQggHlSWEh4","papermill":{"duration":13.258546,"end_time":"2024-12-07T19:26:36.623185","exception":false,"start_time":"2024-12-07T19:26:23.364639","status":"completed"},"tags":[]},"outputs":[],"source":["# create new directory with sampled test images\n","sample_images(test_dir, test_dir_sampled, n_test_images)"]},{"cell_type":"code","execution_count":9,"id":"cf57d2a4","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:36.636141Z","iopub.status.busy":"2024-12-07T19:26:36.635832Z","iopub.status.idle":"2024-12-07T19:26:41.334438Z","shell.execute_reply":"2024-12-07T19:26:41.333522Z"},"id":"J5i-u-VSE74K","outputId":"cda0d93f-4445-41f3-bb1b-5b1942d838b6","papermill":{"duration":4.707104,"end_time":"2024-12-07T19:26:41.336198","exception":false,"start_time":"2024-12-07T19:26:36.629094","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Found 20000 files belonging to 5 classes.\n","Found 1500 files belonging to 5 classes.\n","Found 303 files belonging to 1 classes.\n","Number of train samples: -2\n","Number of test samples: -2\n"]}],"source":["# create train dataset\n","train_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," train_dir_sampled,\n"," label_mode='categorical',\n"," shuffle=True,\n"," seed=seed,\n",")\n","\n","# create test dataset\n","test_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," test_dir_sampled,\n"," label_mode='categorical',\n"," shuffle=False,\n",")\n","\n","# create test2 dataset\n","test2_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," test2_dir,\n"," label_mode='categorical',\n"," shuffle=False,\n",")\n","\n","# we need to unbatch because there's somehow an unwanted additional dimension\n","train_ds = train_ds.unbatch()\n","test_ds = test_ds.unbatch()\n","test2_ds = test2_ds.unbatch()\n","\n","print(f'Number of train samples: {train_ds.cardinality()}')\n","print(f'Number of test samples: {test_ds.cardinality()}')"]},{"cell_type":"code","execution_count":10,"id":"786f5351","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:41.349284Z","iopub.status.busy":"2024-12-07T19:26:41.349005Z","iopub.status.idle":"2024-12-07T19:26:41.35361Z","shell.execute_reply":"2024-12-07T19:26:41.352723Z"},"id":"myqLQZuqFZkx","outputId":"1636afdc-4dcd-4ad9-9041-bedfc196f415","papermill":{"duration":0.012969,"end_time":"2024-12-07T19:26:41.355256","exception":false,"start_time":"2024-12-07T19:26:41.342287","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["(TensorSpec(shape=(256, 256, 3), dtype=tf.float32, name=None), TensorSpec(shape=(5,), dtype=tf.float32, name=None)) (TensorSpec(shape=(256, 256, 3), dtype=tf.float32, name=None), TensorSpec(shape=(5,), dtype=tf.float32, name=None))\n"]}],"source":["# check dimensions\n","print(train_ds.element_spec, test_ds.element_spec)"]},{"cell_type":"code","execution_count":11,"id":"bf67849a","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:41.36775Z","iopub.status.busy":"2024-12-07T19:26:41.36751Z","iopub.status.idle":"2024-12-07T19:26:41.450258Z","shell.execute_reply":"2024-12-07T19:26:41.449603Z"},"id":"YCc38anvFgJc","papermill":{"duration":0.09093,"end_time":"2024-12-07T19:26:41.452007","exception":false,"start_time":"2024-12-07T19:26:41.361077","status":"completed"},"tags":[]},"outputs":[],"source":["# setup dataset with tf.data\n","resize_fn = keras.layers.Resizing(224, 224)\n","\n","train_ds = train_ds.map(lambda x, y: (resize_fn(x), y))\n","test_ds = test_ds.map(lambda x, y: (resize_fn(x), y))\n","test2_ds = test2_ds.map(lambda x, y: (resize_fn(x), y))\n","\n","train_ds = train_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()\n","test_ds = test_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()\n","test2_ds = test2_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()"]},{"cell_type":"markdown","id":"06cec097","metadata":{"id":"CdVE1QLMFtA5","papermill":{"duration":0.005797,"end_time":"2024-12-07T19:26:41.463946","exception":false,"start_time":"2024-12-07T19:26:41.458149","status":"completed"},"tags":[]},"source":["## Prepare model"]},{"cell_type":"code","execution_count":12,"id":"1486af37","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:41.476701Z","iopub.status.busy":"2024-12-07T19:26:41.476453Z","iopub.status.idle":"2024-12-07T19:26:59.579324Z","shell.execute_reply":"2024-12-07T19:26:59.578374Z"},"id":"3mmwlJBDFf_6","outputId":"73087a5a-85e9-43f0-bdee-b067a8168bcb","papermill":{"duration":18.111613,"end_time":"2024-12-07T19:26:59.581211","exception":false,"start_time":"2024-12-07T19:26:41.469598","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Downloading data from https://github.com/james77777778/keras-image-models/releases/download/0.1.0/efficientnetv2s_tf_efficientnetv2_s.in21k_ft_in1k.keras\n","\u001b[1m87666342/87666342\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 0us/step\n"]},{"data":{"text/html":["
Model: \"functional\" \n"," \n"],"text/plain":["\u001b[1mModel: \"functional\"\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┓\n","┃ Layer (type) ┃ Output Shape ┃ Param # ┃ Trai… ┃\n","┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━┩\n","│ input_layer_1 (InputLayer ) │ (None , 224 , 224 , 3 ) │ 0 │ - │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ EfficientNetV2S │ (None , 7 , 7 , 1280 ) │ 20,331,360 │ N │\n","│ (EfficientNetV2S ) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ global_average_pooling2d │ (None , 1280 ) │ 0 │ - │\n","│ (GlobalAveragePooling2D ) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dropout (Dropout ) │ (None , 1280 ) │ 0 │ - │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dense (Dense ) │ (None , 5 ) │ 6,405 │ Y │\n","└─────────────────────────────┴───────────────────────┴────────────┴───────┘\n"," \n"],"text/plain":["┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┓\n","┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mTrai…\u001b[0m\u001b[1m \u001b[0m┃\n","┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━┩\n","│ input_layer_1 (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ EfficientNetV2S │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m20,331,360\u001b[0m │ \u001b[1;91mN\u001b[0m │\n","│ (\u001b[38;5;33mEfficientNetV2S\u001b[0m) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ global_average_pooling2d │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","│ (\u001b[38;5;33mGlobalAveragePooling2D\u001b[0m) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m5\u001b[0m) │ \u001b[38;5;34m6,405\u001b[0m │ \u001b[1;38;5;34mY\u001b[0m │\n","└─────────────────────────────┴───────────────────────┴────────────┴───────┘\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Total params: 20,337,765 (77.58 MB)\n"," \n"],"text/plain":["\u001b[1m Total params: \u001b[0m\u001b[38;5;34m20,337,765\u001b[0m (77.58 MB)\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Trainable params: 6,405 (25.02 KB)\n"," \n"],"text/plain":["\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m6,405\u001b[0m (25.02 KB)\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Non-trainable params: 20,331,360 (77.56 MB)\n"," \n"],"text/plain":["\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m20,331,360\u001b[0m (77.56 MB)\n"]},"metadata":{},"output_type":"display_data"}],"source":["# create base model\n","if model_constructor == 'EfficientNetV2B0':\n"," base_model = kimm.models.EfficientNetV2B0(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '5 mio'\n"," frozen_file_size = '26 mb'\n","elif model_constructor == 'EfficientNetV2B2':\n"," base_model = kimm.models.EfficientNetV2B2(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '9 mio'\n"," frozen_file_size = '37 mb'\n","elif model_constructor == 'EfficientNetV2S':\n"," base_model = kimm.models.EfficientNetV2S(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '21 mio'\n"," frozen_file_size = '84 mb'\n","elif model_constructor == 'EfficientNetV2M':\n"," base_model = kimm.models.EfficientNetV2M(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '54 mio'\n"," frozen_file_size = '216 mb'\n","elif model_constructor == 'EfficientNetV2L':\n"," base_model = kimm.models.EfficientNetV2L(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '119 mio'\n"," frozen_file_size = '475 mb'\n","elif model_constructor == 'EfficientNetV2XL':\n"," base_model = kimm.models.EfficientNetV2XL(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '208 mio'\n"," frozen_file_size = '835 mb'\n","else:\n"," raise Exception('Please select a valid model constructor.') \n","\n","# freeze base model\n","base_model.trainable = False\n","\n","# create new model on top\n","inputs = keras.Input(shape=(224, 224, 3))\n","x = inputs\n","\n","# The base model contains batchnorm layers. We want to keep them in inference mode\n","# when we unfreeze the base model for fine-tuning, so we make sure that the\n","# base_model is running in inference mode here.\n","x = base_model(x, training=False)\n","x = keras.layers.GlobalAveragePooling2D()(x)\n","x = keras.layers.Dropout(0.2)(x) # regularize with dropout\n","outputs = keras.layers.Dense(num_classes, activation='softmax')(x)\n","model = keras.Model(inputs, outputs)\n","\n","model.summary(show_trainable=True)"]},{"cell_type":"markdown","id":"9c5a62ab","metadata":{"id":"YcYVdF_1F9EQ","papermill":{"duration":0.007995,"end_time":"2024-12-07T19:26:59.597746","exception":false,"start_time":"2024-12-07T19:26:59.589751","status":"completed"},"tags":[]},"source":["## Training\n","\n","Follow [mewc-train](https://github.com/zaandahl/mewc-train)"]},{"cell_type":"code","execution_count":13,"id":"fd55cdff","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:59.615155Z","iopub.status.busy":"2024-12-07T19:26:59.614794Z","iopub.status.idle":"2024-12-07T19:26:59.623898Z","shell.execute_reply":"2024-12-07T19:26:59.623184Z"},"id":"Ho-88Fe_GxVd","papermill":{"duration":0.019787,"end_time":"2024-12-07T19:26:59.625562","exception":false,"start_time":"2024-12-07T19:26:59.605775","status":"completed"},"tags":[]},"outputs":[],"source":["df_size = int(n_train_images * num_classes)\n","\n","epochs = 30\n","\n","lr_init = 1e-4\n","min_lr_frac = 1/5 # default minimum learning rate fraction of initial learning rate\n","steps_per_epoch = df_size // batch_size\n","total_steps = epochs * steps_per_epoch # total number of steps for monotonic exponential decay across all epochs\n","lr = optimizers.schedules.ExponentialDecay(initial_learning_rate=lr_init, decay_steps=total_steps, decay_rate=min_lr_frac, staircase=False)\n","amsgrad = True\n","weight_decay = 1e-4\n","optimizer = optimizers.AdamW(learning_rate=lr, amsgrad=amsgrad, weight_decay=weight_decay)\n","\n","if num_classes == 2:\n"," loss_f = losses.BinaryFocalCrossentropy() # use for binary classification tasks\n"," act_f = 'sigmoid' # use for binary classification tasks\n","else:\n"," loss_f = losses.CategoricalFocalCrossentropy() # use for unbalanced multi-class tasks (typical for wildlife datasets)\n"," act_f = 'softmax' # use for multi-class classification tasks\n","\n","metrics = ['accuracy']\n","\n","callbacks = [callbacks.EarlyStopping(monitor='loss', mode='min', min_delta=0.001, patience=5, restore_best_weights=True)]"]},{"cell_type":"code","execution_count":14,"id":"cc249647","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:59.642655Z","iopub.status.busy":"2024-12-07T19:26:59.642361Z","iopub.status.idle":"2024-12-07T19:26:59.652558Z","shell.execute_reply":"2024-12-07T19:26:59.651897Z"},"id":"fAHCE7OrGCGF","papermill":{"duration":0.020834,"end_time":"2024-12-07T19:26:59.654438","exception":false,"start_time":"2024-12-07T19:26:59.633604","status":"completed"},"tags":[]},"outputs":[],"source":["model.compile(\n"," optimizer=optimizer,\n"," loss=loss_f,\n"," metrics=metrics,\n",")"]},{"cell_type":"code","execution_count":15,"id":"c70ccd37","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:26:59.671834Z","iopub.status.busy":"2024-12-07T19:26:59.671542Z","iopub.status.idle":"2024-12-07T19:44:01.366448Z","shell.execute_reply":"2024-12-07T19:44:01.365359Z"},"id":"GZKd2EixF8yO","outputId":"e8424e62-1116-4b52-90af-5fe25403927f","papermill":{"duration":1021.705664,"end_time":"2024-12-07T19:44:01.36823","exception":false,"start_time":"2024-12-07T19:26:59.662566","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Epoch 1/30\n"]},{"name":"stderr","output_type":"stream","text":["WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n","I0000 00:00:1733599634.252028 103 service.cc:145] XLA service 0x7a2f68004d40 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n","I0000 00:00:1733599634.252100 103 service.cc:153] StreamExecutor device (0): Tesla P100-PCIE-16GB, Compute Capability 6.0\n"]},{"name":"stdout","output_type":"stream","text":[" 3/Unknown \u001b[1m24s\u001b[0m 42ms/step - accuracy: 0.2188 - loss: 0.3537"]},{"name":"stderr","output_type":"stream","text":["I0000 00:00:1733599644.024647 103 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n"]},{"name":"stdout","output_type":"stream","text":[" 1250/Unknown \u001b[1m82s\u001b[0m 46ms/step - accuracy: 0.6078 - loss: 0.1701"]},{"name":"stderr","output_type":"stream","text":["/opt/conda/lib/python3.10/site-packages/keras/src/trainers/epoch_iterator.py:151: UserWarning: Your input ran out of data; interrupting training. Make sure that your dataset or generator can generate at least `steps_per_epoch * epochs` batches. You may need to use the `.repeat()` function when building your dataset.\n"," self._interrupted_warning()\n"]},{"name":"stdout","output_type":"stream","text":["\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m83s\u001b[0m 47ms/step - accuracy: 0.6079 - loss: 0.1700\n","Epoch 2/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.8546 - loss: 0.0580\n","Epoch 3/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.8789 - loss: 0.0448\n","Epoch 4/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.8899 - loss: 0.0396\n","Epoch 5/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9010 - loss: 0.0362\n","Epoch 6/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9080 - loss: 0.0329\n","Epoch 7/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9106 - loss: 0.0308\n","Epoch 8/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9173 - loss: 0.0293\n","Epoch 9/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9180 - loss: 0.0278\n","Epoch 10/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 32ms/step - accuracy: 0.9212 - loss: 0.0272\n","Epoch 11/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9236 - loss: 0.0261\n","Epoch 12/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9213 - loss: 0.0267\n","Epoch 13/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9290 - loss: 0.0244\n","Epoch 14/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9240 - loss: 0.0249\n","Epoch 15/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9334 - loss: 0.0232\n","Epoch 16/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9302 - loss: 0.0233\n","Epoch 17/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9300 - loss: 0.0240\n","Epoch 18/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9330 - loss: 0.0225\n","Epoch 19/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9347 - loss: 0.0218\n","Epoch 20/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9325 - loss: 0.0225\n","Epoch 21/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9329 - loss: 0.0220\n","Epoch 22/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 32ms/step - accuracy: 0.9359 - loss: 0.0217\n","Epoch 23/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9355 - loss: 0.0221\n","Epoch 24/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m41s\u001b[0m 33ms/step - accuracy: 0.9335 - loss: 0.0218\n","Training time mins: 17.03\n"]}],"source":["start_time = time.time()\n","model.fit(train_ds, epochs=epochs, callbacks=callbacks)\n","end_time = time.time()\n","training_time_mins = round((end_time - start_time) / 60, 2)\n","print(f'Training time mins: {training_time_mins}')"]},{"cell_type":"code","execution_count":16,"id":"d5ed513e","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:44:02.820954Z","iopub.status.busy":"2024-12-07T19:44:02.820582Z","iopub.status.idle":"2024-12-07T19:44:03.953327Z","shell.execute_reply":"2024-12-07T19:44:03.952582Z"},"id":"ik4KqmJdUbKd","outputId":"d168634b-b029-4bf1-cf87-e280ace945fb","papermill":{"duration":1.881712,"end_time":"2024-12-07T19:44:03.955299","exception":false,"start_time":"2024-12-07T19:44:02.073587","status":"completed"},"tags":[]},"outputs":[],"source":["saving.save_model(model, model_path)"]},{"cell_type":"markdown","id":"aac6d808","metadata":{"id":"qIGU25KNO1sp","papermill":{"duration":0.687282,"end_time":"2024-12-07T19:44:05.386344","exception":false,"start_time":"2024-12-07T19:44:04.699062","status":"completed"},"tags":[]},"source":["## Evaluation"]},{"cell_type":"code","execution_count":17,"id":"dd59548c","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:44:06.864001Z","iopub.status.busy":"2024-12-07T19:44:06.863602Z","iopub.status.idle":"2024-12-07T19:44:22.300186Z","shell.execute_reply":"2024-12-07T19:44:22.299005Z"},"papermill":{"duration":16.183684,"end_time":"2024-12-07T19:44:22.302181","exception":false,"start_time":"2024-12-07T19:44:06.118497","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m94/94\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m15s\u001b[0m 91ms/step - accuracy: 0.9544 - loss: 0.0154\n","Test accuracy: 93.20%\n"]}],"source":["test_accuracy = model.evaluate(test_ds)\n","print(f'Test accuracy: {test_accuracy[1] * 100:3.2f}%')"]},{"cell_type":"code","execution_count":18,"id":"70db3624","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:44:23.772084Z","iopub.status.busy":"2024-12-07T19:44:23.770989Z","iopub.status.idle":"2024-12-07T19:44:36.100248Z","shell.execute_reply":"2024-12-07T19:44:36.099501Z"},"id":"zyDqRJSEGM4L","outputId":"09e78303-ee89-418f-cef9-f1a4900de3f2","papermill":{"duration":13.085571,"end_time":"2024-12-07T19:44:36.101876","exception":false,"start_time":"2024-12-07T19:44:23.016305","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m19/19\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m12s\u001b[0m 299ms/step - accuracy: 0.8592 - loss: 3.2432\n","Test2 accuracy: 86.80%\n"]}],"source":["test2_accuracy = model.evaluate(test2_ds)\n","print(f'Test2 accuracy: {test2_accuracy[1] * 100:3.2f}%')"]},{"cell_type":"code","execution_count":19,"id":"18ad116d","metadata":{"collapsed":true,"execution":{"iopub.execute_input":"2024-12-07T19:44:37.56147Z","iopub.status.busy":"2024-12-07T19:44:37.560375Z","iopub.status.idle":"2024-12-07T19:45:00.425598Z","shell.execute_reply":"2024-12-07T19:45:00.424702Z"},"id":"hpMkylclPBAB","jupyter":{"outputs_hidden":true},"outputId":"909e4490-b5b4-48ff-a2a6-71f42226d86e","papermill":{"duration":23.58238,"end_time":"2024-12-07T19:45:00.427463","exception":false,"start_time":"2024-12-07T19:44:36.845083","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 7s/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 64ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 63ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 63ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 64ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 77ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 64ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 63ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 64ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 63ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 65ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 7s/step\n"]}],"source":["true_labels = []\n","predicted_labels = []\n","\n","for images, labels in test_ds:\n"," # append true labels based on their format\n"," if len(labels.shape) > 1: # if one-hot encoded\n"," true_labels.append(np.argmax(labels.numpy(), axis=1))\n"," else: # if integer labels\n"," true_labels.append(labels.numpy())\n","\n"," # predict labels\n"," predictions = model.predict(images)\n"," predicted_labels.append(np.argmax(predictions, axis=1))\n","\n","# combine all batches into single arrays\n","true_labels = np.concatenate(true_labels)\n","predicted_labels = np.concatenate(predicted_labels)"]},{"cell_type":"code","execution_count":20,"id":"be7fbbd8","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:45:01.945982Z","iopub.status.busy":"2024-12-07T19:45:01.945028Z","iopub.status.idle":"2024-12-07T19:45:01.957775Z","shell.execute_reply":"2024-12-07T19:45:01.956883Z"},"papermill":{"duration":0.774399,"end_time":"2024-12-07T19:45:01.959381","exception":false,"start_time":"2024-12-07T19:45:01.184982","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Precision: 93.22%; Recall: 93.20%; F1: 93.21%\n"]}],"source":["precision = precision_score(true_labels, predicted_labels, average='macro')\n","recall = recall_score(true_labels, predicted_labels, average='macro')\n","f1 = f1_score(true_labels, predicted_labels, average='macro')\n","print(f'Precision: {precision * 100:3.2f}%; Recall: {recall * 100:3.2f}%; F1: {f1 * 100:3.2f}%')"]},{"cell_type":"code","execution_count":21,"id":"eed57222","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:45:03.426075Z","iopub.status.busy":"2024-12-07T19:45:03.424984Z","iopub.status.idle":"2024-12-07T19:45:03.431641Z","shell.execute_reply":"2024-12-07T19:45:03.430717Z"},"id":"vYjCERt3PNQX","outputId":"a6eaab6b-1891-44a3-a150-8ef7a86474fc","papermill":{"duration":0.774688,"end_time":"2024-12-07T19:45:03.433455","exception":false,"start_time":"2024-12-07T19:45:02.658767","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Confusion matrix:\n"," [[294 0 2 1 3]\n"," [ 1 278 3 7 11]\n"," [ 0 8 280 6 6]\n"," [ 1 13 5 273 8]\n"," [ 2 8 7 10 273]]\n"]}],"source":["cm = confusion_matrix(true_labels, predicted_labels)\n","print('Confusion matrix:\\n', cm)"]},{"cell_type":"code","execution_count":22,"id":"fda65506","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:45:04.898414Z","iopub.status.busy":"2024-12-07T19:45:04.898065Z","iopub.status.idle":"2024-12-07T19:45:04.909897Z","shell.execute_reply":"2024-12-07T19:45:04.908826Z"},"id":"9db2EW1LPRzc","outputId":"2f0bc5bf-cf72-4972-8656-228d67f6161d","papermill":{"duration":0.715199,"end_time":"2024-12-07T19:45:04.911735","exception":false,"start_time":"2024-12-07T19:45:04.196536","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Classification report:\n"," precision recall f1-score support\n","\n"," tiger 0.99 0.98 0.98 300\n"," lynx 0.91 0.93 0.92 300\n"," bear 0.94 0.93 0.94 300\n"," deer 0.92 0.91 0.91 300\n"," bird 0.91 0.91 0.91 300\n","\n"," accuracy 0.93 1500\n"," macro avg 0.93 0.93 0.93 1500\n","weighted avg 0.93 0.93 0.93 1500\n","\n"]}],"source":["report = classification_report(true_labels, predicted_labels, target_names=class_names)\n","print('Classification report:\\n', report)"]},{"cell_type":"code","execution_count":23,"id":"94c724ab","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:45:06.413173Z","iopub.status.busy":"2024-12-07T19:45:06.412777Z","iopub.status.idle":"2024-12-07T19:45:07.344683Z","shell.execute_reply":"2024-12-07T19:45:07.343747Z"},"id":"oc7KSHEBPV8o","outputId":"d378ad2e-85be-46c7-914c-0bbf12c9ade0","papermill":{"duration":1.688267,"end_time":"2024-12-07T19:45:07.346494","exception":false,"start_time":"2024-12-07T19:45:05.658227","status":"completed"},"tags":[]},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAxQAAAK9CAYAAAC95yoDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/xnp5ZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABv0UlEQVR4nO3dd3gUVdvH8d8mpEASEkIICUgvkV4VQhcQpCMW4EEpUpQmELGg0pEgSLWASJWiohQfQHqVKgLSa0SaodeEkLrvH77ss2tAsmOSSeD74Zrryp5p9+yQZO/c58yxWK1WqwAAAADAABezAwAAAACQeZFQAAAAADCMhAIAAACAYSQUAAAAAAwjoQAAAABgGAkFAAAAAMNIKAAAAAAYRkIBAAAAwDASCgAAAACGkVAAwN+cOHFCDRo0kK+vrywWi5YsWZKqx//jjz9ksVg0a9asVD3uo6BgwYLq2LGj2WEAAJxAQgEgQ4qIiNDrr7+uwoULy9PTU9mzZ1f16tU1ceJExcTEpOm5O3TooAMHDuijjz7SnDlzVLly5TQ936Po8OHDGjJkiP744w+zQwEApDGL1Wq1mh0EANhbvny5XnrpJXl4eKh9+/YqXbq04uLitGXLFi1cuFAdO3bU1KlT0+TcMTExypYtmz744AONGDEiTc5htVoVGxsrNzc3ubq6psk5zPbDDz/opZde0oYNG1SnTp0U7xcbGysXFxe5ubmlXXAAgFSVxewAAMDeqVOn1KZNGxUoUEDr169XcHCwbV3Pnj118uRJLV++PM3Of/nyZUmSn59fmp3DYrHI09MzzY6f2VitVt29e1dZs2aVh4eH2eEAAJxElycAGcro0aMVFRWl6dOnOyQT9xQtWlR9+vSxvU5ISNDw4cNVpEgReXh4qGDBgnr//fcVGxvrsF/BggXVtGlTbdmyRU8//bQ8PT1VuHBhff3117ZthgwZogIFCkiS3n77bVksFhUsWFCS1LFjR9vX9oYMGSKLxeLQtmbNGtWoUUN+fn7y9vZWSEiI3n//fdv6B42hWL9+vWrWrCkvLy/5+fmpRYsWOnLkyH3Pd/LkSXXs2FF+fn7y9fVVp06ddOfOnQe/sf+vTp06Kl26tPbv36/atWsrW7ZsKlq0qH744QdJ0qZNm1SlShVlzZpVISEhWrt2rcP+p0+fVo8ePRQSEqKsWbMqZ86ceumllxy6Ns2aNUsvvfSSJOmZZ56RxWKRxWLRxo0bJf3vXqxatUqVK1dW1qxZ9eWXX9rW3RtDYbVa9cwzzyhXrly6dOmS7fhxcXEqU6aMihQpoujo6IdeMwAgbZFQAMhQli5dqsKFC6tatWop2r5Lly4aNGiQKlasqPHjx6t27doKDw9XmzZtkm178uRJvfjii3r22Wc1duxY5ciRQx07dtShQ4ckSa1atdL48eMlSW3bttWcOXM0YcIEp+I/dOiQmjZtqtjYWA0bNkxjx45V8+bNtXXr1n/cb+3atWrYsKEuXbqkIUOGKCwsTNu2bVP16tXvOw7h5Zdf1u3btxUeHq6XX35Zs2bN0tChQ1MU4/Xr19W0aVNVqVJFo0ePloeHh9q0aaPvvvtObdq0UePGjTVq1ChFR0frxRdf1O3bt2377tq1S9u2bVObNm00adIkvfHGG1q3bp3q1KljS2hq1aqlN998U5L0/vvva86cOZozZ45KlChhO86xY8fUtm1bPfvss5o4caLKly+fLE6LxaIZM2bo7t27euONN2ztgwcP1qFDhzRz5kx5eXml6JoBAGnICgAZxM2bN62SrC1atEjR9r/99ptVkrVLly4O7f3797dKsq5fv97WVqBAAask6+bNm21tly5dsnp4eFjfeustW9upU6eskqxjxoxxOGaHDh2sBQoUSBbD4MGDrfY/SsePH2+VZL18+fID4753jpkzZ9raypcvbw0MDLRevXrV1rZv3z6ri4uLtX379snO99prrzkc8/nnn7fmzJnzgee8p3bt2lZJ1vnz59vajh49apVkdXFxse7YscPWvmrVqmRx3rlzJ9kxt2/fbpVk/frrr21t33//vVWSdcOGDcm2v3cvVq5ced91HTp0cGj78ssvrZKsc+fOte7YscPq6upq7du370OvFQCQPqhQAMgwbt26JUny8fFJ0fY//fSTJCksLMyh/a233pKkZGMtSpYsqZo1a9pe58qVSyEhIfr9998Nx/x398Ze/Pjjj0pKSkrRPpGRkfrtt9/UsWNH+fv729rLli2rZ5991nad9uz/Yi9JNWvW1NWrV23v4T/x9vZ2qOCEhITIz89PJUqUUJUqVWzt9762f3+yZs1q+zo+Pl5Xr15V0aJF5efnpz179qTgav9SqFAhNWzYMEXbduvWTQ0bNlTv3r316quvqkiRIho5cmSK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A02YMEEDBgxQq1atJElTpkzRqlWrHnje48ePa8GCBVqzZo3q168vSSpcuLBt/b3uUYGBgfLz85P0V0Vj5MiRWrt2rUJDQ237bNmyRV9++aVq166tyZMnq0iRIho7dqwkKSQkRAcOHNDHH3+ciu8aAOBRREIBAE5YtmyZvL29FR8fr6SkJP3nP//RkCFD1LNnT5UpU8Zh3MS+fft08uRJ+fj4OBzj7t27ioiI0M2bNxUZGakqVarY1mXJkkWVK1dO1u3pnt9++02urq6qXbt2imM+efKk7ty5o2effdahPS4uThUqVJAkHTlyxCEOSbbkAwCAf0JCAQBOeOaZZzR58mS5u7srT548ypLlfz9Gvby8HLaNiopSpUqVNG/evGTHyZUrl6HzZ82a1el9oqKiJEnLly9X3rx5HdZ5eHgYigMAgHtIKADACV5eXipatGiKtq1YsaK+++47BQYGKnv27PfdJjg4WDt37lStWrUkSQkJCdq9e7cqVqx43+3LlCmjpKQkbdq0ydblyd69CkliYqKtrWTJkvLw8NCZM2ceWNkoUaKE/vvf/zq07dix4+EXCQB47DEoGwDSSLt27RQQEKAWLVro559/1qlTp7Rx40a9+eabOnfunCSpT58+GjVqlJYsWaKjR4+qR48e/ziHRMGCBdWhQwe99tprWrJkie2YCxYskCQVKFBAFotFy5Yt0+XLlxUVFSUfHx/1799f/fr10+zZsxUREaE9e/bo008/1ezZsyVJb7zxhk6cOKG3335bx44d0/z58zVr1qy0fosAAI8AEgoASCPZsmXT5s2blT9/frVq1UolSpRQ586ddffuXVvF4q233tKrr76qDh06KDQ0VD4+Pnr++ef/8biTJ0/Wiy++qB49eujJJ59U165dFR0dLUnKmzevhg4dqvfee0+5c+dWr169JEnDhw/XwIEDFR4erhIlSui5557T8uXLVahQIUlS/vz5tXDhQi1ZskTlypXTlClTNHLkyDR8dwAAjwqL9UEj/wAAAADgIahQAAAAADCMhAIAAACAYSQUAAAAAAwjoQAAAABgGAkFAAAAAMNIKAAAAAAYRkIBAAAAwDASCgAAAACGkVAAAAAAMIyEAgAAAIBhJBQAAAAADPs/ssUhBOEitcAAAAAASUVORK5CYII=","text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["plt.figure(figsize=(10, 8))\n","sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)\n","plt.xlabel('Predicted')\n","plt.ylabel('True')\n","plt.title('Confusion matrix')\n","confusion_matrix_path = media_dir + '/confusion_matrix.png'\n","plt.savefig(confusion_matrix_path, dpi=300, bbox_inches='tight')\n","plt.show()"]},{"cell_type":"markdown","id":"8bdd587c","metadata":{"papermill":{"duration":0.757235,"end_time":"2024-12-07T19:45:08.801389","exception":false,"start_time":"2024-12-07T19:45:08.044154","status":"completed"},"tags":[]},"source":["## Log run to W&B"]},{"cell_type":"code","execution_count":24,"id":"4b9d3908","metadata":{"execution":{"iopub.execute_input":"2024-12-07T19:45:10.24288Z","iopub.status.busy":"2024-12-07T19:45:10.241978Z","iopub.status.idle":"2024-12-07T19:45:13.85388Z","shell.execute_reply":"2024-12-07T19:45:13.852921Z"},"papermill":{"duration":4.312114,"end_time":"2024-12-07T19:45:13.855502","exception":false,"start_time":"2024-12-07T19:45:09.543388","status":"completed"},"tags":[]},"outputs":[{"name":"stderr","output_type":"stream","text":["\u001b[34m\u001b[1mwandb\u001b[0m: Using wandb-core as the SDK backend. Please refer to https://wandb.me/wandb-core for more information.\n","\u001b[34m\u001b[1mwandb\u001b[0m: Currently logged in as: \u001b[33malexvmt\u001b[0m. Use \u001b[1m`wandb login --relogin`\u001b[0m to force relogin\n","\u001b[34m\u001b[1mwandb\u001b[0m: Tracking run with wandb version 0.18.7\n","\u001b[34m\u001b[1mwandb\u001b[0m: Run data is saved locally in \u001b[35m\u001b[1m/wandb/run-20241207_194511-18cb8f9u\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: Run \u001b[1m`wandb offline`\u001b[0m to turn off syncing.\n","\u001b[34m\u001b[1mwandb\u001b[0m: Syncing run \u001b[33mlively-pond-12\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: ⭐️ View project at \u001b[34m\u001b[4mhttps://wandb.ai/alexvmt/tiger_classification\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: 🚀 View run at \u001b[34m\u001b[4mhttps://wandb.ai/alexvmt/tiger_classification/runs/18cb8f9u\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: \n","\u001b[34m\u001b[1mwandb\u001b[0m: \n","\u001b[34m\u001b[1mwandb\u001b[0m: Run history:\n","\u001b[34m\u001b[1mwandb\u001b[0m: f1 ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: precision ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: recall ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: test2_accuracy ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: test_accuracy ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: training_time_mins ▁\n","\u001b[34m\u001b[1mwandb\u001b[0m: \n","\u001b[34m\u001b[1mwandb\u001b[0m: Run summary:\n","\u001b[34m\u001b[1mwandb\u001b[0m: f1 0.9321\n","\u001b[34m\u001b[1mwandb\u001b[0m: precision 0.9322\n","\u001b[34m\u001b[1mwandb\u001b[0m: recall 0.932\n","\u001b[34m\u001b[1mwandb\u001b[0m: test2_accuracy 0.868\n","\u001b[34m\u001b[1mwandb\u001b[0m: test_accuracy 0.932\n","\u001b[34m\u001b[1mwandb\u001b[0m: training_time_mins 17.03\n","\u001b[34m\u001b[1mwandb\u001b[0m: \n","\u001b[34m\u001b[1mwandb\u001b[0m: 🚀 View run \u001b[33mlively-pond-12\u001b[0m at: \u001b[34m\u001b[4mhttps://wandb.ai/alexvmt/tiger_classification/runs/18cb8f9u\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: ⭐️ View project at: \u001b[34m\u001b[4mhttps://wandb.ai/alexvmt/tiger_classification\u001b[0m\n","\u001b[34m\u001b[1mwandb\u001b[0m: Synced 5 W&B file(s), 0 media file(s), 0 artifact file(s) and 0 other file(s)\n","\u001b[34m\u001b[1mwandb\u001b[0m: Find logs at: \u001b[35m\u001b[1m\u001b[0m\n"]}],"source":["if logging:\n"," run = wandb.init(\n"," project='tiger_classification',\n"," config={\n"," 'model_constructor': model_constructor,\n"," 'model_params': model_params,\n"," 'frozen_file_size': frozen_file_size,\n"," 'num_classes': num_classes,\n"," 'n_train_images': n_train_images,\n"," 'n_test_images': n_test_images,\n"," 'batch_size': batch_size,\n"," 'epochs': epochs,\n"," },\n"," )\n"," wandb.log({\n"," 'training_time_mins': training_time_mins,\n"," 'test_accuracy': round(test_accuracy[1], 4),\n"," 'test2_accuracy': round(test2_accuracy[1], 4),\n"," 'precision': round(precision, 4),\n"," 'recall': round(recall, 4),\n"," 'f1': round(f1, 4),\n"," })\n"," wandb.finish()"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[]},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":211343195,"sourceType":"kernelVersion"}],"dockerImageVersionId":30805,"isGpuEnabled":true,"isInternetEnabled":true,"language":"python","sourceType":"notebook"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.14"},"papermill":{"default_parameters":{},"duration":1356.582856,"end_time":"2024-12-07T19:45:22.168756","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-12-07T19:22:45.5859","version":"2.6.0"}},"nbformat":4,"nbformat_minor":5}
\ No newline at end of file
+{"cells":[{"source":" ","metadata":{},"cell_type":"markdown"},{"cell_type":"markdown","id":"bc835be3","metadata":{"id":"0goBcwsXEl7q","papermill":{"duration":0.006992,"end_time":"2024-12-07T20:43:12.668766","exception":false,"start_time":"2024-12-07T20:43:12.661774","status":"completed"},"tags":[]},"source":["# Training"]},{"cell_type":"markdown","id":"3a0e368d","metadata":{"id":"_AciCyGkEpkC","papermill":{"duration":0.006929,"end_time":"2024-12-07T20:43:12.681656","exception":false,"start_time":"2024-12-07T20:43:12.674727","status":"completed"},"tags":[]},"source":["## Setup"]},{"cell_type":"code","execution_count":1,"id":"2b7ac84c","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:12.694222Z","iopub.status.busy":"2024-12-07T20:43:12.693883Z","iopub.status.idle":"2024-12-07T20:43:25.016455Z","shell.execute_reply":"2024-12-07T20:43:25.015356Z"},"id":"KVoOmsrBExwK","outputId":"266204f1-044a-49f4-cf32-5ce95a872f9b","papermill":{"duration":12.331731,"end_time":"2024-12-07T20:43:25.018878","exception":false,"start_time":"2024-12-07T20:43:12.687147","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Requirement already satisfied: keras in /opt/conda/lib/python3.10/site-packages (3.3.3)\r\n","Collecting keras\r\n"," Downloading keras-3.7.0-py3-none-any.whl.metadata (5.8 kB)\r\n","Collecting kimm\r\n"," Downloading kimm-0.2.5-py3-none-any.whl.metadata (12 kB)\r\n","Requirement already satisfied: absl-py in /opt/conda/lib/python3.10/site-packages (from keras) (1.4.0)\r\n","Requirement already satisfied: numpy in /opt/conda/lib/python3.10/site-packages (from keras) (1.26.4)\r\n","Requirement already satisfied: rich in /opt/conda/lib/python3.10/site-packages (from keras) (13.7.1)\r\n","Requirement already satisfied: namex in /opt/conda/lib/python3.10/site-packages (from keras) (0.0.8)\r\n","Requirement already satisfied: h5py in /opt/conda/lib/python3.10/site-packages (from keras) (3.11.0)\r\n","Requirement already satisfied: optree in /opt/conda/lib/python3.10/site-packages (from keras) (0.11.0)\r\n","Requirement already satisfied: ml-dtypes in /opt/conda/lib/python3.10/site-packages (from keras) (0.3.2)\r\n","Requirement already satisfied: packaging in /opt/conda/lib/python3.10/site-packages (from keras) (21.3)\r\n","Requirement already satisfied: typing-extensions>=4.0.0 in /opt/conda/lib/python3.10/site-packages (from optree->keras) (4.12.2)\r\n","Requirement already satisfied: pyparsing!=3.0.5,>=2.0.2 in /opt/conda/lib/python3.10/site-packages (from packaging->keras) (3.1.2)\r\n","Requirement already satisfied: markdown-it-py>=2.2.0 in /opt/conda/lib/python3.10/site-packages (from rich->keras) (3.0.0)\r\n","Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /opt/conda/lib/python3.10/site-packages (from rich->keras) (2.18.0)\r\n","Requirement already satisfied: mdurl~=0.1 in /opt/conda/lib/python3.10/site-packages (from markdown-it-py>=2.2.0->rich->keras) (0.1.2)\r\n","Downloading keras-3.7.0-py3-none-any.whl (1.2 MB)\r\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.2/1.2 MB\u001b[0m \u001b[31m15.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n","\u001b[?25hDownloading kimm-0.2.5-py3-none-any.whl (123 kB)\r\n","\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m123.4/123.4 kB\u001b[0m \u001b[31m8.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\r\n","\u001b[?25hInstalling collected packages: keras, kimm\r\n"," Attempting uninstall: keras\r\n"," Found existing installation: keras 3.3.3\r\n"," Uninstalling keras-3.3.3:\r\n"," Successfully uninstalled keras-3.3.3\r\n","Successfully installed keras-3.7.0 kimm-0.2.5\r\n"]}],"source":["!pip install keras kimm -U"]},{"cell_type":"code","execution_count":2,"id":"b4baf665","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:25.034238Z","iopub.status.busy":"2024-12-07T20:43:25.033564Z","iopub.status.idle":"2024-12-07T20:43:25.039887Z","shell.execute_reply":"2024-12-07T20:43:25.03892Z"},"papermill":{"duration":0.015851,"end_time":"2024-12-07T20:43:25.041802","exception":false,"start_time":"2024-12-07T20:43:25.025951","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["/\n"]}],"source":["%cd ../../"]},{"cell_type":"code","execution_count":3,"id":"05626c98","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:25.055758Z","iopub.status.busy":"2024-12-07T20:43:25.055507Z","iopub.status.idle":"2024-12-07T20:43:28.270506Z","shell.execute_reply":"2024-12-07T20:43:28.269376Z"},"id":"4bedI2X2QDdf","papermill":{"duration":3.224493,"end_time":"2024-12-07T20:43:28.272712","exception":false,"start_time":"2024-12-07T20:43:25.048219","status":"completed"},"tags":[]},"outputs":[],"source":["# set seed\n","seed = 42\n","\n","# set num classes and class names\n","num_classes = 5\n","class_names = ['tiger', 'lynx', 'bear', 'deer', 'bird']\n","yaml_file = 'class_list.yaml'\n","\n","# set n train and test images\n","n_train_images = 4000\n","n_test_images = 300\n","\n","# set batch size and epochs\n","batch_size = 16\n","epochs = 30\n","\n","# define paths to train and test images\n","images_input_dir = 'kaggle/input/preprocess-images/images'\n","images_sampled_dir = 'images'\n","!mkdir -p \"$images_sampled_dir\"\n","train_dir = images_input_dir + '/train'\n","train_dir_sampled = images_sampled_dir + '/train_sampled'\n","test_dir = images_input_dir + '/test'\n","test_dir_sampled = images_sampled_dir + '/test_sampled'\n","test2_dir = images_input_dir + '/test2'\n","\n","# define path to model dir\n","model_dir = 'kaggle/working/model'\n","!mkdir -p \"$model_dir\"\n","model_path = model_dir + '/model.h5'\n","model_constructor = 'EfficientNetV2S'\n","\n","# define path to media dir\n","media_dir = 'kaggle/working/media'\n","!mkdir -p \"$media_dir\"\n","\n","# decide whether to log run or not\n","logging = False"]},{"cell_type":"code","execution_count":4,"id":"18634c53","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:28.287265Z","iopub.status.busy":"2024-12-07T20:43:28.286961Z","iopub.status.idle":"2024-12-07T20:43:43.474074Z","shell.execute_reply":"2024-12-07T20:43:43.473036Z"},"id":"WNSWKPrzEzy_","papermill":{"duration":15.197335,"end_time":"2024-12-07T20:43:43.476378","exception":false,"start_time":"2024-12-07T20:43:28.279043","status":"completed"},"tags":[]},"outputs":[],"source":["import os\n","import time\n","import yaml\n","import shutil\n","import random\n","import numpy as np\n","\n","import keras\n","from keras import layers, optimizers, losses, callbacks, saving\n","import kimm\n","import tensorflow as tf\n","import tensorflow_datasets as tfds\n","from sklearn.metrics import precision_score, recall_score, f1_score, confusion_matrix, classification_report\n","\n","import matplotlib.pyplot as plt\n","import seaborn as sns\n","\n","import wandb\n","from kaggle_secrets import UserSecretsClient"]},{"cell_type":"code","execution_count":5,"id":"e43d2962","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:43.4905Z","iopub.status.busy":"2024-12-07T20:43:43.490231Z","iopub.status.idle":"2024-12-07T20:43:43.497025Z","shell.execute_reply":"2024-12-07T20:43:43.496319Z"},"id":"RjGj2LDNR15z","papermill":{"duration":0.015275,"end_time":"2024-12-07T20:43:43.498601","exception":false,"start_time":"2024-12-07T20:43:43.483326","status":"completed"},"tags":[]},"outputs":[],"source":["def sample_images(source_dir, target_dir, samples_per_class, seed=42):\n"," \"\"\"\n"," Samples a fixed number of images per class from a directory structure.\n","\n"," Args:\n"," source_dir (str): Path to the source dataset directory.\n"," target_dir (str): Path to the target dataset directory to store sampled data.\n"," samples_per_class (int): Number of images to sample per class.\n"," seed (int): Random seed for reproducibility.\n"," \"\"\"\n"," random.seed(seed)\n","\n"," if not os.path.exists(target_dir):\n"," os.makedirs(target_dir)\n","\n"," for class_name in os.listdir(source_dir):\n"," class_path = os.path.join(source_dir, class_name)\n"," if os.path.isdir(class_path):\n"," sampled_class_dir = os.path.join(target_dir, class_name)\n"," os.makedirs(sampled_class_dir, exist_ok=True)\n","\n"," # list and shuffle all files in class directory\n"," all_images = os.listdir(class_path)\n"," random.shuffle(all_images)\n","\n"," # select desired number of samples\n"," sampled_images = all_images[:samples_per_class]\n","\n"," # copy sampled images to new directory\n"," for image_name in sampled_images:\n"," source_image_path = os.path.join(class_path, image_name)\n"," target_image_path = os.path.join(sampled_class_dir, image_name)\n"," shutil.copy(source_image_path, target_image_path)"]},{"cell_type":"code","execution_count":6,"id":"5a00223c","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:43.512361Z","iopub.status.busy":"2024-12-07T20:43:43.512076Z","iopub.status.idle":"2024-12-07T20:43:43.51786Z","shell.execute_reply":"2024-12-07T20:43:43.516975Z"},"papermill":{"duration":0.014624,"end_time":"2024-12-07T20:43:43.51957","exception":false,"start_time":"2024-12-07T20:43:43.504946","status":"completed"},"tags":[]},"outputs":[],"source":["def create_class_list_yaml_file(num_classes, class_names, file_path):\n"," \"\"\"\n"," Create a YAML file that maps numerical indices to class names.\n","\n"," This function generates a YAML file with a mapping of integer indices \n"," (as strings starting from '1') to the provided class names. The file is \n"," saved to the specified file path, creating any necessary directories along the way.\n","\n"," Args:\n"," num_classes (int): The number of classes. Must match the length of `class_names`.\n"," class_names (list of str): A list of class names to include in the YAML file.\n"," file_path (str): The full file path (including directories and file name) \n"," where the YAML file will be saved.\n"," \"\"\"\n"," if len(class_names) != num_classes:\n"," raise ValueError('The number of class names must match num_classes.')\n","\n"," # ensure the directory exists\n"," directory = os.path.dirname(file_path)\n"," if directory and not os.path.exists(directory):\n"," os.makedirs(directory)\n","\n"," # create a dictionary with the index as keys and class names as values\n"," class_dict = {str(i + 1): class_names[i] for i in range(num_classes)}\n","\n"," # write the dictionary to a YAML file\n"," with open(file_path, 'w') as file:\n"," yaml.dump(class_dict, file, default_flow_style=False)"]},{"cell_type":"code","execution_count":7,"id":"3de89afa","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:43.533664Z","iopub.status.busy":"2024-12-07T20:43:43.533134Z","iopub.status.idle":"2024-12-07T20:43:43.53783Z","shell.execute_reply":"2024-12-07T20:43:43.537106Z"},"papermill":{"duration":0.013655,"end_time":"2024-12-07T20:43:43.539484","exception":false,"start_time":"2024-12-07T20:43:43.525829","status":"completed"},"tags":[]},"outputs":[],"source":["# create class list yaml file which is needed later for deployment\n","yaml_path = model_dir + '/' + yaml_file\n","create_class_list_yaml_file(num_classes, class_names, yaml_path)"]},{"cell_type":"code","execution_count":8,"id":"6db94b2b","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:43.552887Z","iopub.status.busy":"2024-12-07T20:43:43.552605Z","iopub.status.idle":"2024-12-07T20:43:43.556769Z","shell.execute_reply":"2024-12-07T20:43:43.555805Z"},"papermill":{"duration":0.01294,"end_time":"2024-12-07T20:43:43.558384","exception":false,"start_time":"2024-12-07T20:43:43.545444","status":"completed"},"tags":[]},"outputs":[],"source":["# log in to w&b using api key\n","if logging:\n"," user_secrets = UserSecretsClient()\n"," key = user_secrets.get_secret('wandb')\n"," !wandb login $key"]},{"cell_type":"markdown","id":"1e0c6fcc","metadata":{"id":"o-oFY9SuE8dT","papermill":{"duration":0.00609,"end_time":"2024-12-07T20:43:43.570923","exception":false,"start_time":"2024-12-07T20:43:43.564833","status":"completed"},"tags":[]},"source":["## Prepare train and test datasets"]},{"cell_type":"code","execution_count":9,"id":"2f75663a","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:43:43.584575Z","iopub.status.busy":"2024-12-07T20:43:43.584285Z","iopub.status.idle":"2024-12-07T20:46:00.949168Z","shell.execute_reply":"2024-12-07T20:46:00.948217Z"},"id":"KewO2flaRgLu","papermill":{"duration":137.37435,"end_time":"2024-12-07T20:46:00.95147","exception":false,"start_time":"2024-12-07T20:43:43.57712","status":"completed"},"tags":[]},"outputs":[],"source":["# create new directory with sampled train images\n","sample_images(train_dir, train_dir_sampled, n_train_images)"]},{"cell_type":"code","execution_count":10,"id":"cada74ee","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:00.967413Z","iopub.status.busy":"2024-12-07T20:46:00.966711Z","iopub.status.idle":"2024-12-07T20:46:12.056292Z","shell.execute_reply":"2024-12-07T20:46:12.055188Z"},"id":"feQggHlSWEh4","papermill":{"duration":11.09987,"end_time":"2024-12-07T20:46:12.058425","exception":false,"start_time":"2024-12-07T20:46:00.958555","status":"completed"},"tags":[]},"outputs":[],"source":["# create new directory with sampled test images\n","sample_images(test_dir, test_dir_sampled, n_test_images)"]},{"cell_type":"code","execution_count":11,"id":"5b43eb82","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:12.071919Z","iopub.status.busy":"2024-12-07T20:46:12.071657Z","iopub.status.idle":"2024-12-07T20:46:17.055815Z","shell.execute_reply":"2024-12-07T20:46:17.054666Z"},"id":"J5i-u-VSE74K","outputId":"cda0d93f-4445-41f3-bb1b-5b1942d838b6","papermill":{"duration":4.993142,"end_time":"2024-12-07T20:46:17.057823","exception":false,"start_time":"2024-12-07T20:46:12.064681","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Found 20000 files belonging to 5 classes.\n","Found 1500 files belonging to 5 classes.\n","Found 303 files belonging to 1 classes.\n","Number of train samples: -2\n","Number of test samples: -2\n"]}],"source":["# create train dataset\n","train_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," train_dir_sampled,\n"," label_mode='categorical',\n"," shuffle=True,\n"," seed=seed,\n",")\n","\n","# create test dataset\n","test_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," test_dir_sampled,\n"," label_mode='categorical',\n"," shuffle=False,\n",")\n","\n","# create test2 dataset\n","test2_ds = tf.keras.preprocessing.image_dataset_from_directory(\n"," test2_dir,\n"," label_mode='categorical',\n"," shuffle=False,\n",")\n","\n","# we need to unbatch because there's somehow an unwanted additional dimension\n","train_ds = train_ds.unbatch()\n","test_ds = test_ds.unbatch()\n","test2_ds = test2_ds.unbatch()\n","\n","print(f'Number of train samples: {train_ds.cardinality()}')\n","print(f'Number of test samples: {test_ds.cardinality()}')"]},{"cell_type":"code","execution_count":12,"id":"d792fb98","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:17.073395Z","iopub.status.busy":"2024-12-07T20:46:17.073065Z","iopub.status.idle":"2024-12-07T20:46:17.077966Z","shell.execute_reply":"2024-12-07T20:46:17.076939Z"},"id":"myqLQZuqFZkx","outputId":"1636afdc-4dcd-4ad9-9041-bedfc196f415","papermill":{"duration":0.015047,"end_time":"2024-12-07T20:46:17.079804","exception":false,"start_time":"2024-12-07T20:46:17.064757","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["(TensorSpec(shape=(256, 256, 3), dtype=tf.float32, name=None), TensorSpec(shape=(5,), dtype=tf.float32, name=None)) (TensorSpec(shape=(256, 256, 3), dtype=tf.float32, name=None), TensorSpec(shape=(5,), dtype=tf.float32, name=None))\n"]}],"source":["# check dimensions\n","print(train_ds.element_spec, test_ds.element_spec)"]},{"cell_type":"code","execution_count":13,"id":"9d363dbb","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:17.094914Z","iopub.status.busy":"2024-12-07T20:46:17.09395Z","iopub.status.idle":"2024-12-07T20:46:17.190972Z","shell.execute_reply":"2024-12-07T20:46:17.19022Z"},"id":"YCc38anvFgJc","papermill":{"duration":0.106983,"end_time":"2024-12-07T20:46:17.193179","exception":false,"start_time":"2024-12-07T20:46:17.086196","status":"completed"},"tags":[]},"outputs":[],"source":["# setup dataset with tf.data\n","resize_fn = keras.layers.Resizing(224, 224)\n","\n","train_ds = train_ds.map(lambda x, y: (resize_fn(x), y))\n","test_ds = test_ds.map(lambda x, y: (resize_fn(x), y))\n","test2_ds = test2_ds.map(lambda x, y: (resize_fn(x), y))\n","\n","train_ds = train_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()\n","test_ds = test_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()\n","test2_ds = test2_ds.batch(batch_size).prefetch(tf.data.AUTOTUNE).cache()"]},{"cell_type":"markdown","id":"2604dc32","metadata":{"id":"CdVE1QLMFtA5","papermill":{"duration":0.006709,"end_time":"2024-12-07T20:46:17.207251","exception":false,"start_time":"2024-12-07T20:46:17.200542","status":"completed"},"tags":[]},"source":["## Prepare model"]},{"cell_type":"code","execution_count":14,"id":"77ed5544","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:17.222726Z","iopub.status.busy":"2024-12-07T20:46:17.222396Z","iopub.status.idle":"2024-12-07T20:46:36.854257Z","shell.execute_reply":"2024-12-07T20:46:36.853244Z"},"id":"3mmwlJBDFf_6","outputId":"73087a5a-85e9-43f0-bdee-b067a8168bcb","papermill":{"duration":19.641991,"end_time":"2024-12-07T20:46:36.856279","exception":false,"start_time":"2024-12-07T20:46:17.214288","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Downloading data from https://github.com/james77777778/keras-image-models/releases/download/0.1.0/efficientnetv2s_tf_efficientnetv2_s.in21k_ft_in1k.keras\n","\u001b[1m87666342/87666342\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m1s\u001b[0m 0us/step\n"]},{"data":{"text/html":["Model: \"functional\" \n"," \n"],"text/plain":["\u001b[1mModel: \"functional\"\u001b[0m\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":["┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┓\n","┃ Layer (type) ┃ Output Shape ┃ Param # ┃ Trai… ┃\n","┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━┩\n","│ input_layer_1 (InputLayer ) │ (None , 224 , 224 , 3 ) │ 0 │ - │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ EfficientNetV2S │ (None , 7 , 7 , 1280 ) │ 20,331,360 │ N │\n","│ (EfficientNetV2S ) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ global_average_pooling2d │ (None , 1280 ) │ 0 │ - │\n","│ (GlobalAveragePooling2D ) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dropout (Dropout ) │ (None , 1280 ) │ 0 │ - │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dense (Dense ) │ (None , 5 ) │ 6,405 │ Y │\n","└─────────────────────────────┴───────────────────────┴────────────┴───────┘\n"," \n"],"text/plain":["┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━┳━━━━━━━┓\n","┃\u001b[1m \u001b[0m\u001b[1mLayer (type) \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mOutput Shape \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1m Param #\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mTrai…\u001b[0m\u001b[1m \u001b[0m┃\n","┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━╇━━━━━━━┩\n","│ input_layer_1 (\u001b[38;5;33mInputLayer\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m224\u001b[0m, \u001b[38;5;34m3\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ EfficientNetV2S │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m7\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m20,331,360\u001b[0m │ \u001b[1;91mN\u001b[0m │\n","│ (\u001b[38;5;33mEfficientNetV2S\u001b[0m) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ global_average_pooling2d │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","│ (\u001b[38;5;33mGlobalAveragePooling2D\u001b[0m) │ │ │ │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dropout (\u001b[38;5;33mDropout\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m1280\u001b[0m) │ \u001b[38;5;34m0\u001b[0m │ \u001b[1m-\u001b[0m │\n","├─────────────────────────────┼───────────────────────┼────────────┼───────┤\n","│ dense (\u001b[38;5;33mDense\u001b[0m) │ (\u001b[38;5;45mNone\u001b[0m, \u001b[38;5;34m5\u001b[0m) │ \u001b[38;5;34m6,405\u001b[0m │ \u001b[1;38;5;34mY\u001b[0m │\n","└─────────────────────────────┴───────────────────────┴────────────┴───────┘\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Total params: 20,337,765 (77.58 MB)\n"," \n"],"text/plain":["\u001b[1m Total params: \u001b[0m\u001b[38;5;34m20,337,765\u001b[0m (77.58 MB)\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Trainable params: 6,405 (25.02 KB)\n"," \n"],"text/plain":["\u001b[1m Trainable params: \u001b[0m\u001b[38;5;34m6,405\u001b[0m (25.02 KB)\n"]},"metadata":{},"output_type":"display_data"},{"data":{"text/html":[" Non-trainable params: 20,331,360 (77.56 MB)\n"," \n"],"text/plain":["\u001b[1m Non-trainable params: \u001b[0m\u001b[38;5;34m20,331,360\u001b[0m (77.56 MB)\n"]},"metadata":{},"output_type":"display_data"}],"source":["# create base model\n","if model_constructor == 'EfficientNetV2B0':\n"," base_model = kimm.models.EfficientNetV2B0(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '5 mio'\n"," frozen_file_size = '26 mb'\n","elif model_constructor == 'EfficientNetV2B2':\n"," base_model = kimm.models.EfficientNetV2B2(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '9 mio'\n"," frozen_file_size = '37 mb'\n","elif model_constructor == 'EfficientNetV2S':\n"," base_model = kimm.models.EfficientNetV2S(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '21 mio'\n"," frozen_file_size = '84 mb'\n","elif model_constructor == 'EfficientNetV2M':\n"," base_model = kimm.models.EfficientNetV2M(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '54 mio'\n"," frozen_file_size = '216 mb'\n","elif model_constructor == 'EfficientNetV2L':\n"," base_model = kimm.models.EfficientNetV2L(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '119 mio'\n"," frozen_file_size = '475 mb'\n","elif model_constructor == 'EfficientNetV2XL':\n"," base_model = kimm.models.EfficientNetV2XL(\n"," input_shape=(224, 224, 3),\n"," include_preprocessing=True,\n"," include_top=False,\n"," )\n"," model_params = '208 mio'\n"," frozen_file_size = '835 mb'\n","else:\n"," raise Exception('Please select a valid model constructor.') \n","\n","# freeze base model\n","base_model.trainable = False\n","\n","# create new model on top\n","inputs = keras.Input(shape=(224, 224, 3))\n","x = inputs\n","\n","# The base model contains batchnorm layers. We want to keep them in inference mode\n","# when we unfreeze the base model for fine-tuning, so we make sure that the\n","# base_model is running in inference mode here.\n","x = base_model(x, training=False)\n","x = keras.layers.GlobalAveragePooling2D()(x)\n","x = keras.layers.Dropout(0.2)(x) # regularize with dropout\n","outputs = keras.layers.Dense(num_classes, activation='softmax')(x)\n","model = keras.Model(inputs, outputs)\n","\n","model.summary(show_trainable=True)"]},{"cell_type":"markdown","id":"fd0a52c2","metadata":{"id":"YcYVdF_1F9EQ","papermill":{"duration":0.008162,"end_time":"2024-12-07T20:46:36.873383","exception":false,"start_time":"2024-12-07T20:46:36.865221","status":"completed"},"tags":[]},"source":["## Training\n","\n","Follow [mewc-train](https://github.com/zaandahl/mewc-train)"]},{"cell_type":"code","execution_count":15,"id":"3d9af3dd","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:36.891185Z","iopub.status.busy":"2024-12-07T20:46:36.890335Z","iopub.status.idle":"2024-12-07T20:46:36.900936Z","shell.execute_reply":"2024-12-07T20:46:36.900228Z"},"id":"Ho-88Fe_GxVd","papermill":{"duration":0.021364,"end_time":"2024-12-07T20:46:36.902614","exception":false,"start_time":"2024-12-07T20:46:36.88125","status":"completed"},"tags":[]},"outputs":[],"source":["df_size = int(n_train_images * num_classes)\n","\n","lr_init = 1e-4\n","min_lr_frac = 1/5 # default minimum learning rate fraction of initial learning rate\n","steps_per_epoch = df_size // batch_size\n","total_steps = epochs * steps_per_epoch # total number of steps for monotonic exponential decay across all epochs\n","lr = optimizers.schedules.ExponentialDecay(initial_learning_rate=lr_init, decay_steps=total_steps, decay_rate=min_lr_frac, staircase=False)\n","amsgrad = True\n","weight_decay = 1e-4\n","optimizer = optimizers.AdamW(learning_rate=lr, amsgrad=amsgrad, weight_decay=weight_decay)\n","\n","if num_classes == 2:\n"," loss_f = losses.BinaryFocalCrossentropy() # use for binary classification tasks\n"," act_f = 'sigmoid' # use for binary classification tasks\n","else:\n"," loss_f = losses.CategoricalFocalCrossentropy() # use for unbalanced multi-class tasks (typical for wildlife datasets)\n"," act_f = 'softmax' # use for multi-class classification tasks\n","\n","metrics = ['accuracy']\n","\n","callbacks = [callbacks.EarlyStopping(monitor='loss', mode='min', min_delta=0.001, patience=5, restore_best_weights=True)]"]},{"cell_type":"code","execution_count":16,"id":"9674fe77","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:36.920071Z","iopub.status.busy":"2024-12-07T20:46:36.919753Z","iopub.status.idle":"2024-12-07T20:46:36.93005Z","shell.execute_reply":"2024-12-07T20:46:36.929353Z"},"id":"fAHCE7OrGCGF","papermill":{"duration":0.021003,"end_time":"2024-12-07T20:46:36.931892","exception":false,"start_time":"2024-12-07T20:46:36.910889","status":"completed"},"tags":[]},"outputs":[],"source":["model.compile(\n"," optimizer=optimizer,\n"," loss=loss_f,\n"," metrics=metrics,\n",")"]},{"cell_type":"code","execution_count":17,"id":"9ff7d098","metadata":{"execution":{"iopub.execute_input":"2024-12-07T20:46:36.949224Z","iopub.status.busy":"2024-12-07T20:46:36.9489Z","iopub.status.idle":"2024-12-07T21:04:57.659925Z","shell.execute_reply":"2024-12-07T21:04:57.658896Z"},"id":"GZKd2EixF8yO","outputId":"e8424e62-1116-4b52-90af-5fe25403927f","papermill":{"duration":1100.721879,"end_time":"2024-12-07T21:04:57.66185","exception":false,"start_time":"2024-12-07T20:46:36.939971","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Epoch 1/30\n"]},{"name":"stderr","output_type":"stream","text":["WARNING: All log messages before absl::InitializeLog() is called are written to STDERR\n","I0000 00:00:1733604413.541465 84 service.cc:145] XLA service 0x7c3668001be0 initialized for platform CUDA (this does not guarantee that XLA will be used). Devices:\n","I0000 00:00:1733604413.541536 84 service.cc:153] StreamExecutor device (0): Tesla P100-PCIE-16GB, Compute Capability 6.0\n"]},{"name":"stdout","output_type":"stream","text":[" 3/Unknown \u001b[1m27s\u001b[0m 42ms/step - accuracy: 0.2188 - loss: 0.3537"]},{"name":"stderr","output_type":"stream","text":["I0000 00:00:1733604424.214460 84 device_compiler.h:188] Compiled cluster using XLA! This line is logged at most once for the lifetime of the process.\n"]},{"name":"stdout","output_type":"stream","text":[" 1250/Unknown \u001b[1m90s\u001b[0m 51ms/step - accuracy: 0.6078 - loss: 0.1701"]},{"name":"stderr","output_type":"stream","text":["/opt/conda/lib/python3.10/site-packages/keras/src/trainers/epoch_iterator.py:151: UserWarning: Your input ran out of data; interrupting training. Make sure that your dataset or generator can generate at least `steps_per_epoch * epochs` batches. You may need to use the `.repeat()` function when building your dataset.\n"," self._interrupted_warning()\n"]},{"name":"stdout","output_type":"stream","text":["\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m91s\u001b[0m 51ms/step - accuracy: 0.6079 - loss: 0.1700\n","Epoch 2/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.8546 - loss: 0.0580\n","Epoch 3/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.8789 - loss: 0.0448\n","Epoch 4/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.8899 - loss: 0.0396\n","Epoch 5/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9010 - loss: 0.0362\n","Epoch 6/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9080 - loss: 0.0329\n","Epoch 7/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9106 - loss: 0.0308\n","Epoch 8/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9173 - loss: 0.0293\n","Epoch 9/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9180 - loss: 0.0278\n","Epoch 10/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m43s\u001b[0m 35ms/step - accuracy: 0.9212 - loss: 0.0272\n","Epoch 11/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9236 - loss: 0.0261\n","Epoch 12/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9213 - loss: 0.0267\n","Epoch 13/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 36ms/step - accuracy: 0.9290 - loss: 0.0244\n","Epoch 14/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9240 - loss: 0.0249\n","Epoch 15/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9334 - loss: 0.0232\n","Epoch 16/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9302 - loss: 0.0233\n","Epoch 17/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9300 - loss: 0.0240\n","Epoch 18/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9330 - loss: 0.0225\n","Epoch 19/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9347 - loss: 0.0218\n","Epoch 20/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9325 - loss: 0.0225\n","Epoch 21/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9329 - loss: 0.0220\n","Epoch 22/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m44s\u001b[0m 35ms/step - accuracy: 0.9359 - loss: 0.0217\n","Epoch 23/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m43s\u001b[0m 35ms/step - accuracy: 0.9355 - loss: 0.0221\n","Epoch 24/30\n","\u001b[1m1250/1250\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m43s\u001b[0m 34ms/step - accuracy: 0.9335 - loss: 0.0218\n","Training time mins: 18.35\n"]}],"source":["start_time = time.time()\n","model.fit(train_ds, epochs=epochs, callbacks=callbacks)\n","end_time = time.time()\n","training_time_mins = round((end_time - start_time) / 60, 2)\n","print(f'Training time mins: {training_time_mins}')"]},{"cell_type":"code","execution_count":18,"id":"c60025ac","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:04:59.171125Z","iopub.status.busy":"2024-12-07T21:04:59.170754Z","iopub.status.idle":"2024-12-07T21:04:59.693603Z","shell.execute_reply":"2024-12-07T21:04:59.692839Z"},"id":"ik4KqmJdUbKd","outputId":"d168634b-b029-4bf1-cf87-e280ace945fb","papermill":{"duration":1.306508,"end_time":"2024-12-07T21:04:59.695598","exception":false,"start_time":"2024-12-07T21:04:58.38909","status":"completed"},"tags":[]},"outputs":[],"source":["saving.save_model(model, model_path)"]},{"cell_type":"markdown","id":"38d78f4c","metadata":{"id":"qIGU25KNO1sp","papermill":{"duration":0.733873,"end_time":"2024-12-07T21:05:01.220996","exception":false,"start_time":"2024-12-07T21:05:00.487123","status":"completed"},"tags":[]},"source":["## Evaluation"]},{"cell_type":"code","execution_count":19,"id":"b146e98f","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:05:02.765595Z","iopub.status.busy":"2024-12-07T21:05:02.765206Z","iopub.status.idle":"2024-12-07T21:05:19.074074Z","shell.execute_reply":"2024-12-07T21:05:19.072447Z"},"papermill":{"duration":17.086515,"end_time":"2024-12-07T21:05:19.076192","exception":false,"start_time":"2024-12-07T21:05:01.989677","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m94/94\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m16s\u001b[0m 97ms/step - accuracy: 0.9544 - loss: 0.0154\n","Test accuracy: 93.20%\n"]}],"source":["test_accuracy = model.evaluate(test_ds)\n","print(f'Test accuracy: {test_accuracy[1] * 100:3.2f}%')"]},{"cell_type":"code","execution_count":20,"id":"9dee9061","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:05:20.580226Z","iopub.status.busy":"2024-12-07T21:05:20.579867Z","iopub.status.idle":"2024-12-07T21:05:33.525015Z","shell.execute_reply":"2024-12-07T21:05:33.523948Z"},"id":"zyDqRJSEGM4L","outputId":"09e78303-ee89-418f-cef9-f1a4900de3f2","papermill":{"duration":13.722087,"end_time":"2024-12-07T21:05:33.52678","exception":false,"start_time":"2024-12-07T21:05:19.804693","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m19/19\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m13s\u001b[0m 307ms/step - accuracy: 0.8592 - loss: 3.2432\n","Test2 accuracy: 86.80%\n"]}],"source":["test2_accuracy = model.evaluate(test2_ds)\n","print(f'Test2 accuracy: {test2_accuracy[1] * 100:3.2f}%')"]},{"cell_type":"code","execution_count":21,"id":"4add1328","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:05:35.032328Z","iopub.status.busy":"2024-12-07T21:05:35.031351Z","iopub.status.idle":"2024-12-07T21:05:59.609545Z","shell.execute_reply":"2024-12-07T21:05:59.60868Z"},"id":"hpMkylclPBAB","outputId":"909e4490-b5b4-48ff-a2a6-71f42226d86e","papermill":{"duration":25.301667,"end_time":"2024-12-07T21:05:59.611203","exception":false,"start_time":"2024-12-07T21:05:34.309536","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 7s/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 66ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 75ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 79ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 78ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 79ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 77ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 75ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 83ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 79ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 75ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 68ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 77ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 75ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 77ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 72ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 74ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 71ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 73ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 76ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 69ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 70ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m0s\u001b[0m 67ms/step\n","\u001b[1m1/1\u001b[0m \u001b[32m━━━━━━━━━━━━━━━━━━━━\u001b[0m\u001b[37m\u001b[0m \u001b[1m7s\u001b[0m 7s/step\n"]}],"source":["true_labels = []\n","predicted_labels = []\n","\n","for images, labels in test_ds:\n"," # append true labels based on their format\n"," if len(labels.shape) > 1: # if one-hot encoded\n"," true_labels.append(np.argmax(labels.numpy(), axis=1))\n"," else: # if integer labels\n"," true_labels.append(labels.numpy())\n","\n"," # predict labels\n"," predictions = model.predict(images)\n"," predicted_labels.append(np.argmax(predictions, axis=1))\n","\n","# combine all batches into single arrays\n","true_labels = np.concatenate(true_labels)\n","predicted_labels = np.concatenate(predicted_labels)"]},{"cell_type":"code","execution_count":22,"id":"7a7a8fe7","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:06:01.178876Z","iopub.status.busy":"2024-12-07T21:06:01.178504Z","iopub.status.idle":"2024-12-07T21:06:01.19184Z","shell.execute_reply":"2024-12-07T21:06:01.190693Z"},"papermill":{"duration":0.801657,"end_time":"2024-12-07T21:06:01.193789","exception":false,"start_time":"2024-12-07T21:06:00.392132","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Precision: 93.22%; Recall: 93.20%; F1: 93.21%\n"]}],"source":["precision = precision_score(true_labels, predicted_labels, average='macro')\n","recall = recall_score(true_labels, predicted_labels, average='macro')\n","f1 = f1_score(true_labels, predicted_labels, average='macro')\n","print(f'Precision: {precision * 100:3.2f}%; Recall: {recall * 100:3.2f}%; F1: {f1 * 100:3.2f}%')"]},{"cell_type":"code","execution_count":23,"id":"827ba6f5","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:06:02.721673Z","iopub.status.busy":"2024-12-07T21:06:02.72133Z","iopub.status.idle":"2024-12-07T21:06:02.728735Z","shell.execute_reply":"2024-12-07T21:06:02.727645Z"},"id":"vYjCERt3PNQX","outputId":"a6eaab6b-1891-44a3-a150-8ef7a86474fc","papermill":{"duration":0.746514,"end_time":"2024-12-07T21:06:02.730425","exception":false,"start_time":"2024-12-07T21:06:01.983911","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Confusion matrix:\n"," [[294 0 2 1 3]\n"," [ 1 278 3 7 11]\n"," [ 0 8 280 6 6]\n"," [ 1 13 5 273 8]\n"," [ 2 8 7 10 273]]\n"]}],"source":["cm = confusion_matrix(true_labels, predicted_labels)\n","print('Confusion matrix:\\n', cm)"]},{"cell_type":"code","execution_count":24,"id":"96363a39","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:06:04.272219Z","iopub.status.busy":"2024-12-07T21:06:04.271861Z","iopub.status.idle":"2024-12-07T21:06:04.283806Z","shell.execute_reply":"2024-12-07T21:06:04.282814Z"},"id":"9db2EW1LPRzc","outputId":"2f0bc5bf-cf72-4972-8656-228d67f6161d","papermill":{"duration":0.746301,"end_time":"2024-12-07T21:06:04.285528","exception":false,"start_time":"2024-12-07T21:06:03.539227","status":"completed"},"tags":[]},"outputs":[{"name":"stdout","output_type":"stream","text":["Classification report:\n"," precision recall f1-score support\n","\n"," tiger 0.99 0.98 0.98 300\n"," lynx 0.91 0.93 0.92 300\n"," bear 0.94 0.93 0.94 300\n"," deer 0.92 0.91 0.91 300\n"," bird 0.91 0.91 0.91 300\n","\n"," accuracy 0.93 1500\n"," macro avg 0.93 0.93 0.93 1500\n","weighted avg 0.93 0.93 0.93 1500\n","\n"]}],"source":["report = classification_report(true_labels, predicted_labels, target_names=class_names)\n","print('Classification report:\\n', report)"]},{"cell_type":"code","execution_count":25,"id":"93564034","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:06:05.854Z","iopub.status.busy":"2024-12-07T21:06:05.853629Z","iopub.status.idle":"2024-12-07T21:06:06.829963Z","shell.execute_reply":"2024-12-07T21:06:06.829004Z"},"id":"oc7KSHEBPV8o","outputId":"d378ad2e-85be-46c7-914c-0bbf12c9ade0","papermill":{"duration":1.760316,"end_time":"2024-12-07T21:06:06.831607","exception":false,"start_time":"2024-12-07T21:06:05.071291","status":"completed"},"tags":[]},"outputs":[{"data":{"image/png":"iVBORw0KGgoAAAANSUhEUgAAAxQAAAK9CAYAAAC95yoDAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuNSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/xnp5ZAAAACXBIWXMAAA9hAAAPYQGoP6dpAABv0UlEQVR4nO3dd3gUVdvH8d8mpEASEkIICUgvkV4VQhcQpCMW4EEpUpQmELGg0pEgSLWASJWiohQfQHqVKgLSa0SaodeEkLrvH77ss2tAsmOSSeD74Zrryp5p9+yQZO/c58yxWK1WqwAAAADAABezAwAAAACQeZFQAAAAADCMhAIAAACAYSQUAAAAAAwjoQAAAABgGAkFAAAAAMNIKAAAAAAYRkIBAAAAwDASCgAAAACGkVAAwN+cOHFCDRo0kK+vrywWi5YsWZKqx//jjz9ksVg0a9asVD3uo6BgwYLq2LGj2WEAAJxAQgEgQ4qIiNDrr7+uwoULy9PTU9mzZ1f16tU1ceJExcTEpOm5O3TooAMHDuijjz7SnDlzVLly5TQ936Po8OHDGjJkiP744w+zQwEApDGL1Wq1mh0EANhbvny5XnrpJXl4eKh9+/YqXbq04uLitGXLFi1cuFAdO3bU1KlT0+TcMTExypYtmz744AONGDEiTc5htVoVGxsrNzc3ubq6psk5zPbDDz/opZde0oYNG1SnTp0U7xcbGysXFxe5ubmlXXAAgFSVxewAAMDeqVOn1KZNGxUoUEDr169XcHCwbV3Pnj118uRJLV++PM3Of/nyZUmSn59fmp3DYrHI09MzzY6f2VitVt29e1dZs2aVh4eH2eEAAJxElycAGcro0aMVFRWl6dOnOyQT9xQtWlR9+vSxvU5ISNDw4cNVpEgReXh4qGDBgnr//fcVGxvrsF/BggXVtGlTbdmyRU8//bQ8PT1VuHBhff3117ZthgwZogIFCkiS3n77bVksFhUsWFCS1LFjR9vX9oYMGSKLxeLQtmbNGtWoUUN+fn7y9vZWSEiI3n//fdv6B42hWL9+vWrWrCkvLy/5+fmpRYsWOnLkyH3Pd/LkSXXs2FF+fn7y9fVVp06ddOfOnQe/sf+vTp06Kl26tPbv36/atWsrW7ZsKlq0qH744QdJ0qZNm1SlShVlzZpVISEhWrt2rcP+p0+fVo8ePRQSEqKsWbMqZ86ceumllxy6Ns2aNUsvvfSSJOmZZ56RxWKRxWLRxo0bJf3vXqxatUqVK1dW1qxZ9eWXX9rW3RtDYbVa9cwzzyhXrly6dOmS7fhxcXEqU6aMihQpoujo6IdeMwAgbZFQAMhQli5dqsKFC6tatWop2r5Lly4aNGiQKlasqPHjx6t27doKDw9XmzZtkm178uRJvfjii3r22Wc1duxY5ciRQx07dtShQ4ckSa1atdL48eMlSW3bttWcOXM0YcIEp+I/dOiQmjZtqtjYWA0bNkxjx45V8+bNtXXr1n/cb+3atWrYsKEuXbqkIUOGKCwsTNu2bVP16tXvOw7h5Zdf1u3btxUeHq6XX35Zs2bN0tChQ1MU4/Xr19W0aVNVqVJFo0ePloeHh9q0aaPvvvtObdq0UePGjTVq1ChFR0frxRdf1O3bt2377tq1S9u2bVObNm00adIkvfHGG1q3bp3q1KljS2hq1aqlN998U5L0/vvva86cOZozZ45KlChhO86xY8fUtm1bPfvss5o4caLKly+fLE6LxaIZM2bo7t27euONN2ztgwcP1qFDhzRz5kx5eXml6JoBAGnICgAZxM2bN62SrC1atEjR9r/99ptVkrVLly4O7f3797dKsq5fv97WVqBAAask6+bNm21tly5dsnp4eFjfeustW9upU6eskqxjxoxxOGaHDh2sBQoUSBbD4MGDrfY/SsePH2+VZL18+fID4753jpkzZ9raypcvbw0MDLRevXrV1rZv3z6ri4uLtX379snO99prrzkc8/nnn7fmzJnzgee8p3bt2lZJ1vnz59vajh49apVkdXFxse7YscPWvmrVqmRx3rlzJ9kxt2/fbpVk/frrr21t33//vVWSdcOGDcm2v3cvVq5ced91HTp0cGj78ssvrZKsc+fOte7YscPq6upq7du370OvFQCQPqhQAMgwbt26JUny8fFJ0fY//fSTJCksLMyh/a233pKkZGMtSpYsqZo1a9pe58qVSyEhIfr9998Nx/x398Ze/Pjjj0pKSkrRPpGRkfrtt9/UsWNH+fv729rLli2rZ5991nad9uz/Yi9JNWvW1NWrV23v4T/x9vZ2qOCEhITIz89PJUqUUJUqVWzt9762f3+yZs1q+zo+Pl5Xr15V0aJF5efnpz179qTgav9SqFAhNWzYMEXbduvWTQ0bNlTv3r316quvqkiRIho5cmSK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A02YMEEDBgxQq1atJElTpkzRqlWrHnje48ePa8GCBVqzZo3q168vSSpcuLBt/b3uUYGBgfLz85P0V0Vj5MiRWrt2rUJDQ237bNmyRV9++aVq166tyZMnq0iRIho7dqwkKSQkRAcOHNDHH3+ciu8aAOBRREIBAE5YtmyZvL29FR8fr6SkJP3nP//RkCFD1LNnT5UpU8Zh3MS+fft08uRJ+fj4OBzj7t27ioiI0M2bNxUZGakqVarY1mXJkkWVK1dO1u3pnt9++02urq6qXbt2imM+efKk7ty5o2effdahPS4uThUqVJAkHTlyxCEOSbbkAwCAf0JCAQBOeOaZZzR58mS5u7srT548ypLlfz9Gvby8HLaNiopSpUqVNG/evGTHyZUrl6HzZ82a1el9oqKiJEnLly9X3rx5HdZ5eHgYigMAgHtIKADACV5eXipatGiKtq1YsaK+++47BQYGKnv27PfdJjg4WDt37lStWrUkSQkJCdq9e7cqVqx43+3LlCmjpKQkbdq0ydblyd69CkliYqKtrWTJkvLw8NCZM2ceWNkoUaKE/vvf/zq07dix4+EXCQB47DEoGwDSSLt27RQQEKAWLVro559/1qlTp7Rx40a9+eabOnfunCSpT58+GjVqlJYsWaKjR4+qR48e/ziHRMGCBdWhQwe99tprWrJkie2YCxYskCQVKFBAFotFy5Yt0+XLlxUVFSUfHx/1799f/fr10+zZsxUREaE9e/bo008/1ezZsyVJb7zxhk6cOKG3335bx44d0/z58zVr1qy0fosAAI8AEgoASCPZsmXT5s2blT9/frVq1UolSpRQ586ddffuXVvF4q233tKrr76qDh06KDQ0VD4+Pnr++ef/8biTJ0/Wiy++qB49eujJJ59U165dFR0dLUnKmzevhg4dqvfee0+5c+dWr169JEnDhw/XwIEDFR4erhIlSui5557T8uXLVahQIUlS/vz5tXDhQi1ZskTlypXTlClTNHLkyDR8dwAAjwqL9UEj/wAAAADgIahQAAAAADCMhAIAAACAYSQUAAAAAAwjoQAAAABgGAkFAAAAAMNIKAAAAAAYRkIBAAAAwDASCgAAAACGkVAAAAAAMIyEAgAAAIBhJBQAAAAADPs/ssUhBOEitcAAAAAASUVORK5CYII=","text/plain":[""]},"metadata":{},"output_type":"display_data"}],"source":["plt.figure(figsize=(10, 8))\n","sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=class_names, yticklabels=class_names)\n","plt.xlabel('Predicted')\n","plt.ylabel('True')\n","plt.title('Confusion matrix')\n","confusion_matrix_path = media_dir + '/confusion_matrix.png'\n","plt.savefig(confusion_matrix_path, dpi=300, bbox_inches='tight')\n","plt.show()"]},{"cell_type":"markdown","id":"12272ea3","metadata":{"papermill":{"duration":0.78006,"end_time":"2024-12-07T21:06:08.382629","exception":false,"start_time":"2024-12-07T21:06:07.602569","status":"completed"},"tags":[]},"source":["## Log run to W&B"]},{"cell_type":"code","execution_count":26,"id":"803bd0ea","metadata":{"execution":{"iopub.execute_input":"2024-12-07T21:06:09.901524Z","iopub.status.busy":"2024-12-07T21:06:09.900428Z","iopub.status.idle":"2024-12-07T21:06:09.910141Z","shell.execute_reply":"2024-12-07T21:06:09.909221Z"},"papermill":{"duration":0.748173,"end_time":"2024-12-07T21:06:09.912114","exception":false,"start_time":"2024-12-07T21:06:09.163941","status":"completed"},"tags":[]},"outputs":[],"source":["if logging:\n"," run = wandb.init(\n"," project='tiger_classification',\n"," config={\n"," 'model_constructor': model_constructor,\n"," 'model_params': model_params,\n"," 'frozen_file_size': frozen_file_size,\n"," 'num_classes': num_classes,\n"," 'n_train_images': n_train_images,\n"," 'n_test_images': n_test_images,\n"," 'batch_size': batch_size,\n"," 'epochs': epochs,\n"," },\n"," )\n"," wandb.log({\n"," 'training_time_mins': training_time_mins,\n"," 'test_accuracy': round(test_accuracy[1], 4),\n"," 'test2_accuracy': round(test2_accuracy[1], 4),\n"," 'precision': round(precision, 4),\n"," 'recall': round(recall, 4),\n"," 'f1': round(f1, 4),\n"," })\n"," wandb.finish()"]}],"metadata":{"accelerator":"GPU","colab":{"gpuType":"T4","provenance":[]},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":211343195,"sourceType":"kernelVersion"}],"dockerImageVersionId":30805,"isGpuEnabled":true,"isInternetEnabled":true,"language":"python","sourceType":"notebook"},"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.10.14"},"papermill":{"default_parameters":{},"duration":1388.685544,"end_time":"2024-12-07T21:06:18.776939","environment_variables":{},"exception":null,"input_path":"__notebook__.ipynb","output_path":"__notebook__.ipynb","parameters":{},"start_time":"2024-12-07T20:43:10.091395","version":"2.6.0"}},"nbformat":4,"nbformat_minor":5}
\ No newline at end of file