OpenMV-Image-Classification/openmv clasification training.ipynb
2024-09-14 19:47:15 -04:00

1.4 MiB
Raw Permalink Blame History

None <html lang="en"> <head> </head>

Post-training integer quantization

Overview

Integer quantization is an optimization strategy that converts 32-bit floating-point numbers (such as weights and activation outputs) to the nearest 8-bit fixed-point numbers. This results in a smaller model and increased inferencing speed, which is valuable for low-power devices such as the OpenMV camera

Setup

In order to quantize both the input and output tensors, we need to use APIs added in TensorFlow 2.3:

In [1]:
import os
import logging

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
logging.getLogger('tensorflow').setLevel(logging.ERROR)


import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf


from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential

Generate a TensorFlow Model

We'll build a simple model to classify a few playing cards.

In [2]:
batch_size = 58
img_height = 120
img_width = 120


train_ds = tf.keras.utils.image_dataset_from_directory(
  "images/",
  #color_mode='grayscale',
  validation_split=0.2,
  subset="training",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)

val_ds = tf.keras.utils.image_dataset_from_directory(
  "images/",
  #color_mode='grayscale',
  validation_split=0.2,
  subset="validation",
  seed=123,
  image_size=(img_height, img_width),
  batch_size=batch_size)



# print info on the classes in the dataset
class_names = train_ds.class_names
num_classes = len(class_names)
print("number of classes:", num_classes)

plt.figure(figsize=(10, 10))
for images, labels in train_ds.take(3):
  for i in range(9):
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(images[i].numpy().astype("uint8"))
    plt.title(class_names[labels[i]])
    plt.axis("off")
Found 97 files belonging to 5 classes.
Using 78 files for training.
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
I0000 00:00:1726357209.971252  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.016076  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.016287  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.017355  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.017543  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.017701  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.082813  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.083011  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
I0000 00:00:1726357210.083177  177727 cuda_executor.cc:1015] successful NUMA node read from SysFS had negative value (-1), but there must be at least one NUMA node, so returning NUMA node zero. See more at https://github.com/torvalds/linux/blob/v6.0/Documentation/ABI/testing/sysfs-bus-pci#L344-L355
Found 97 files belonging to 5 classes.
Using 19 files for validation.
number of classes: 5
No description has been provided for this image

 479/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9829 - loss: 0.0583

 516/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9828 - loss: 0.0585

 553/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9827 - loss: 0.0587

 590/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9827 - loss: 0.0589

 627/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9826 - loss: 0.0591

 664/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9826 - loss: 0.0593

 700/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9825 - loss: 0.0594

 736/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9825 - loss: 0.0596

 772/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9825 - loss: 0.0597

 808/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9824 - loss: 0.0598

 844/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9824 - loss: 0.0599

 881/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9824 - loss: 0.0600

 918/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9824 - loss: 0.0600

 956/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9823 - loss: 0.0601

 993/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9823 - loss: 0.0602

1030/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9823 - loss: 0.0603

1067/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9823 - loss: 0.0604

1105/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9823 - loss: 0.0605

1143/1875 ━━━━━━━━━━━━━━━━━━━━ 1s 1ms/step - accuracy: 0.9822 - loss: 0.0606

1181/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0606

1218/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0607

1256/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0608

1295/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0608

1334/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0609

1373/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0609

1412/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0610

1451/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9822 - loss: 0.0610

1489/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0611

1528/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0611

1566/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0612

1603/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0612

1641/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0613

1679/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0613

1718/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0614

1756/1875 ━━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0614

1795/1875 ━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9821 - loss: 0.0614

1833/1875 ━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9820 - loss: 0.0615

1870/1875 ━━━━━━━━━━━━━━━━━━━ 0s 1ms/step - accuracy: 0.9820 - loss: 0.0615

1875/1875 ━━━━━━━━━━━━━━━━━━━━ 3s 2ms/step - accuracy: 0.9820 - loss: 0.0615 - val_accuracy: 0.9797 - val_loss: 0.0668
Out[2]:
<keras.src.callbacks.history.History at 0x7f0f06a4f5b0>
In [3]:
image_list = []  # Initialize an empty list to store the images
label_list = []  # Initialize an empty list to store the labels

for images, labels in val_ds:  # Take the first batch

    for i in range(len(images)):
        image_list.append(images[i].numpy())  # Convert to NumPy and store in the list
        label_list.append(labels[i].numpy())  # Convert to NumPy and store in the list

