Skip to content

Fashion Classification

Multi-class classification using neural networks.

Complementary material:

Append notebooks directory to sys.path

1
2
3
import sys

sys.path.append("../../..")

Install packages

1
2
3
4
5
6
7
8
9
!uv pip install -q \
    python-dotenv==1.2.1 \
    pandas==2.3.2 \
    pandas-stubs==2.3.2.250827 \
    numpy==2.3.2 \
    matplotlib==3.10.6 \
    seaborn==0.13.2 \
    tensorflow==2.20.0 \
    scipy==1.16.3

Import packages

import os
import pathlib
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.preprocessing.image import load_img
from tensorflow.keras.applications.xception import (
     Xception, preprocess_input, decode_predictions
)
from tensorflow.keras.preprocessing.image import ImageDataGenerator

pd.set_option("display.max_columns", None)

sns.set_style("darkgrid")
sns.set_theme(style="darkgrid")

%matplotlib inline
2025-12-31 09:38:27.922913: I external/local_xla/xla/tsl/cuda/cudart_stub.cc:31] Could not find cuda drivers on your machine, GPU will not be used.

2025-12-31 09:38:30.448559: I tensorflow/core/platform/cpu_feature_guard.cc:210] This TensorFlow binary is optimized to use available CPU instructions in performance-critical operations.

To enable the following instructions: AVX2 FMA, in other operations, rebuild TensorFlow with the appropriate compiler flags.

2025-12-31 09:38:42.180428: I external/local_xla/xla/tsl/cuda/cudart_stub.cc:31] Could not find cuda drivers on your machine, GPU will not be used.

/home/gabrieldmenezes/.cache/uv/builds-v0/.tmpUBIVWs/lib/python3.11/site-packages/keras/src/export/tf2onnx_lib.py:8: FutureWarning: In the future `np.object` will be defined as the corresponding NumPy scalar.

  if not hasattr(np, "object"):

Create data directory

1
2
3
DATA_DIR = pathlib.Path("data/fashion-classification")

os.makedirs(DATA_DIR, exist_ok=True)

Download images from github repository

!git clone https://github.com/alexeygrigorev/clothing-dataset-small $DATA_DIR --depth 1
fatal: destination path 'data/fashion-classification' already exists and is not an empty directory.

Loading an image

1
2
3
4
file_name = "5f0a3fa0-6a3d-4b68-b213-72766a643de7.jpg"
path = DATA_DIR / "train" / "t-shirt" / file_name
img = load_img(path, target_size=(299, 299))
img
<PIL.Image.Image image mode=RGB size=299x299>

Check image object

print(img)
<PIL.Image.Image image mode=RGB size=299x299 at 0x77FED8EBA450>

Seeing the image as array, each array contains 3 values (RGB)

np.array(img)[:3, :3, :]
array([[[179, 171,  99],
        [179, 171,  99],
        [181, 173, 101]],

       [[188, 179, 112],
        [187, 178, 111],
        [186, 177, 108]],

       [[199, 189, 127],
        [200, 190, 128],
        [200, 191, 126]]], dtype=uint8)

Array size

x = np.array(img)
x.shape
(299, 299, 3)

Pre-trained convolutional neural networks

Instance model

model = Xception(weights="imagenet", input_shape=(299, 299, 3))
2025-12-30 08:54:47.542447: E external/local_xla/xla/stream_executor/cuda/cuda_platform.cc:51] failed call to cuInit: INTERNAL: CUDA error: Failed call to cuInit: UNKNOWN ERROR (303)

Check X shape

X = np.array([x])
X.shape
(1, 299, 299, 3)

Preprocess the image to fit the model input requirements

Instead of 0 - 255 (RGB), values should be between -1 and 1

X = preprocess_input(X)
X[:, :3, :3, :]
array([[[[ 0.4039216 ,  0.3411765 , -0.2235294 ],
         [ 0.4039216 ,  0.3411765 , -0.2235294 ],
         [ 0.41960788,  0.35686278, -0.20784312]],

        [[ 0.47450984,  0.4039216 , -0.12156862],
         [ 0.4666667 ,  0.39607847, -0.12941176],
         [ 0.45882356,  0.38823533, -0.15294117]],

        [[ 0.56078434,  0.48235297, -0.00392157],
         [ 0.5686275 ,  0.4901961 ,  0.00392163],
         [ 0.5686275 ,  0.49803925, -0.01176471]]]], dtype=float32)

Predict

pred = model.predict(X)
pred.shape
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 953ms/step
(1, 1000)

Decode predictions

decode_predictions(pred)
[[('n03595614', 'jersey', np.float32(0.68196267)),
  ('n02916936', 'bulletproof_vest', np.float32(0.03814007)),
  ('n04370456', 'sweatshirt', np.float32(0.03432477)),
  ('n03710637', 'maillot', np.float32(0.011354245)),
  ('n04525038', 'velvet', np.float32(0.0018453626))]]

Convolutional Neural Networks (CNNs)

  • Convolutional layers
  • Dense Layers
  • Pooling Layers

Convolutional Layers

Convolultional layers are based in filters (kernels) that slide through the input data to extract features.

For each part of the input data and each filter, is calculated the similarity between the filter and the input data.

As result, we have a feature map that indicates where the feature represented by the filter is found in the input data.

High values in the feature map indicate high similarity between the filter and the input data.

At the end we have several feature maps, one for each filter.

Then another layer can be added to extract more complex features based on the previous feature maps and so on.

The final result is a vector that represents the input data in terms of the features extracted by the filters.

Dense Layers

Dense layers connect each element of input data to each element of output data.

There are a lot of connections and each connection has a weight that indicates the importance of that connection.

Pooling Layers

Pooling layers are used to reduce the size of the input data.

Transfer Learning

  • Use the convolutional base of a pre-trained model
  • Add custom dense layers on top
  • Train only the custom layers
1
2
3
train_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input,
)
1
2
3
4
5
train_dataset = train_generator.flow_from_directory(
    DATA_DIR / "train",
    target_size=(150, 150),
    batch_size=32,
)
Found 3068 images belonging to 10 classes.

Class names are inferred from the directory structure

train_dataset.class_indices
{'dress': 0,
 'hat': 1,
 'longsleeve': 2,
 'outwear': 3,
 'pants': 4,
 'shirt': 5,
 'shoes': 6,
 'shorts': 7,
 'skirt': 8,
 't-shirt': 9}

Folders

!ls $DATA_DIR/train
dress  hat  longsleeve  outwear  pants  shirt  shoes  shorts  skirt  t-shirt

Validation Data

validation_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input,
)

validation_dataset = validation_generator.flow_from_directory(
    DATA_DIR / "validation",
    target_size=(150, 150),
    batch_size=32,
    shuffle=False,
)
Found 341 images belonging to 10 classes.

Setup model for transfer learning

1
2
3
4
5
6
7
base_model = Xception(
    weights="imagenet",
    include_top=False,  # Top means the dense layers
    input_shape=(150, 150, 3),
)

base_model.trainable = False  # Do not train the convolutional base

Define model

inputs = keras.Input(shape=(150, 150, 3))

base = base_model(inputs, training=False)  # 3 Dimensional

pooling = keras.layers.GlobalAveragePooling2D()

vectors = pooling(base)  # 2 Dimensional

outputs = keras.layers.Dense(10)(vectors)

model = keras.Model(inputs, outputs)

Define optimizer and loss function

1
2
3
4
learning_rate = 0.01
optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

loss = keras.losses.CategoricalCrossentropy(from_logits=True)

Compile model

model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])

Train model