# Convert the list of NumPy arrays into a single NumPy array

image_array = np.array(image_list)
test_labels = np.array(label_list)

# Now apply astype and normalization
test_images = image_array.astype(np.float32) / 255.0


image_list = []  # Initialize an empty list to store the images
label_list = []  # Initialize an empty list to store the labels

for images, labels in train_ds:  # Take the first batch
    for i in range(len(images)):
        image_list.append(images[i].numpy())  # Convert to NumPy and store in the list
        label_list.append(labels[i].numpy())  # Convert to NumPy and store in the list

# Convert the list of NumPy arrays into a single NumPy array

image_array = np.array(image_list)
train_labels = np.array(label_list)

# Now apply astype and normalization
train_images = image_array.astype(np.float32) / 255.0
In [4]:
image_list = []  # Initialize an empty list to store the images
label_list = []  # Initialize an empty list to store the labels

for images, labels in train_ds:  # Take the first batch
    for i in range(len(images)):
        image_list.append(images[i].numpy())  # Convert to NumPy and store in the list
        label_list.append(labels[i].numpy())  # Convert to NumPy and store in the list

# Convert the list of NumPy arrays into a single NumPy array

image_array = np.array(image_list)
train_labels = np.array(label_list)

# Now apply astype and normalization
train_images = image_array.astype(np.float32) / 255.0

first_image = train_images[0]
print(np.min(first_image), np.max(first_image))
0.2882355 0.99411756

In this step we will do a little data augmentation so that the model does not overfit

In [5]:
# Augment training data

data_augmentation = keras.Sequential(
  [
    layers.RandomFlip("horizontal", input_shape=(img_height, img_width, 3)),
    layers.RandomRotation(0.4),
    layers.RandomZoom(0.1),
  ]
)


# Visualize Change
plt.figure(figsize=(10, 10))
for images, _ in train_ds.take(1):
  for i in range(9):
    augmented_images = data_augmentation(images)
    ax = plt.subplot(3, 3, i + 1)
    plt.imshow(augmented_images[0].numpy().astype("uint8"))
    plt.axis("off")
/home/brickman/miniconda3/envs/openmv_train/lib/python3.10/site-packages/keras/src/layers/preprocessing/tf_data_layer.py:19: UserWarning: Do not pass an `input_shape`/`input_dim` argument to a layer. When using Sequential models, prefer using an `Input(shape)` object as the first layer in the model instead.
  super().__init__(**kwargs)
No description has been provided for this image

Let's set up our model architecture and decide whether we want to use transfer learning or build the model from scratch. Transfer learning may include more overhead for the edge device but is better with less data, making it faster to build and train.

Choose whether you want to use transfer learning by setting the transfer_learning parameter to True or False.

In [6]:
transfer_learning = True

if transfer_learning:
    # Load the pre-trained MobileNetV2 model (excluding the top classification layer)
    base_model = tf.keras.applications.MobileNetV2(input_shape=(img_height, img_width, 3),
                                                   include_top=False,  # Do not include the final classification layer
                                                   weights='imagenet')  # Use weights pre-trained on ImageNet
    
    base_model.trainable = False  # Freeze the base model so its weights won't be updated during training
    
    # Create the model
    model = Sequential([
        data_augmentation,
        base_model,  # Add the pre-trained MobileNetV2
        layers.GlobalAveragePooling2D(),  # Use global average pooling instead of flattening
        layers.Dense(128, activation='relu'),  # Add a fully connected layer
        layers.Dropout(0.2),  # Dropout to reduce overfitting
        layers.Dense(num_classes, name="outputs", activation='softmax')  # Final classification layer (for 10 classes)
    ])

else:
    model = Sequential([
      layers.InputLayer(input_shape(img_height, img_width, 3), batch_size=1),  # Proper InputLayer with batch_size=1
      data_augmentation,
      layers.Conv2D(32, 3, padding='same', activation='relu'),
      layers.MaxPooling2D(),
      layers.Conv2D(64, 3, padding='same', activation='relu'),
      layers.MaxPooling2D(),
      layers.Conv2D(128, 3, padding='same', activation='relu'),
      layers.MaxPooling2D(),
      layers.Dropout(0.2),
      layers.Flatten(),
      layers.Dense(24, activation='relu'),
      layers.Dense(48, activation='relu'),
      layers.Dense(num_classes, name="outputs", activation='softmax')
    ])