1
2
3
4
5
history = model.fit(
    train_dataset,
    epochs=10,  # Go through the dataset 10 times
    validation_data=validation_dataset,
)
Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 74s 738ms/step - accuracy: 0.6640 - loss: 1.3232 - val_accuracy: 0.7302 - val_loss: 1.0214

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 73s 762ms/step - accuracy: 0.8312 - loss: 0.5431 - val_accuracy: 0.7889 - val_loss: 0.8865

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.8915 - loss: 0.3086 - val_accuracy: 0.7654 - val_loss: 0.9782

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 790ms/step - accuracy: 0.9133 - loss: 0.2490 - val_accuracy: 0.7889 - val_loss: 0.8459

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 790ms/step - accuracy: 0.9355 - loss: 0.1825 - val_accuracy: 0.7889 - val_loss: 0.9866

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 75s 786ms/step - accuracy: 0.9544 - loss: 0.1289 - val_accuracy: 0.8006 - val_loss: 0.9130

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 789ms/step - accuracy: 0.9677 - loss: 0.0855 - val_accuracy: 0.8182 - val_loss: 0.8773

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 788ms/step - accuracy: 0.9899 - loss: 0.0419 - val_accuracy: 0.8094 - val_loss: 0.8750

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 75s 785ms/step - accuracy: 0.9935 - loss: 0.0344 - val_accuracy: 0.8094 - val_loss: 0.8731

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 75s 780ms/step - accuracy: 0.9967 - loss: 0.0262 - val_accuracy: 0.8152 - val_loss: 0.9464

1
2
3
4
5
6
7
plt.plot(history.history["accuracy"], label="accuracy")
plt.plot(history.history["val_accuracy"], label="val_accuracy")
plt.xticks(range(10))
plt.xlabel("Epoch")
plt.ylabel("Accuracy")
plt.legend()
plt.show()
output_50_0.png

Adjusting Learning Rate

We can do an analogy to learning rate as how fast you can read a book, if you read to much books very fast when you need to apply the knowledge you may not have learned the necessary, also if you read to slow, you may not have acquire enough knowledge and will also perform poorly.

  • Too high learning rate may overfit the model
  • Too low learning rate may underfit the model
def make_model(learning_rate=0.01):
    base_model = Xception(
        weights="imagenet", include_top=False, input_shape=(150, 150, 3)
    )

    base_model.trainable = False

    inputs = keras.Input(shape=(150, 150, 3))
    base = base_model(inputs, training=False)
    vectors = keras.layers.GlobalAveragePooling2D()(base)
    outputs = keras.layers.Dense(10)(vectors)

    model = keras.Model(inputs, outputs)

    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

    loss = keras.losses.CategoricalCrossentropy(from_logits=True)

    model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])

    return model

Try different learning rates

scores = {}

for learning_rate in [0.0001, 0.001, 0.01, 0.1]:
    print(learning_rate)

    model = make_model(learning_rate=learning_rate)
    history = model.fit(
        train_dataset, epochs=10, validation_data=validation_dataset
    )
    scores[learning_rate] = history.history

    print(20 * "=")
0.0001

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 764ms/step - accuracy: 0.3892 - loss: 1.8841 - val_accuracy: 0.5191 - val_loss: 1.5799

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 74s 770ms/step - accuracy: 0.5704 - loss: 1.3781 - val_accuracy: 0.6217 - val_loss: 1.2411

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 73s 765ms/step - accuracy: 0.6424 - loss: 1.1424 - val_accuracy: 0.6950 - val_loss: 1.0613

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 73s 764ms/step - accuracy: 0.6806 - loss: 1.0059 - val_accuracy: 0.7155 - val_loss: 0.9513

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 73s 762ms/step - accuracy: 0.7145 - loss: 0.9126 - val_accuracy: 0.7390 - val_loss: 0.8816

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 134s 1s/step - accuracy: 0.7301 - loss: 0.8446 - val_accuracy: 0.7683 - val_loss: 0.8208

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 798ms/step - accuracy: 0.7389 - loss: 0.7931 - val_accuracy: 0.7771 - val_loss: 0.7871

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.7552 - loss: 0.7502 - val_accuracy: 0.7830 - val_loss: 0.7541

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 803ms/step - accuracy: 0.7689 - loss: 0.7145 - val_accuracy: 0.7713 - val_loss: 0.7288

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 800ms/step - accuracy: 0.7787 - loss: 0.6827 - val_accuracy: 0.7771 - val_loss: 0.7122

====================

0.001

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 803ms/step - accuracy: 0.6268 - loss: 1.0997 - val_accuracy: 0.7478 - val_loss: 0.7258

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 796ms/step - accuracy: 0.7852 - loss: 0.6297 - val_accuracy: 0.7947 - val_loss: 0.6415

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 797ms/step - accuracy: 0.8315 - loss: 0.5074 - val_accuracy: 0.8006 - val_loss: 0.5809

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 797ms/step - accuracy: 0.8664 - loss: 0.4266 - val_accuracy: 0.8065 - val_loss: 0.5609

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.8898 - loss: 0.3676 - val_accuracy: 0.8094 - val_loss: 0.5695

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.9061 - loss: 0.3259 - val_accuracy: 0.8270 - val_loss: 0.5393

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 800ms/step - accuracy: 0.9218 - loss: 0.2921 - val_accuracy: 0.8211 - val_loss: 0.5435

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 802ms/step - accuracy: 0.9368 - loss: 0.2577 - val_accuracy: 0.8182 - val_loss: 0.5506

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.9430 - loss: 0.2300 - val_accuracy: 0.8152 - val_loss: 0.5296

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 803ms/step - accuracy: 0.9508 - loss: 0.2145 - val_accuracy: 0.8240 - val_loss: 0.5458

====================

0.01

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 813ms/step - accuracy: 0.6747 - loss: 1.2486 - val_accuracy: 0.7625 - val_loss: 0.9220

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 803ms/step - accuracy: 0.8227 - loss: 0.5599 - val_accuracy: 0.7625 - val_loss: 0.9899

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 805ms/step - accuracy: 0.8827 - loss: 0.3497 - val_accuracy: 0.7889 - val_loss: 0.8677

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9254 - loss: 0.2295 - val_accuracy: 0.7859 - val_loss: 0.9640

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.9384 - loss: 0.1636 - val_accuracy: 0.8094 - val_loss: 0.8942

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 803ms/step - accuracy: 0.9436 - loss: 0.1531 - val_accuracy: 0.7977 - val_loss: 0.9416

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9609 - loss: 0.0977 - val_accuracy: 0.8035 - val_loss: 0.9496

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 802ms/step - accuracy: 0.9782 - loss: 0.0664 - val_accuracy: 0.8152 - val_loss: 0.9223

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9886 - loss: 0.0395 - val_accuracy: 0.8065 - val_loss: 0.9262

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9964 - loss: 0.0251 - val_accuracy: 0.8006 - val_loss: 0.9117

====================

0.1

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 816ms/step - accuracy: 0.6444 - loss: 9.5137 - val_accuracy: 0.7302 - val_loss: 7.9670

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 808ms/step - accuracy: 0.7774 - loss: 5.0173 - val_accuracy: 0.7537 - val_loss: 6.7191

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 809ms/step - accuracy: 0.8250 - loss: 3.8600 - val_accuracy: 0.7449 - val_loss: 9.0268

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.8693 - loss: 2.6443 - val_accuracy: 0.7449 - val_loss: 8.2813

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.8999 - loss: 1.7828 - val_accuracy: 0.7713 - val_loss: 7.8167

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9035 - loss: 1.6880 - val_accuracy: 0.7537 - val_loss: 9.4322

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.9130 - loss: 1.7304 - val_accuracy: 0.7507 - val_loss: 9.9843

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.9270 - loss: 1.3411 - val_accuracy: 0.8006 - val_loss: 9.0324

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 805ms/step - accuracy: 0.9374 - loss: 1.1541 - val_accuracy: 0.7801 - val_loss: 9.0159

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 808ms/step - accuracy: 0.9488 - loss: 0.9243 - val_accuracy: 0.7566 - val_loss: 12.3442

====================

1
2
3
4
5
6
7
8
for learning_rate, history in scores.items():
    # plt.plot(history["accuracy"], label=f"train: {learning_rate}")
    plt.plot(history["val_accuracy"], label=f"validation: {learning_rate}")


plt.xticks(np.arange(10))
plt.legend()
plt.show()
output_55_0.png

learning_rate = 0.001

Checkpointing

Saving the model on a specific iteration when certain conditions are meet

1
2
3
4
5
6
checkpoint = keras.callbacks.ModelCheckpoint(
    "xception_v1_{epoch:02d}_{val_accuracy:.3f}.h5",
    save_best_only=True,
    monitor="val_accuracy",
    mode="max",
)
1
2
3
4
5
6
7
model = make_model(learning_rate=learning_rate)
history = model.fit(
    train_dataset,
    epochs=10,
    validation_data=validation_dataset,
    callbacks=[checkpoint],
)
Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 708ms/step - accuracy: 0.4990 - loss: 1.5025
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 800ms/step - accuracy: 0.6248 - loss: 1.1180 - val_accuracy: 0.7801 - val_loss: 0.7236

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 706ms/step - accuracy: 0.7790 - loss: 0.6416
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 789ms/step - accuracy: 0.7790 - loss: 0.6345 - val_accuracy: 0.8006 - val_loss: 0.6582

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 707ms/step - accuracy: 0.8368 - loss: 0.4947
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 789ms/step - accuracy: 0.8305 - loss: 0.5091 - val_accuracy: 0.8123 - val_loss: 0.5879

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 75s 787ms/step - accuracy: 0.8618 - loss: 0.4309 - val_accuracy: 0.8035 - val_loss: 0.6221

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 708ms/step - accuracy: 0.8907 - loss: 0.3613
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 790ms/step - accuracy: 0.8830 - loss: 0.3725 - val_accuracy: 0.8211 - val_loss: 0.5622

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 790ms/step - accuracy: 0.9061 - loss: 0.3258 - val_accuracy: 0.8211 - val_loss: 0.5430

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 789ms/step - accuracy: 0.9140 - loss: 0.2925 - val_accuracy: 0.8211 - val_loss: 0.5408

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 790ms/step - accuracy: 0.9276 - loss: 0.2617 - val_accuracy: 0.8006 - val_loss: 0.5494

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 725ms/step - accuracy: 0.9413 - loss: 0.2293
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 812ms/step - accuracy: 0.9407 - loss: 0.2331 - val_accuracy: 0.8270 - val_loss: 0.5478

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 735ms/step - accuracy: 0.9587 - loss: 0.2026
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9514 - loss: 0.2134 - val_accuracy: 0.8299 - val_loss: 0.5640

Adding more layers

def make_model(learning_rate=0.01, size_inner=100):
    base_model = Xception(
        weights="imagenet", include_top=False, input_shape=(150, 150, 3)
    )

    base_model.trainable = False

    inputs = keras.Input(shape=(150, 150, 3))
    base = base_model(inputs, training=False)
    vectors = keras.layers.GlobalAveragePooling2D()(base)

    inner = keras.layers.Dense(size_inner, activation="relu")(vectors)

    outputs = keras.layers.Dense(10)(inner)

    model = keras.Model(inputs, outputs)

    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

    loss = keras.losses.CategoricalCrossentropy(from_logits=True)

    model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])

    return model

Try different sizes

scores = {}

for size in [10, 100, 1000]:
    print(size)

    model = make_model(learning_rate=learning_rate, size_inner=size)
    history = model.fit(
        train_dataset, epochs=10, validation_data=validation_dataset
    )
    scores[size] = history.history

    print(20 * "=")
10

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 811ms/step - accuracy: 0.5098 - loss: 1.4685 - val_accuracy: 0.6188 - val_loss: 1.0868

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 804ms/step - accuracy: 0.7151 - loss: 0.9091 - val_accuracy: 0.7361 - val_loss: 0.8299

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 802ms/step - accuracy: 0.7764 - loss: 0.6887 - val_accuracy: 0.7478 - val_loss: 0.7325

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.8214 - loss: 0.5709 - val_accuracy: 0.7859 - val_loss: 0.6571

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.8507 - loss: 0.4807 - val_accuracy: 0.7801 - val_loss: 0.6294

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 802ms/step - accuracy: 0.8807 - loss: 0.4144 - val_accuracy: 0.7801 - val_loss: 0.6495

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 800ms/step - accuracy: 0.8882 - loss: 0.3663 - val_accuracy: 0.8065 - val_loss: 0.5826

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 797ms/step - accuracy: 0.9097 - loss: 0.3214 - val_accuracy: 0.8094 - val_loss: 0.5996

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 796ms/step - accuracy: 0.9221 - loss: 0.2861 - val_accuracy: 0.7830 - val_loss: 0.6398

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 797ms/step - accuracy: 0.9286 - loss: 0.2588 - val_accuracy: 0.8240 - val_loss: 0.5776

====================

100

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 802ms/step - accuracy: 0.6744 - loss: 0.9782 - val_accuracy: 0.7683 - val_loss: 0.6640

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 796ms/step - accuracy: 0.8331 - loss: 0.4993 - val_accuracy: 0.7947 - val_loss: 0.6025

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 795ms/step - accuracy: 0.8810 - loss: 0.3680 - val_accuracy: 0.8270 - val_loss: 0.5472

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 795ms/step - accuracy: 0.9228 - loss: 0.2548 - val_accuracy: 0.8065 - val_loss: 0.5329

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 835ms/step - accuracy: 0.9544 - loss: 0.1740 - val_accuracy: 0.8299 - val_loss: 0.5415

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 831ms/step - accuracy: 0.9668 - loss: 0.1293 - val_accuracy: 0.8152 - val_loss: 0.5332

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 830ms/step - accuracy: 0.9840 - loss: 0.0885 - val_accuracy: 0.8065 - val_loss: 0.5607

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 830ms/step - accuracy: 0.9915 - loss: 0.0609 - val_accuracy: 0.7889 - val_loss: 0.6016

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 832ms/step - accuracy: 0.9971 - loss: 0.0454 - val_accuracy: 0.8035 - val_loss: 0.5859

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 809ms/step - accuracy: 0.9987 - loss: 0.0319 - val_accuracy: 0.8152 - val_loss: 0.6155

====================

1000

Epoch 1/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 818ms/step - accuracy: 0.6930 - loss: 0.9262 - val_accuracy: 0.7801 - val_loss: 0.6534

Epoch 2/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 814ms/step - accuracy: 0.8452 - loss: 0.4320 - val_accuracy: 0.7713 - val_loss: 0.6616

Epoch 3/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 814ms/step - accuracy: 0.9081 - loss: 0.2637 - val_accuracy: 0.7977 - val_loss: 0.6410

Epoch 4/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 810ms/step - accuracy: 0.9570 - loss: 0.1443 - val_accuracy: 0.8035 - val_loss: 0.6322

Epoch 5/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 809ms/step - accuracy: 0.9749 - loss: 0.0886 - val_accuracy: 0.8035 - val_loss: 0.6385

Epoch 6/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 814ms/step - accuracy: 0.9928 - loss: 0.0461 - val_accuracy: 0.8211 - val_loss: 0.6523

Epoch 7/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 812ms/step - accuracy: 0.9977 - loss: 0.0226 - val_accuracy: 0.8270 - val_loss: 0.6230

Epoch 8/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 816ms/step - accuracy: 0.9997 - loss: 0.0105 - val_accuracy: 0.8387 - val_loss: 0.6385

Epoch 9/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 814ms/step - accuracy: 0.9997 - loss: 0.0085 - val_accuracy: 0.8123 - val_loss: 0.6850

Epoch 10/10

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 814ms/step - accuracy: 0.9990 - loss: 0.0114 - val_accuracy: 0.8299 - val_loss: 0.6655

====================

Plotting sizes

1
2
3
4
5
6
for size, hist in scores.items():
    plt.plot(hist["val_accuracy"], label=f"validation {size}")

plt.xticks(np.arange(10))
plt.legend()
plt.show()
output_65_0.png