# compile the model
model.compile(optimizer='adam',
              loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
              metrics=['accuracy'])


# give a nice summary of the model architecture
model.summary()
/tmp/ipykernel_177727/819969002.py:5: UserWarning: `input_shape` is undefined or non-square, or `rows` is not in [96, 128, 160, 192, 224]. Weights for input shape (224, 224) will be loaded as the default.
  base_model = tf.keras.applications.MobileNetV2(input_shape=(img_height, img_width, 3),
Model: "sequential_1"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓
┃ Layer (type)                     Output Shape                  Param # ┃
┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩
│ sequential (Sequential)         │ (None, 120, 120, 3)    │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ mobilenetv2_1.00_224            │ (None, 4, 4, 1280)     │     2,257,984 │
│ (Functional)                    │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ global_average_pooling2d        │ (None, 1280)           │             0 │
│ (GlobalAveragePooling2D)        │                        │               │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dense (Dense)                   │ (None, 128)            │       163,968 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ dropout (Dropout)               │ (None, 128)            │             0 │
├─────────────────────────────────┼────────────────────────┼───────────────┤
│ outputs (Dense)                 │ (None, 5)              │           645 │
└─────────────────────────────────┴────────────────────────┴───────────────┘
 Total params: 2,422,597 (9.24 MB)
 Trainable params: 164,613 (643.02 KB)
 Non-trainable params: 2,257,984 (8.61 MB)

Training Model

Now that we have setup are model's architecture lets train our model

In [7]:
epochs = 100
history = model.fit(
  train_images,
  train_labels,
  epochs=epochs,
  validation_data=(test_images, test_labels)
)
Epoch 1/100
/home/brickman/miniconda3/envs/openmv_train/lib/python3.10/site-packages/keras/src/backend/tensorflow/nn.py:635: UserWarning: "`sparse_categorical_crossentropy` received `from_logits=True`, but the `output` argument was produced by a Softmax activation and thus does not represent logits. Was this intended?
  output, from_logits = _get_logits(
W0000 00:00:1726357216.800337  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.819953  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.821099  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.828785  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.830769  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.832719  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.834030  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.836192  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.837501  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.855066  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.962140  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.963683  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.966329  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.968056  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.989936  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.991655  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.993431  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.996330  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357216.999003  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.002068  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.005231  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.008253  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.011157  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.013318  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.015547  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.018033  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.021012  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.023248  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.026339  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.029253  177813 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 47ms/step - accuracy: 0.2181 - loss: 2.0655
W0000 00:00:1726357217.334963  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.336193  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.337305  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.338814  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.340084  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.341282  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.342461  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.343583  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.344710  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.345837  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.346965  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.348335  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.349593  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.350913  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.352279  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.353686  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.355036  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.356617  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.357905  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.359370  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.360732  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.362069  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.363444  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.364888  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.366474  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.367893  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.369443  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357217.370858  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
3/3 ━━━━━━━━━━━━━━━━━━━━ 4s 398ms/step - accuracy: 0.2373 - loss: 2.0153 - val_accuracy: 0.4737 - val_loss: 1.2687
Epoch 2/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.7404 - loss: 0.6928 - val_accuracy: 0.6316 - val_loss: 0.8260
Epoch 3/100
W0000 00:00:1726357218.034327  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.035458  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.036568  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.038225  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.039556  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.040762  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.041962  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.043101  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.044236  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.045447  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.046593  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.048033  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.049332  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.050737  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.052219  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.053743  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.055201  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.056975  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.058376  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.059985  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.061481  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.062938  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.064427  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.066005  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.067798  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.069361  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.071101  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
W0000 00:00:1726357218.072682  177812 gpu_timer.cc:114] Skipping the delay kernel, measurement accuracy will be reduced
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.8503 - loss: 0.4061 - val_accuracy: 0.5789 - val_loss: 0.6591
Epoch 4/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.8076 - loss: 0.4528 - val_accuracy: 0.6842 - val_loss: 0.7452
Epoch 5/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9445 - loss: 0.2263 - val_accuracy: 0.7895 - val_loss: 0.5651
Epoch 6/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 38ms/step - accuracy: 0.8965 - loss: 0.2498 - val_accuracy: 0.8421 - val_loss: 0.4142
Epoch 7/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 0.8848 - loss: 0.2633 - val_accuracy: 0.8421 - val_loss: 0.4038
Epoch 8/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9509 - loss: 0.2042 - val_accuracy: 0.8421 - val_loss: 0.3523
Epoch 9/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step - accuracy: 0.8798 - loss: 0.2198 - val_accuracy: 0.8421 - val_loss: 0.3389
Epoch 10/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9534 - loss: 0.1349 - val_accuracy: 0.8421 - val_loss: 0.3604
Epoch 11/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9716 - loss: 0.0719 - val_accuracy: 0.7895 - val_loss: 0.3791
Epoch 12/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9186 - loss: 0.1475 - val_accuracy: 0.8947 - val_loss: 0.3160
Epoch 13/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 0.9250 - loss: 0.1747 - val_accuracy: 0.8947 - val_loss: 0.2067
Epoch 14/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9406 - loss: 0.1366 - val_accuracy: 0.9474 - val_loss: 0.1961
Epoch 15/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step - accuracy: 0.9445 - loss: 0.1685 - val_accuracy: 0.8947 - val_loss: 0.2783
Epoch 16/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9534 - loss: 0.1124 - val_accuracy: 0.8947 - val_loss: 0.2823
Epoch 17/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9819 - loss: 0.1058 - val_accuracy: 0.8947 - val_loss: 0.2889
Epoch 18/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9897 - loss: 0.0564 - val_accuracy: 0.8947 - val_loss: 0.3029
Epoch 19/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 0.9264 - loss: 0.1349 - val_accuracy: 0.8947 - val_loss: 0.2102
Epoch 20/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9637 - loss: 0.0832 - val_accuracy: 0.9474 - val_loss: 0.1600
Epoch 21/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 1.0000 - loss: 0.0557 - val_accuracy: 0.9474 - val_loss: 0.1391
Epoch 22/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9431 - loss: 0.1461 - val_accuracy: 0.8947 - val_loss: 0.1811
Epoch 23/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9665 - loss: 0.0685 - val_accuracy: 0.9474 - val_loss: 0.1729
Epoch 24/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9612 - loss: 0.0803 - val_accuracy: 0.9474 - val_loss: 0.1309
Epoch 25/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9716 - loss: 0.0867 - val_accuracy: 0.9474 - val_loss: 0.1322
Epoch 26/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 1.0000 - loss: 0.0355 - val_accuracy: 0.9474 - val_loss: 0.1303
Epoch 27/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9367 - loss: 0.1395 - val_accuracy: 0.9474 - val_loss: 0.1509
Epoch 28/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 38ms/step - accuracy: 0.9794 - loss: 0.0619 - val_accuracy: 0.8421 - val_loss: 0.2339
Epoch 29/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9651 - loss: 0.0518 - val_accuracy: 0.8421 - val_loss: 0.2864
Epoch 30/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9534 - loss: 0.1049 - val_accuracy: 0.8947 - val_loss: 0.2026
Epoch 31/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 1.0000 - loss: 0.0255 - val_accuracy: 0.9474 - val_loss: 0.1675
Epoch 32/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 30ms/step - accuracy: 0.9637 - loss: 0.0935 - val_accuracy: 0.9474 - val_loss: 0.1276
Epoch 33/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9819 - loss: 0.0436 - val_accuracy: 0.9474 - val_loss: 0.1064
Epoch 34/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9794 - loss: 0.0587 - val_accuracy: 0.9474 - val_loss: 0.1186
Epoch 35/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0234 - val_accuracy: 0.9474 - val_loss: 0.1543
Epoch 36/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9897 - loss: 0.0388 - val_accuracy: 0.8421 - val_loss: 0.2616
Epoch 37/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9716 - loss: 0.0450 - val_accuracy: 0.8421 - val_loss: 0.3819
Epoch 38/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9716 - loss: 0.0580 - val_accuracy: 0.8421 - val_loss: 0.2887
Epoch 39/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0327 - val_accuracy: 0.9474 - val_loss: 0.1340
Epoch 40/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9819 - loss: 0.0443 - val_accuracy: 1.0000 - val_loss: 0.1000
Epoch 41/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9819 - loss: 0.0453 - val_accuracy: 1.0000 - val_loss: 0.0908
Epoch 42/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9936 - loss: 0.0317 - val_accuracy: 0.9474 - val_loss: 0.1173
Epoch 43/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 1.0000 - loss: 0.0393 - val_accuracy: 0.8947 - val_loss: 0.2235
Epoch 44/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9897 - loss: 0.0439 - val_accuracy: 0.8947 - val_loss: 0.2219
Epoch 45/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9819 - loss: 0.0424 - val_accuracy: 0.9474 - val_loss: 0.1414
Epoch 46/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step - accuracy: 0.9819 - loss: 0.0419 - val_accuracy: 0.8947 - val_loss: 0.1344
Epoch 47/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 1.0000 - loss: 0.0116 - val_accuracy: 0.9474 - val_loss: 0.1197
Epoch 48/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9872 - loss: 0.0355 - val_accuracy: 1.0000 - val_loss: 0.0458
Epoch 49/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0174 - val_accuracy: 1.0000 - val_loss: 0.0609
Epoch 50/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9897 - loss: 0.0796 - val_accuracy: 1.0000 - val_loss: 0.0605
Epoch 51/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9637 - loss: 0.1125 - val_accuracy: 1.0000 - val_loss: 0.0857
Epoch 52/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 1.0000 - loss: 0.0073 - val_accuracy: 0.8421 - val_loss: 0.2956
Epoch 53/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 1.0000 - loss: 0.0133 - val_accuracy: 0.8421 - val_loss: 0.5120
Epoch 54/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 1.0000 - loss: 0.0175 - val_accuracy: 0.8421 - val_loss: 0.5815
Epoch 55/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9794 - loss: 0.0523 - val_accuracy: 0.8421 - val_loss: 0.2835
Epoch 56/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 28ms/step - accuracy: 0.9819 - loss: 0.0399 - val_accuracy: 0.9474 - val_loss: 0.0811
Epoch 57/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9936 - loss: 0.0282 - val_accuracy: 1.0000 - val_loss: 0.0485
Epoch 58/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9819 - loss: 0.0518 - val_accuracy: 0.9474 - val_loss: 0.0833
Epoch 59/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 1.0000 - loss: 0.0224 - val_accuracy: 0.8947 - val_loss: 0.1869
Epoch 60/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9819 - loss: 0.0641 - val_accuracy: 0.8947 - val_loss: 0.1960
Epoch 61/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9936 - loss: 0.0185 - val_accuracy: 0.8947 - val_loss: 0.2296
Epoch 62/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 1.0000 - loss: 0.0176 - val_accuracy: 0.8947 - val_loss: 0.2455
Epoch 63/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9897 - loss: 0.0347 - val_accuracy: 0.9474 - val_loss: 0.1655
Epoch 64/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 37ms/step - accuracy: 1.0000 - loss: 0.0240 - val_accuracy: 0.9474 - val_loss: 0.0992
Epoch 65/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 30ms/step - accuracy: 0.9819 - loss: 0.0640 - val_accuracy: 0.8947 - val_loss: 0.1745
Epoch 66/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9936 - loss: 0.0290 - val_accuracy: 0.8947 - val_loss: 0.1984
Epoch 67/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9716 - loss: 0.0526 - val_accuracy: 0.8947 - val_loss: 0.1530
Epoch 68/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0082 - val_accuracy: 0.8947 - val_loss: 0.1839
Epoch 69/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 0.9936 - loss: 0.0211 - val_accuracy: 0.8947 - val_loss: 0.1748
Epoch 70/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9819 - loss: 0.0434 - val_accuracy: 1.0000 - val_loss: 0.0406
Epoch 71/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9936 - loss: 0.0144 - val_accuracy: 1.0000 - val_loss: 0.0327
Epoch 72/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9819 - loss: 0.0381 - val_accuracy: 1.0000 - val_loss: 0.0354
Epoch 73/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0129 - val_accuracy: 1.0000 - val_loss: 0.0431
Epoch 74/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9819 - loss: 0.0261 - val_accuracy: 0.9474 - val_loss: 0.0838
Epoch 75/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 0.9936 - loss: 0.0191 - val_accuracy: 0.9474 - val_loss: 0.0921
Epoch 76/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 1.0000 - loss: 0.0163 - val_accuracy: 0.9474 - val_loss: 0.0705
Epoch 77/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9819 - loss: 0.0398 - val_accuracy: 1.0000 - val_loss: 0.0305
Epoch 78/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 1.0000 - loss: 0.0062 - val_accuracy: 1.0000 - val_loss: 0.0220
Epoch 79/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 30ms/step - accuracy: 1.0000 - loss: 0.0081 - val_accuracy: 1.0000 - val_loss: 0.0310
Epoch 80/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9897 - loss: 0.0317 - val_accuracy: 1.0000 - val_loss: 0.0296
Epoch 81/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 1.0000 - loss: 0.0135 - val_accuracy: 1.0000 - val_loss: 0.0430
Epoch 82/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9819 - loss: 0.0453 - val_accuracy: 1.0000 - val_loss: 0.0502
Epoch 83/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 1.0000 - loss: 0.0103 - val_accuracy: 1.0000 - val_loss: 0.0567
Epoch 84/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 33ms/step - accuracy: 1.0000 - loss: 0.0137 - val_accuracy: 0.9474 - val_loss: 0.0686
Epoch 85/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0110 - val_accuracy: 0.9474 - val_loss: 0.0707
Epoch 86/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 30ms/step - accuracy: 0.9534 - loss: 0.0879 - val_accuracy: 1.0000 - val_loss: 0.0606
Epoch 87/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step - accuracy: 1.0000 - loss: 0.0065 - val_accuracy: 1.0000 - val_loss: 0.0367
Epoch 88/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 1.0000 - loss: 0.0108 - val_accuracy: 1.0000 - val_loss: 0.0265
Epoch 89/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 30ms/step - accuracy: 1.0000 - loss: 0.0051 - val_accuracy: 1.0000 - val_loss: 0.0277
Epoch 90/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9897 - loss: 0.0246 - val_accuracy: 1.0000 - val_loss: 0.0157
Epoch 91/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 32ms/step - accuracy: 1.0000 - loss: 0.0144 - val_accuracy: 1.0000 - val_loss: 0.0152
Epoch 92/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 1.0000 - loss: 0.0042 - val_accuracy: 1.0000 - val_loss: 0.0228
Epoch 93/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 0.9897 - loss: 0.0215 - val_accuracy: 1.0000 - val_loss: 0.0461
Epoch 94/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 34ms/step - accuracy: 1.0000 - loss: 0.0045 - val_accuracy: 0.9474 - val_loss: 0.0861
Epoch 95/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 31ms/step - accuracy: 1.0000 - loss: 0.0142 - val_accuracy: 0.8947 - val_loss: 0.1580
Epoch 96/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step - accuracy: 1.0000 - loss: 0.0039 - val_accuracy: 0.8947 - val_loss: 0.1995
Epoch 97/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9819 - loss: 0.0465 - val_accuracy: 0.8947 - val_loss: 0.1079
Epoch 98/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 36ms/step - accuracy: 0.9936 - loss: 0.0257 - val_accuracy: 0.9474 - val_loss: 0.1108
Epoch 99/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 0.9936 - loss: 0.0122 - val_accuracy: 0.8947 - val_loss: 0.2087
Epoch 100/100
3/3 ━━━━━━━━━━━━━━━━━━━━ 0s 35ms/step - accuracy: 1.0000 - loss: 0.0078 - val_accuracy: 0.8947 - val_loss: 0.2261

Visualize training results

Create plots of the loss and accuracy on the training and validation sets:

In [8]:
acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

epochs_range = range(epochs)

plt.figure(figsize=(15, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.show()
No description has been provided for this image

Convert to a TensorFlow Lite model

Convert using integer-only quantization

To quantize the variable data (such as model input/output and intermediates between layers), you need to provide a RepresentativeDataset. This is a generator function that provides a set of input data that's large enough to represent typical values. It allows the converter to estimate a dynamic range for all the variable data. (The dataset does not need to be unique compared to the training or evaluation dataset.) To support multiple inputs, each representative data point is a list and elements in the list are fed to the model according to their indices.

To quantize the input and output tensors, and make the converter throw an error if it encounters an operation it cannot quantize, convert the model again with some additional parameters:

In [9]:
def representative_data_gen():
  for input_value in tf.data.Dataset.from_tensor_slices(train_images).batch(1).take(100):
    yield [input_value]

converter = tf.lite.TFLiteConverter.from_keras_model(model)

converter._experimental_disable_per_channel_quantization_for_dense_layers = True

converter.optimizations = [tf.lite.Optimize.DEFAULT]
converter.representative_dataset = representative_data_gen
converter.target_spec.supported_ops = [tf.lite.OpsSet.TFLITE_BUILTINS_INT8]
converter.target_spec.supported_types = [tf.int8]
converter.inference_input_type = tf.uint8
converter.inference_output_type = tf.uint8
tflite_model_quant = converter.convert()
INFO:tensorflow:Assets written to: /tmp/tmpurjcrmlo/assets
INFO:tensorflow:Assets written to: /tmp/tmpurjcrmlo/assets
Saved artifact at '/tmp/tmpurjcrmlo'. The following endpoints are available:

* Endpoint 'serve'
  args_0 (POSITIONAL_ONLY): TensorSpec(shape=(None, 120, 120, 3), dtype=tf.float32, name='keras_tensor_158')
Output Type:
  TensorSpec(shape=(None, 5), dtype=tf.float32, name=None)
Captures:
  131556059225376: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556070830352: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556070832640: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556070827712: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556070831936: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556070830176: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061018800: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061017744: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061014400: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061009472: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061012288: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061010704: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061005248: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061009296: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061013520: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061005952: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061284832: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061282896: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061282544: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061285008: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061293104: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061292048: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061294688: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061284480: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061292576: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061297680: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061121168: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061119232: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061121520: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061121344: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061126976: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061125920: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061128384: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061124512: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061127152: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061134368: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061130848: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061130496: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061131552: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061130320: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061129968: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060929664: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060930720: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060926848: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060929488: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060936704: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060935648: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060932128: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060934240: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060936880: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556060934592: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059257088: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059259728: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059255680: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059257616: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059265888: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059264832: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059261312: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059253744: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059266064: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061130144: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059321744: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059322800: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059318928: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059321568: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059328784: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059327728: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059330368: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059319280: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059328256: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059324384: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059353456: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059353104: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059350640: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059353280: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059360672: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059359616: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059362080: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059358208: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059360848: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059364896: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061775472: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061775296: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061776704: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061777232: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061784448: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061783392: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061785856: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061781984: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556059364016: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061781632: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061907248: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061905312: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061787968: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061907424: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061915696: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061914640: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061917280: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061907776: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061915168: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061920272: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061743760: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061741824: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061744112: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061743936: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061749568: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061748512: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061750976: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061747104: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061749744: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061756960: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061753440: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061753088: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061754144: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061752912: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061752560: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062486144: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062487200: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062483328: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062485968: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062493360: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062492304: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062488784: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062490896: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062493536: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556062491248: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061631888: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061633648: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061631536: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061632064: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061640336: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061639280: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061641744: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061629424: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061640512: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061628192: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061484608: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061485664: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061481792: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061484432: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061491648: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061490592: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061493232: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061482144: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061491120: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556061487248: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066710048: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066709696: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066707232: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066709872: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066717264: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066716208: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066718672: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066714800: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066717440: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066721488: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066182944: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066185056: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066181184: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066184704: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066191920: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066190864: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066193328: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066189456: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066192096: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066189104: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065756256: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066190688: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066195968: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065755200: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066196496: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065762240: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065764880: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065760832: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065762768: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065771040: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065761184: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065766464: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065768224: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556065766992: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066720432: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066615264: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066616144: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066617728: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066615616: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066611920: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066610160: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066612800: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066616496: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066614560: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066613504: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066531760: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066532816: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066528944: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066531584: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066538976: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066537920: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066540384: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066536512: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066539152: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066536864: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066268384: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066271024: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066266976: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066268912: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066277184: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066276128: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066278592: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066265040: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066277360: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066611216: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066365808: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066365456: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066362992: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066365632: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066372848: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066371792: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066374432: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066363344: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066372320: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556066377424: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057320784: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057318320: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057317440: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057320960: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057328000: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057326944: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057329408: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057325536: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057328176: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057332224: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057367120: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057366768: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057331344: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057368880: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057376096: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057375040: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057377504: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057373632: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057376272: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057373280: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057384208: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057384560: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057381552: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057382976: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057379616: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057390192: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057392832: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057388784: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057390720: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057398992: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057389136: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057394416: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057396176: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057449040: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057331168: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057455024: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057456080: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057452208: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057454848: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057463648: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057679648: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057678944: TensorSpec(shape=(), dtype=tf.resource, name=None)
  131556057682464: TensorSpec(shape=(), dtype=tf.resource, name=None)
/home/brickman/miniconda3/envs/openmv_train/lib/python3.10/site-packages/tensorflow/lite/python/convert.py:983: UserWarning: Statistics for quantized inputs were expected, but not specified; continuing anyway.
  warnings.warn(
WARNING: All log messages before absl::InitializeLog() is called are written to STDERR
W0000 00:00:1726357234.059892  177727 tf_tfl_flatbuffer_helpers.cc:392] Ignored output_format.
W0000 00:00:1726357234.059913  177727 tf_tfl_flatbuffer_helpers.cc:395] Ignored drop_control_dependency.
fully_quantize: 0, inference_type: 6, input_inference_type: UINT8, output_inference_type: UINT8

The internal quantization remains the same as above, but you can see the input and output tensors are now integer format:

In [10]:
interpreter = tf.lite.Interpreter(model_content=tflite_model_quant)
input_type = interpreter.get_input_details()[0]['dtype']
print('input: ', input_type)
output_type = interpreter.get_output_details()[0]['dtype']
print('output: ', output_type)
input:  <class 'numpy.uint8'>
output:  <class 'numpy.uint8'>

Now you have an integer quantized model that uses integer data for the model's input and output tensors, so it's compatible with integer-only hardware such as the Edge TPU.

Save the models as files

You'll need a .tflite file to deploy your model on other devices. So let's save the converted model to a file and then load it when we run inferences below.

In [11]:
import pathlib

tflite_models_dir = pathlib.Path("models/")
tflite_models_dir.mkdir(exist_ok=True, parents=True)

# Save the quantized model:
tflite_model_quant_file = tflite_models_dir/"model_quant.tflite"
tflite_model_quant_file.write_bytes(tflite_model_quant)
Out[11]:
2876048

Run the TensorFlow Lite model

Now we'll run inferences using the TensorFlow Lite Interpreter to confirm our model's accuracy.

First, we need a function that runs inference with the model and images, and then return the predictions:

In [12]:
# Helper function to run inference on a TFLite model
def run_tflite_model(tflite_file, test_image_indices):
  global test_images

  # Initialize the interpreter
  interpreter = tf.lite.Interpreter(model_path=str(tflite_file))
  interpreter.allocate_tensors()

  input_details = interpreter.get_input_details()[0]
  output_details = interpreter.get_output_details()[0]


  predictions = np.zeros((len(test_image_indices),), dtype=int)
  for i, test_image_index in enumerate(test_image_indices):
    test_image = test_images[test_image_index]

    # Check if the input type is quantized, then rescale input data to uint8
    if input_details['dtype'] == np.uint8:
      input_scale, input_zero_point = input_details["quantization"]
      test_image = test_image / input_scale + input_zero_point

    test_image = np.expand_dims(test_image, axis=0).astype(input_details["dtype"])
      
    interpreter.set_tensor(input_details["index"], test_image)
    interpreter.invoke()
    output = interpreter.get_tensor(output_details["index"])[0]


    predictions[i] = output.argmax()

  return predictions

Testing the model on one image

Now we'll test the performance of the model.

Let's create another function to print our predictions:

In [13]:
import matplotlib.pylab as plt

# Change this to test a different image
test_image_index = 18

## Helper function to test the models on one image
def test_model(tflite_file, test_image_index):
  global test_labels

  predictions = run_tflite_model(tflite_file, [test_image_index])


  plt.imshow(test_images[test_image_index])
  template = " Model \n True: {true}, Predicted: {predict}"
  _ = plt.title(template.format(true= str(class_names[test_labels[test_image_index]]), predict=str(class_names[predictions[0]])))
  plt.grid(False)

And test the model on an image:

In [14]:
test_model(tflite_model_quant_file, test_image_index)
INFO: Created TensorFlow Lite XNNPACK delegate for CPU.
No description has been provided for this image

Evaluate the model on all images

Now let's run the model using all the test images we loaded at the beginning:

In [15]:
# Helper function to evaluate a TFLite model on all images
def evaluate_model(tflite_file, model_type):
  global test_images
  global test_labels

  test_image_indices = range(test_images.shape[0])
  predictions = run_tflite_model(tflite_file, test_image_indices)

  accuracy = (np.sum(test_labels== predictions) * 100) / len(test_images)

  print('%s model accuracy is %.4f%% (Number of test samples=%d)' % (
      model_type, accuracy, len(test_images)))

Evaluate the model:

In [16]:
evaluate_model(tflite_model_quant_file, model_type="Quantized")
Quantized model accuracy is 84.2105% (Number of test samples=19)
</html>