Regularization and dropout

  • Regularization: introduce something that does not allow the neural network overfit to some patterns that does not exist. Ex: when it finds same logo on two different pieces of clothing classify as same like a hat and a t-shirt with same logo classified both as a t-shirt.
  • Dropout: randomly hide a part of the input in each iteration. This is done by freezing some part of the neural network so the neuron do not receive the information. Ex: parts of an image
def make_model(learning_rate=0.01, size_inner=100, drop_rate=0.5):
    base_model = Xception(
        weights="imagenet", include_top=False, input_shape=(150, 150, 3)
    )

    base_model.trainable = False

    inputs = keras.Input(shape=(150, 150, 3))
    base = base_model(inputs, training=False)
    vectors = keras.layers.GlobalAveragePooling2D()(base)

    inner = keras.layers.Dense(size_inner, activation="relu")(vectors)

    drop = keras.layers.Dropout(drop_rate)(inner)

    outputs = keras.layers.Dense(10)(drop)

    model = keras.Model(inputs, outputs)

    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

    loss = keras.losses.CategoricalCrossentropy(from_logits=True)

    model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])

    return model

Define default size

size = 100

Train model with drop rate hyperparameter

scores = {}

for drop_rate in [
    0.0,  # 0.0 means no freezing
    0.2,
    0.5,
    0.8,
]:
    print(drop_rate)

    model = make_model(
        learning_rate=learning_rate, size_inner=size, drop_rate=drop_rate
    )
    history = model.fit(
        train_dataset,
        epochs=30,  # While frozen layers, 10 epochs is not enough anymore to learn
        validation_data=validation_dataset,
    )
    scores[drop_rate] = history.history

    print(20 * "=")
0.0

Epoch 1/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 789ms/step - accuracy: 0.6613 - loss: 0.9749 - val_accuracy: 0.7742 - val_loss: 0.6429

Epoch 2/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 807ms/step - accuracy: 0.8259 - loss: 0.5021 - val_accuracy: 0.8123 - val_loss: 0.5964

Epoch 3/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.8814 - loss: 0.3540 - val_accuracy: 0.8094 - val_loss: 0.5700

Epoch 4/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.9299 - loss: 0.2462 - val_accuracy: 0.7977 - val_loss: 0.5621

Epoch 5/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.9436 - loss: 0.1873 - val_accuracy: 0.8094 - val_loss: 0.5793

Epoch 6/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9690 - loss: 0.1314 - val_accuracy: 0.8211 - val_loss: 0.5556

Epoch 7/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9844 - loss: 0.0913 - val_accuracy: 0.8270 - val_loss: 0.5464

Epoch 8/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9899 - loss: 0.0666 - val_accuracy: 0.8211 - val_loss: 0.5916

Epoch 9/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9954 - loss: 0.0490 - val_accuracy: 0.8123 - val_loss: 0.6175

Epoch 10/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9984 - loss: 0.0325 - val_accuracy: 0.8152 - val_loss: 0.6158

Epoch 11/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 828ms/step - accuracy: 0.9990 - loss: 0.0256 - val_accuracy: 0.8094 - val_loss: 0.6332

Epoch 12/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 827ms/step - accuracy: 0.9987 - loss: 0.0206 - val_accuracy: 0.8123 - val_loss: 0.6208

Epoch 13/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 824ms/step - accuracy: 0.9993 - loss: 0.0185 - val_accuracy: 0.8065 - val_loss: 0.6377

Epoch 14/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 825ms/step - accuracy: 0.9993 - loss: 0.0137 - val_accuracy: 0.8065 - val_loss: 0.6632

Epoch 15/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 829ms/step - accuracy: 0.9997 - loss: 0.0120 - val_accuracy: 0.7977 - val_loss: 0.6658

Epoch 16/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9993 - loss: 0.0113 - val_accuracy: 0.8211 - val_loss: 0.6592

Epoch 17/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9997 - loss: 0.0100 - val_accuracy: 0.8182 - val_loss: 0.6807

Epoch 18/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 828ms/step - accuracy: 0.9993 - loss: 0.0114 - val_accuracy: 0.8123 - val_loss: 0.6914

Epoch 19/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 828ms/step - accuracy: 0.9997 - loss: 0.0061 - val_accuracy: 0.8211 - val_loss: 0.7184

Epoch 20/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 827ms/step - accuracy: 0.9990 - loss: 0.0101 - val_accuracy: 0.8152 - val_loss: 0.7196

Epoch 21/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9997 - loss: 0.0055 - val_accuracy: 0.8094 - val_loss: 0.7276

Epoch 22/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9993 - loss: 0.0093 - val_accuracy: 0.8270 - val_loss: 0.7344

Epoch 23/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 828ms/step - accuracy: 0.9997 - loss: 0.0056 - val_accuracy: 0.8240 - val_loss: 0.7219

Epoch 24/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9997 - loss: 0.0043 - val_accuracy: 0.8182 - val_loss: 0.7339

Epoch 25/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 831ms/step - accuracy: 0.9997 - loss: 0.0069 - val_accuracy: 0.8240 - val_loss: 0.7437

Epoch 26/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 829ms/step - accuracy: 0.9997 - loss: 0.0050 - val_accuracy: 0.8211 - val_loss: 0.7275

Epoch 27/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 828ms/step - accuracy: 0.9997 - loss: 0.0050 - val_accuracy: 0.8240 - val_loss: 0.7930

Epoch 28/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9987 - loss: 0.0088 - val_accuracy: 0.8152 - val_loss: 0.7531

Epoch 29/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9990 - loss: 0.0064 - val_accuracy: 0.8299 - val_loss: 0.7924

Epoch 30/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 830ms/step - accuracy: 0.9993 - loss: 0.0056 - val_accuracy: 0.8182 - val_loss: 0.7776

====================

0.2

Epoch 1/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 83s 839ms/step - accuracy: 0.6551 - loss: 1.0402 - val_accuracy: 0.7859 - val_loss: 0.6470

Epoch 2/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 827ms/step - accuracy: 0.7787 - loss: 0.6251 - val_accuracy: 0.7713 - val_loss: 0.6429

Epoch 3/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 831ms/step - accuracy: 0.8566 - loss: 0.4431 - val_accuracy: 0.8328 - val_loss: 0.5366

Epoch 4/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 829ms/step - accuracy: 0.8739 - loss: 0.3527 - val_accuracy: 0.8006 - val_loss: 0.5654

Epoch 5/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9078 - loss: 0.2759 - val_accuracy: 0.8299 - val_loss: 0.5324

Epoch 6/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9361 - loss: 0.2043 - val_accuracy: 0.8152 - val_loss: 0.5676

Epoch 7/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 838ms/step - accuracy: 0.9407 - loss: 0.1943 - val_accuracy: 0.8006 - val_loss: 0.5994

Epoch 8/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 834ms/step - accuracy: 0.9599 - loss: 0.1427 - val_accuracy: 0.8182 - val_loss: 0.5779

Epoch 9/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 833ms/step - accuracy: 0.9723 - loss: 0.1113 - val_accuracy: 0.8152 - val_loss: 0.5764

Epoch 10/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 837ms/step - accuracy: 0.9765 - loss: 0.0953 - val_accuracy: 0.8065 - val_loss: 0.6151

Epoch 11/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 835ms/step - accuracy: 0.9853 - loss: 0.0741 - val_accuracy: 0.8240 - val_loss: 0.5973

Epoch 12/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 835ms/step - accuracy: 0.9834 - loss: 0.0706 - val_accuracy: 0.8035 - val_loss: 0.6644

Epoch 13/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 838ms/step - accuracy: 0.9896 - loss: 0.0578 - val_accuracy: 0.8035 - val_loss: 0.6301

Epoch 14/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 836ms/step - accuracy: 0.9922 - loss: 0.0448 - val_accuracy: 0.8152 - val_loss: 0.6562

Epoch 15/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 834ms/step - accuracy: 0.9932 - loss: 0.0413 - val_accuracy: 0.8094 - val_loss: 0.6785

Epoch 16/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 834ms/step - accuracy: 0.9896 - loss: 0.0469 - val_accuracy: 0.8328 - val_loss: 0.6487

Epoch 17/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 839ms/step - accuracy: 0.9915 - loss: 0.0411 - val_accuracy: 0.7947 - val_loss: 0.6888

Epoch 18/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 832ms/step - accuracy: 0.9958 - loss: 0.0292 - val_accuracy: 0.8211 - val_loss: 0.6965

Epoch 19/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 826ms/step - accuracy: 0.9967 - loss: 0.0235 - val_accuracy: 0.8152 - val_loss: 0.7333

Epoch 20/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 818ms/step - accuracy: 0.9951 - loss: 0.0247 - val_accuracy: 0.8152 - val_loss: 0.6820

Epoch 21/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 815ms/step - accuracy: 0.9958 - loss: 0.0247 - val_accuracy: 0.8328 - val_loss: 0.6812

Epoch 22/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.9980 - loss: 0.0174 - val_accuracy: 0.8182 - val_loss: 0.7472

Epoch 23/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.9945 - loss: 0.0239 - val_accuracy: 0.8270 - val_loss: 0.7498

Epoch 24/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.9958 - loss: 0.0208 - val_accuracy: 0.8240 - val_loss: 0.7861

Epoch 25/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9954 - loss: 0.0223 - val_accuracy: 0.8094 - val_loss: 0.8187

Epoch 26/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9961 - loss: 0.0200 - val_accuracy: 0.8152 - val_loss: 0.7807

Epoch 27/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 816ms/step - accuracy: 0.9954 - loss: 0.0213 - val_accuracy: 0.8182 - val_loss: 0.7748

Epoch 28/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.9961 - loss: 0.0178 - val_accuracy: 0.7977 - val_loss: 0.7924

Epoch 29/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 815ms/step - accuracy: 0.9977 - loss: 0.0157 - val_accuracy: 0.8182 - val_loss: 0.8587

Epoch 30/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 816ms/step - accuracy: 0.9925 - loss: 0.0251 - val_accuracy: 0.8065 - val_loss: 0.8645

====================

0.5

Epoch 1/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 82s 832ms/step - accuracy: 0.5711 - loss: 1.2967 - val_accuracy: 0.7390 - val_loss: 0.7548

Epoch 2/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.7220 - loss: 0.8246 - val_accuracy: 0.7801 - val_loss: 0.6719

Epoch 3/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.7601 - loss: 0.6883 - val_accuracy: 0.7918 - val_loss: 0.6165

Epoch 4/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.7953 - loss: 0.5890 - val_accuracy: 0.7977 - val_loss: 0.6313

Epoch 5/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.8338 - loss: 0.5004 - val_accuracy: 0.8035 - val_loss: 0.5585

Epoch 6/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.8416 - loss: 0.4458 - val_accuracy: 0.8123 - val_loss: 0.5388

Epoch 7/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 822ms/step - accuracy: 0.8677 - loss: 0.3911 - val_accuracy: 0.8211 - val_loss: 0.5145

Epoch 8/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.8846 - loss: 0.3513 - val_accuracy: 0.8328 - val_loss: 0.5074

Epoch 9/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.8950 - loss: 0.3167 - val_accuracy: 0.8152 - val_loss: 0.5161

Epoch 10/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 822ms/step - accuracy: 0.8970 - loss: 0.2888 - val_accuracy: 0.8299 - val_loss: 0.5507

Epoch 11/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9169 - loss: 0.2585 - val_accuracy: 0.8358 - val_loss: 0.5326

Epoch 12/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 822ms/step - accuracy: 0.9188 - loss: 0.2441 - val_accuracy: 0.8475 - val_loss: 0.5249

Epoch 13/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9208 - loss: 0.2262 - val_accuracy: 0.8240 - val_loss: 0.5395

Epoch 14/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 822ms/step - accuracy: 0.9306 - loss: 0.2061 - val_accuracy: 0.8299 - val_loss: 0.5398

Epoch 15/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9371 - loss: 0.1951 - val_accuracy: 0.8358 - val_loss: 0.5699

Epoch 16/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9361 - loss: 0.1861 - val_accuracy: 0.8182 - val_loss: 0.5742

Epoch 17/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9511 - loss: 0.1476 - val_accuracy: 0.8240 - val_loss: 0.5629

Epoch 18/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9472 - loss: 0.1433 - val_accuracy: 0.8240 - val_loss: 0.5948

Epoch 19/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.9563 - loss: 0.1343 - val_accuracy: 0.8358 - val_loss: 0.5926

Epoch 20/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 824ms/step - accuracy: 0.9557 - loss: 0.1344 - val_accuracy: 0.8065 - val_loss: 0.6182

Epoch 21/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9586 - loss: 0.1278 - val_accuracy: 0.8182 - val_loss: 0.6016

Epoch 22/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9599 - loss: 0.1239 - val_accuracy: 0.8182 - val_loss: 0.6269

Epoch 23/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9661 - loss: 0.1081 - val_accuracy: 0.8182 - val_loss: 0.6276

Epoch 24/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9690 - loss: 0.1028 - val_accuracy: 0.8328 - val_loss: 0.6214

Epoch 25/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 825ms/step - accuracy: 0.9729 - loss: 0.0889 - val_accuracy: 0.8240 - val_loss: 0.6480

Epoch 26/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 824ms/step - accuracy: 0.9681 - loss: 0.1005 - val_accuracy: 0.8299 - val_loss: 0.6565

Epoch 27/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 825ms/step - accuracy: 0.9687 - loss: 0.0996 - val_accuracy: 0.8446 - val_loss: 0.6213

Epoch 28/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9687 - loss: 0.0952 - val_accuracy: 0.8211 - val_loss: 0.7078

Epoch 29/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.9720 - loss: 0.0858 - val_accuracy: 0.8299 - val_loss: 0.6214

Epoch 30/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 821ms/step - accuracy: 0.9746 - loss: 0.0807 - val_accuracy: 0.8240 - val_loss: 0.6854

====================

0.8

Epoch 1/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 82s 829ms/step - accuracy: 0.3840 - loss: 1.8165 - val_accuracy: 0.6041 - val_loss: 1.1667

Epoch 2/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.5033 - loss: 1.4135 - val_accuracy: 0.6804 - val_loss: 0.9801

Epoch 3/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 822ms/step - accuracy: 0.5434 - loss: 1.2954 - val_accuracy: 0.7097 - val_loss: 0.8887

Epoch 4/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 818ms/step - accuracy: 0.5675 - loss: 1.1960 - val_accuracy: 0.7361 - val_loss: 0.8217

Epoch 5/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 833ms/step - accuracy: 0.5805 - loss: 1.1722 - val_accuracy: 0.7595 - val_loss: 0.7582

Epoch 6/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.5988 - loss: 1.0933 - val_accuracy: 0.7713 - val_loss: 0.7610

Epoch 7/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.6193 - loss: 1.0637 - val_accuracy: 0.7859 - val_loss: 0.7139

Epoch 8/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 823ms/step - accuracy: 0.6092 - loss: 1.0350 - val_accuracy: 0.7801 - val_loss: 0.7010

Epoch 9/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.6340 - loss: 0.9822 - val_accuracy: 0.7947 - val_loss: 0.7085

Epoch 10/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.6320 - loss: 0.9731 - val_accuracy: 0.7889 - val_loss: 0.6850

Epoch 11/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 819ms/step - accuracy: 0.6287 - loss: 0.9601 - val_accuracy: 0.7830 - val_loss: 0.6748

Epoch 12/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 818ms/step - accuracy: 0.6463 - loss: 0.9337 - val_accuracy: 0.7889 - val_loss: 0.6652

Epoch 13/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.6535 - loss: 0.8971 - val_accuracy: 0.7830 - val_loss: 0.6598

Epoch 14/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 79s 820ms/step - accuracy: 0.6506 - loss: 0.8877 - val_accuracy: 0.7830 - val_loss: 0.6693

Epoch 15/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 818ms/step - accuracy: 0.6529 - loss: 0.9161 - val_accuracy: 0.7859 - val_loss: 0.6564

Epoch 16/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 78s 817ms/step - accuracy: 0.6565 - loss: 0.8923 - val_accuracy: 0.8094 - val_loss: 0.6444

Epoch 17/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 806ms/step - accuracy: 0.6679 - loss: 0.8483 - val_accuracy: 0.7918 - val_loss: 0.6217

Epoch 18/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 797ms/step - accuracy: 0.6731 - loss: 0.8459 - val_accuracy: 0.7947 - val_loss: 0.6483

Epoch 19/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 798ms/step - accuracy: 0.6767 - loss: 0.8249 - val_accuracy: 0.7830 - val_loss: 0.6378

Epoch 20/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 799ms/step - accuracy: 0.6721 - loss: 0.8162 - val_accuracy: 0.8094 - val_loss: 0.6035

Epoch 21/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.6793 - loss: 0.8029 - val_accuracy: 0.8006 - val_loss: 0.5998

Epoch 22/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 803ms/step - accuracy: 0.6907 - loss: 0.7881 - val_accuracy: 0.7889 - val_loss: 0.6093

Epoch 23/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 800ms/step - accuracy: 0.6907 - loss: 0.7961 - val_accuracy: 0.8006 - val_loss: 0.6390

Epoch 24/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.6864 - loss: 0.7723 - val_accuracy: 0.7771 - val_loss: 0.6332

Epoch 25/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 800ms/step - accuracy: 0.7011 - loss: 0.7577 - val_accuracy: 0.7977 - val_loss: 0.6405

Epoch 26/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.7018 - loss: 0.7571 - val_accuracy: 0.7830 - val_loss: 0.6456

Epoch 27/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 801ms/step - accuracy: 0.7005 - loss: 0.7668 - val_accuracy: 0.8094 - val_loss: 0.5950

Epoch 28/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 799ms/step - accuracy: 0.6988 - loss: 0.7351 - val_accuracy: 0.8035 - val_loss: 0.6013

Epoch 29/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 77s 798ms/step - accuracy: 0.7177 - loss: 0.7107 - val_accuracy: 0.7947 - val_loss: 0.6009

Epoch 30/30

96/96 ━━━━━━━━━━━━━━━━━━━━ 76s 796ms/step - accuracy: 0.7148 - loss: 0.7204 - val_accuracy: 0.8240 - val_loss: 0.5710

====================

Plot drop rate results

1
2
3
4
5
6
for drop_rate, hist in scores.items():
    plt.plot(hist["val_accuracy"], label=f"validation {drop_rate}")

plt.ylim(0.78, 0.86)
plt.legend()
plt.show()
output_73_0.png

Data Augmentation

Creating more data based on existing data

Possible image transformations:

  • Flip
  • Rotation
  • Height shift
  • Shear
  • Zoom In/Out X
  • Zoom In/Out Y
  • Brightness/Contrast
  • Combine several transformations
train_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    rotation_range=30,
    width_shift_range=10.0,
    height_shift_range=10.0,
    shear_range=10,
    zoom_range=0.1,
    vertical_flip=False,
)

train_dataset = train_generator.flow_from_directory(
    DATA_DIR / "train", target_size=(150, 150), batch_size=32
)

# Always keep validation as is, do not add augmented data
validation_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input
)

validation_dataset = train_generator.flow_from_directory(
    DATA_DIR / "validation",
    target_size=(150, 150),
    batch_size=32,
    shuffle=False,
)
Found 3068 images belonging to 10 classes.

Found 341 images belonging to 10 classes.

Training the new model

learning_rate = 0.001
size = 100
drop_rate = 0.2

model = make_model(
    learning_rate=learning_rate, size_inner=size, drop_rate=drop_rate
)

history = model.fit(
    train_dataset, epochs=50, validation_data=validation_dataset
)
2025-12-30 15:46:14.387886: E external/local_xla/xla/stream_executor/cuda/cuda_platform.cc:51] failed call to cuInit: INTERNAL: CUDA error: Failed call to cuInit: UNKNOWN ERROR (303)
Epoch 1/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 86s 857ms/step - accuracy: 0.5730 - loss: 1.2856 - val_accuracy: 0.6979 - val_loss: 0.9253

Epoch 2/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 836ms/step - accuracy: 0.6845 - loss: 0.9130 - val_accuracy: 0.7185 - val_loss: 0.8813

Epoch 3/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 836ms/step - accuracy: 0.7285 - loss: 0.7784 - val_accuracy: 0.7214 - val_loss: 0.8249

Epoch 4/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 838ms/step - accuracy: 0.7363 - loss: 0.7407 - val_accuracy: 0.7302 - val_loss: 0.8237

Epoch 5/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 839ms/step - accuracy: 0.7621 - loss: 0.6814 - val_accuracy: 0.7214 - val_loss: 0.8524

Epoch 6/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 837ms/step - accuracy: 0.7790 - loss: 0.6301 - val_accuracy: 0.7595 - val_loss: 0.7277

Epoch 7/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.7953 - loss: 0.5791 - val_accuracy: 0.7361 - val_loss: 0.7923

Epoch 8/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8057 - loss: 0.5662 - val_accuracy: 0.7361 - val_loss: 0.8532

Epoch 9/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 841ms/step - accuracy: 0.8070 - loss: 0.5333 - val_accuracy: 0.7507 - val_loss: 0.7609

Epoch 10/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8217 - loss: 0.5133 - val_accuracy: 0.7566 - val_loss: 0.7458

Epoch 11/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8276 - loss: 0.4792 - val_accuracy: 0.7331 - val_loss: 0.7461

Epoch 12/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 840ms/step - accuracy: 0.8338 - loss: 0.4770 - val_accuracy: 0.7185 - val_loss: 0.7635

Epoch 13/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 844ms/step - accuracy: 0.8465 - loss: 0.4482 - val_accuracy: 0.7214 - val_loss: 0.8351

Epoch 14/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8504 - loss: 0.4238 - val_accuracy: 0.7419 - val_loss: 0.7961

Epoch 15/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8504 - loss: 0.4081 - val_accuracy: 0.7302 - val_loss: 0.8967

Epoch 16/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 842ms/step - accuracy: 0.8595 - loss: 0.4039 - val_accuracy: 0.7390 - val_loss: 0.8086

Epoch 17/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 846ms/step - accuracy: 0.8598 - loss: 0.3865 - val_accuracy: 0.7537 - val_loss: 0.7849

Epoch 18/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8579 - loss: 0.3977 - val_accuracy: 0.7390 - val_loss: 0.8071

Epoch 19/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8696 - loss: 0.3837 - val_accuracy: 0.7331 - val_loss: 0.8791

Epoch 20/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8647 - loss: 0.3866 - val_accuracy: 0.7566 - val_loss: 0.7651

Epoch 21/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8716 - loss: 0.3506 - val_accuracy: 0.7801 - val_loss: 0.7526

Epoch 22/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 82s 850ms/step - accuracy: 0.8797 - loss: 0.3414 - val_accuracy: 0.7566 - val_loss: 0.8485

Epoch 23/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8778 - loss: 0.3336 - val_accuracy: 0.7683 - val_loss: 0.8056

Epoch 24/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 837ms/step - accuracy: 0.8843 - loss: 0.3136 - val_accuracy: 0.7478 - val_loss: 0.8381

Epoch 25/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8748 - loss: 0.3352 - val_accuracy: 0.7331 - val_loss: 0.9469

Epoch 26/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 844ms/step - accuracy: 0.8944 - loss: 0.3100 - val_accuracy: 0.7478 - val_loss: 0.8850

Epoch 27/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 841ms/step - accuracy: 0.8882 - loss: 0.3074 - val_accuracy: 0.7390 - val_loss: 0.9180

Epoch 28/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.8924 - loss: 0.3032 - val_accuracy: 0.7683 - val_loss: 0.8132

Epoch 29/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8960 - loss: 0.3110 - val_accuracy: 0.7419 - val_loss: 0.8047

Epoch 30/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 844ms/step - accuracy: 0.9094 - loss: 0.2643 - val_accuracy: 0.7478 - val_loss: 0.7520

Epoch 31/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.9042 - loss: 0.2726 - val_accuracy: 0.7683 - val_loss: 0.7882

Epoch 32/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 844ms/step - accuracy: 0.9038 - loss: 0.2751 - val_accuracy: 0.7243 - val_loss: 0.9899

Epoch 33/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 843ms/step - accuracy: 0.9009 - loss: 0.2766 - val_accuracy: 0.7390 - val_loss: 0.7946

Epoch 34/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.8983 - loss: 0.2953 - val_accuracy: 0.7537 - val_loss: 0.7893

Epoch 35/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 845ms/step - accuracy: 0.9038 - loss: 0.2692 - val_accuracy: 0.7449 - val_loss: 0.9665

Epoch 36/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 842ms/step - accuracy: 0.9038 - loss: 0.2725 - val_accuracy: 0.7273 - val_loss: 0.9017

Epoch 37/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 838ms/step - accuracy: 0.9126 - loss: 0.2568 - val_accuracy: 0.7625 - val_loss: 0.9324

Epoch 38/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 837ms/step - accuracy: 0.9208 - loss: 0.2313 - val_accuracy: 0.7654 - val_loss: 0.9078

Epoch 39/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 833ms/step - accuracy: 0.9146 - loss: 0.2549 - val_accuracy: 0.7713 - val_loss: 0.9492

Epoch 40/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 835ms/step - accuracy: 0.9078 - loss: 0.2532 - val_accuracy: 0.7507 - val_loss: 0.9192

Epoch 41/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 838ms/step - accuracy: 0.9185 - loss: 0.2357 - val_accuracy: 0.7449 - val_loss: 0.9051

Epoch 42/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 837ms/step - accuracy: 0.9179 - loss: 0.2397 - val_accuracy: 0.7449 - val_loss: 1.0074

Epoch 43/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 838ms/step - accuracy: 0.9185 - loss: 0.2380 - val_accuracy: 0.7507 - val_loss: 0.9408

Epoch 44/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 834ms/step - accuracy: 0.9175 - loss: 0.2315 - val_accuracy: 0.7771 - val_loss: 0.8563

Epoch 45/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 835ms/step - accuracy: 0.9140 - loss: 0.2440 - val_accuracy: 0.7654 - val_loss: 0.9574

Epoch 46/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 838ms/step - accuracy: 0.9110 - loss: 0.2537 - val_accuracy: 0.7507 - val_loss: 0.9831

Epoch 47/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 839ms/step - accuracy: 0.9169 - loss: 0.2362 - val_accuracy: 0.7625 - val_loss: 0.9616

Epoch 48/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 836ms/step - accuracy: 0.9221 - loss: 0.2279 - val_accuracy: 0.7683 - val_loss: 0.8058

Epoch 49/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 80s 836ms/step - accuracy: 0.9208 - loss: 0.2284 - val_accuracy: 0.7449 - val_loss: 0.9683

Epoch 50/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 81s 841ms/step - accuracy: 0.9234 - loss: 0.2180 - val_accuracy: 0.7419 - val_loss: 0.9348

Training a larger model

  • 299 x 299 model
def make_model(
    input_size=150, learning_rate=0.01, size_inner=100, drop_rate=0.5
):
    base_model = Xception(
        weights="imagenet",
        include_top=False,
        input_shape=(input_size, input_size, 3),
    )

    base_model.trainable = False

    inputs = keras.Input(shape=(input_size, input_size, 3))
    base = base_model(inputs, training=False)
    vectors = keras.layers.GlobalAveragePooling2D()(base)

    inner = keras.layers.Dense(size_inner, activation="relu")(vectors)

    drop = keras.layers.Dropout(drop_rate)(inner)

    outputs = keras.layers.Dense(10)(drop)

    model = keras.Model(inputs, outputs)

    optimizer = keras.optimizers.Adam(learning_rate=learning_rate)

    loss = keras.losses.CategoricalCrossentropy(from_logits=True)

    model.compile(optimizer=optimizer, loss=loss, metrics=["accuracy"])

    return model

Define data

train_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input,
    # rotation_range=30,
    # width_shift_range=10.0,
    # height_shift_range=10.0,
    # shear_range=10,
    # zoom_range=0.1,
    # vertical_flip=False,
)

train_dataset = train_generator.flow_from_directory(
    DATA_DIR / "train", target_size=(299, 299), batch_size=32
)

# Always keep validation as is, do not add augmented data
validation_generator = ImageDataGenerator(
    preprocessing_function=preprocess_input
)

validation_dataset = train_generator.flow_from_directory(
    DATA_DIR / "validation",
    target_size=(299, 299),
    batch_size=32,
    shuffle=False,
)
Found 3068 images belonging to 10 classes.

Found 341 images belonging to 10 classes.

Set a checkpoint callback

1
2
3
4
5
6
checkpoint = keras.callbacks.ModelCheckpoint(
    "xception_v4_{epoch:02d}_{val_accuracy:.3f}.h5",
    save_best_only=True,
    monitor="val_accuracy",
    mode="max",
)

Training a larger model

learning_rate = 0.001
size = 100
drop_rate = 0.2
input_size = 299

model = make_model(
    input_size=input_size,
    learning_rate=learning_rate,
    size_inner=size,
    drop_rate=drop_rate,
)

history = model.fit(
    train_dataset,
    epochs=50,
    validation_data=validation_dataset,
    callbacks=[checkpoint],
)
Epoch 1/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.6116 - loss: 1.1837
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 334s 3s/step - accuracy: 0.7350 - loss: 0.8060 - val_accuracy: 0.8065 - val_loss: 0.5242

Epoch 2/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.8416 - loss: 0.4496
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.8504 - loss: 0.4242 - val_accuracy: 0.8563 - val_loss: 0.4427

Epoch 3/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.8791 - loss: 0.3455 - val_accuracy: 0.8475 - val_loss: 0.4293

Epoch 4/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.9005 - loss: 0.2930
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9045 - loss: 0.2819 - val_accuracy: 0.8680 - val_loss: 0.3648

Epoch 5/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 326s 3s/step - accuracy: 0.9120 - loss: 0.2548 - val_accuracy: 0.8680 - val_loss: 0.3586

Epoch 6/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.9305 - loss: 0.2129
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 325s 3s/step - accuracy: 0.9254 - loss: 0.2201 - val_accuracy: 0.8768 - val_loss: 0.3667

Epoch 7/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 325s 3s/step - accuracy: 0.9348 - loss: 0.1894 - val_accuracy: 0.8710 - val_loss: 0.3656

Epoch 8/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.9560 - loss: 0.1506
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 327s 3s/step - accuracy: 0.9462 - loss: 0.1675 - val_accuracy: 0.8798 - val_loss: 0.3768

Epoch 9/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 325s 3s/step - accuracy: 0.9508 - loss: 0.1429 - val_accuracy: 0.8798 - val_loss: 0.3668

Epoch 10/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.9607 - loss: 0.1334
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 325s 3s/step - accuracy: 0.9606 - loss: 0.1264 - val_accuracy: 0.8856 - val_loss: 0.3923

Epoch 11/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 352s 4s/step - accuracy: 0.9638 - loss: 0.1179 - val_accuracy: 0.8827 - val_loss: 0.3898

Epoch 12/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 326s 3s/step - accuracy: 0.9700 - loss: 0.0990 - val_accuracy: 0.8592 - val_loss: 0.4020

Epoch 13/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9775 - loss: 0.0885 - val_accuracy: 0.8710 - val_loss: 0.4146

Epoch 14/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9804 - loss: 0.0746 - val_accuracy: 0.8710 - val_loss: 0.4258

Epoch 15/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 322s 3s/step - accuracy: 0.9814 - loss: 0.0753 - val_accuracy: 0.8768 - val_loss: 0.4226

Epoch 16/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9821 - loss: 0.0655 - val_accuracy: 0.8739 - val_loss: 0.4439

Epoch 17/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9879 - loss: 0.0586 - val_accuracy: 0.8680 - val_loss: 0.4618

Epoch 18/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 320s 3s/step - accuracy: 0.9873 - loss: 0.0539 - val_accuracy: 0.8798 - val_loss: 0.4356

Epoch 19/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9915 - loss: 0.0446 - val_accuracy: 0.8827 - val_loss: 0.4358

Epoch 20/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9922 - loss: 0.0392 - val_accuracy: 0.8798 - val_loss: 0.4640

Epoch 21/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9915 - loss: 0.0375 - val_accuracy: 0.8827 - val_loss: 0.4495

Epoch 22/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9899 - loss: 0.0398 - val_accuracy: 0.8798 - val_loss: 0.4520

Epoch 23/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9932 - loss: 0.0319 - val_accuracy: 0.8827 - val_loss: 0.4582

Epoch 24/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 322s 3s/step - accuracy: 0.9954 - loss: 0.0267 - val_accuracy: 0.8798 - val_loss: 0.4862

Epoch 25/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 321s 3s/step - accuracy: 0.9974 - loss: 0.0228 - val_accuracy: 0.8710 - val_loss: 0.4889

Epoch 26/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 4s/step - accuracy: 0.9971 - loss: 0.0225 - val_accuracy: 0.8710 - val_loss: 0.5015

Epoch 27/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9971 - loss: 0.0213 - val_accuracy: 0.8798 - val_loss: 0.4888

Epoch 28/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9883 - loss: 0.0391 - val_accuracy: 0.8798 - val_loss: 0.5098

Epoch 29/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9958 - loss: 0.0265 - val_accuracy: 0.8651 - val_loss: 0.5146

Epoch 30/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9964 - loss: 0.0202 - val_accuracy: 0.8856 - val_loss: 0.5054

Epoch 31/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9974 - loss: 0.0168 - val_accuracy: 0.8768 - val_loss: 0.5491

Epoch 32/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 338s 4s/step - accuracy: 0.9977 - loss: 0.0176 - val_accuracy: 0.8768 - val_loss: 0.5263

Epoch 33/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 4s/step - accuracy: 0.9980 - loss: 0.0132 - val_accuracy: 0.8827 - val_loss: 0.5119

Epoch 34/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 338s 4s/step - accuracy: 0.9980 - loss: 0.0132 - val_accuracy: 0.8710 - val_loss: 0.5483

Epoch 35/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9971 - loss: 0.0161 - val_accuracy: 0.8768 - val_loss: 0.5553

Epoch 36/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 4s/step - accuracy: 0.9974 - loss: 0.0141 - val_accuracy: 0.8680 - val_loss: 0.5530

Epoch 37/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 0s 3s/step - accuracy: 0.9991 - loss: 0.0125
WARNING:absl:You are saving your model as an HDF5 file via `model.save()` or `keras.saving.save_model(model)`. This file format is considered legacy. We recommend using instead the native Keras format, e.g. `model.save('my_model.keras')` or `keras.saving.save_model(model, 'my_model.keras')`.
96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9984 - loss: 0.0140 - val_accuracy: 0.8915 - val_loss: 0.5516

Epoch 38/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 3s/step - accuracy: 0.9980 - loss: 0.0129 - val_accuracy: 0.8827 - val_loss: 0.5545

Epoch 39/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 3s/step - accuracy: 0.9980 - loss: 0.0121 - val_accuracy: 0.8915 - val_loss: 0.5614

Epoch 40/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9964 - loss: 0.0118 - val_accuracy: 0.8856 - val_loss: 0.5593

Epoch 41/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9987 - loss: 0.0105 - val_accuracy: 0.8856 - val_loss: 0.5368

Epoch 42/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9984 - loss: 0.0128 - val_accuracy: 0.8827 - val_loss: 0.5870

Epoch 43/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 4s/step - accuracy: 0.9980 - loss: 0.0107 - val_accuracy: 0.8827 - val_loss: 0.5994

Epoch 44/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 337s 4s/step - accuracy: 0.9997 - loss: 0.0070 - val_accuracy: 0.8915 - val_loss: 0.5784

Epoch 45/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 335s 3s/step - accuracy: 0.9987 - loss: 0.0088 - val_accuracy: 0.8651 - val_loss: 0.6762

Epoch 46/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 336s 4s/step - accuracy: 0.9990 - loss: 0.0088 - val_accuracy: 0.8680 - val_loss: 0.6353

Epoch 47/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 329s 3s/step - accuracy: 0.9984 - loss: 0.0095 - val_accuracy: 0.8856 - val_loss: 0.5977

Epoch 48/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 326s 3s/step - accuracy: 0.9909 - loss: 0.0236 - val_accuracy: 0.8768 - val_loss: 0.6269

Epoch 49/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 329s 3s/step - accuracy: 0.9945 - loss: 0.0195 - val_accuracy: 0.8827 - val_loss: 0.6258

Epoch 50/50

96/96 ━━━━━━━━━━━━━━━━━━━━ 334s 3s/step - accuracy: 0.9967 - loss: 0.0137 - val_accuracy: 0.8739 - val_loss: 0.6609

Using the model

Loading the model

model = keras.models.load_model("xception_v4_37_0.891.h5")
2025-12-31 09:44:39.700604: W external/local_xla/xla/tsl/framework/cpu_allocator_impl.cc:84] Allocation of 12582912 exceeds 10% of free system memory.

WARNING:absl:Compiled the loaded model, but the compiled metrics have yet to be built. `model.compile_metrics` will be empty until you train or evaluate the model.

Load dataset

1
2
3
4
5
6
7
8
test_generator = ImageDataGenerator(preprocessing_function=preprocess_input)

test_dataset = test_generator.flow_from_directory(
    DATA_DIR / "test",
    target_size=(299, 299),
    batch_size=32,
    shuffle=False,
)
Found 372 images belonging to 10 classes.

Evaluate Model

model.evaluate(test_dataset)
12/12 ━━━━━━━━━━━━━━━━━━━━ 122s 9s/step - accuracy: 0.8871 - loss: 0.3760
[0.37596917152404785, 0.8870967626571655]

Load image

1
2
3
image_path = DATA_DIR / "test/pants/c8d21106-bbdb-4e8d-83e4-bf3d14e54c16.jpg"
image = load_img(image_path, target_size=(299, 299))
image
<PIL.Image.Image image mode=RGB size=299x299>

Inspect X shape

1
2
3
x = np.array(image)
X = np.array([x])
X.shape
(1, 299, 299, 3)

Preprocess X

X = preprocess_input(X)

Predict

pred = model.predict(X)
pred
1/1 ━━━━━━━━━━━━━━━━━━━━ 1s 564ms/step
array([[-9.582894 , -6.9979467, -6.667122 , -6.0695252, 13.929666 ,
        -4.5493875, -6.02806  ,  4.2828007, -7.881497 , -6.2412157]],
      dtype=float32)

Get class labels

classes = train_dataset.class_indices.keys()
classes
dict_keys(['dress', 'hat', 'longsleeve', 'outwear', 'pants', 'shirt', 'shoes', 'shorts', 'skirt', 't-shirt'])

Get probabilities for each class

dict(zip(classes, pred[0]))
{'dress': np.float32(-9.582894),
 'hat': np.float32(-6.9979467),
 'longsleeve': np.float32(-6.667122),
 'outwear': np.float32(-6.0695252),
 'pants': np.float32(13.929666),
 'shirt': np.float32(-4.5493875),
 'shoes': np.float32(-6.02806),
 'shorts': np.float32(4.2828007),
 'skirt': np.float32(-7.881497),
 't-shirt': np.float32(-6.2412157)}