In [24]:
import numpy as np
In [25]:
import tensorflow as tf
from tensorflow.keras import layers, Sequential
In [26]:
# Set batch size and image dimensions
batch_size = 32
img_height, img_width = 224, 224
# Make a training set from the directory
train_ds = tf.keras.utils.image_dataset_from_directory(
'test_images/',
validation_split=0.2,
subset='training',
seed=76,
image_size=(img_height, img_width),
batch_size=batch_size
)
# Get class names and the number of classes
class_names = train_ds.class_names
num_classes = len(class_names)
# Make a validation set from the directory
val_ds = tf.keras.utils.image_dataset_from_directory(
'test_images/',
validation_split=0.2,
subset='validation',
seed=76,
image_size=(img_height, img_width),
batch_size=batch_size
)
Found 28 files belonging to 15 classes. Using 23 files for training. Found 28 files belonging to 15 classes. Using 5 files for validation.
In [27]:
data_augmentation = Sequential([
layers.RandomFlip('horizontal'),
layers.RandomRotation(0.2),
layers.RandomContrast(0.1),
], name = 'data_augmentation')
model = Sequential([
layers.Input(shape=(224, 224, 3)),
data_augmentation,
layers.Rescaling(1./255),
layers.Conv2D(32, 3, activation='relu', kernel_regularizer='l2'),
layers.MaxPooling2D(),
layers.Conv2D(64, 3, activation='relu', kernel_regularizer='l2'),
layers.MaxPooling2D(),
layers.Conv2D(128, 3, activation='relu', kernel_regularizer='l2'),
layers.MaxPooling2D(),
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dense(num_classes, activation='softmax')
])
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
In [28]:
hist = model.fit(
train_ds,
validation_data=val_ds,
epochs=20
)
Epoch 1/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 12s 12s/step - accuracy: 0.0000e+00 - loss: 4.0419 - val_accuracy: 0.0000e+00 - val_loss: 5.1998 Epoch 2/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 128ms/step - accuracy: 0.0870 - loss: 3.9378 - val_accuracy: 0.0000e+00 - val_loss: 4.6775 Epoch 3/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 111ms/step - accuracy: 0.0870 - loss: 3.5814 - val_accuracy: 0.0000e+00 - val_loss: 4.7341 Epoch 4/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 104ms/step - accuracy: 0.5652 - loss: 3.2227 - val_accuracy: 0.0000e+00 - val_loss: 5.1688 Epoch 5/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 108ms/step - accuracy: 0.4348 - loss: 2.9905 - val_accuracy: 0.0000e+00 - val_loss: 5.3293 Epoch 6/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 104ms/step - accuracy: 0.6522 - loss: 2.5667 - val_accuracy: 0.0000e+00 - val_loss: 5.4940 Epoch 7/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 107ms/step - accuracy: 0.6957 - loss: 2.1733 - val_accuracy: 0.0000e+00 - val_loss: 5.8128 Epoch 8/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 100ms/step - accuracy: 0.8261 - loss: 1.8269 - val_accuracy: 0.2000 - val_loss: 6.0881 Epoch 9/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 101ms/step - accuracy: 0.9565 - loss: 1.5591 - val_accuracy: 0.2000 - val_loss: 7.1343 Epoch 10/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 102ms/step - accuracy: 0.9565 - loss: 1.4587 - val_accuracy: 0.2000 - val_loss: 8.1284 Epoch 11/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 105ms/step - accuracy: 1.0000 - loss: 1.2308 - val_accuracy: 0.2000 - val_loss: 9.6158 Epoch 12/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 108ms/step - accuracy: 0.9130 - loss: 1.2299 - val_accuracy: 0.2000 - val_loss: 10.2614 Epoch 13/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 101ms/step - accuracy: 0.9565 - loss: 1.3385 - val_accuracy: 0.2000 - val_loss: 11.1809 Epoch 14/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 106ms/step - accuracy: 1.0000 - loss: 1.0952 - val_accuracy: 0.2000 - val_loss: 12.9401 Epoch 15/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 102ms/step - accuracy: 0.9130 - loss: 1.1586 - val_accuracy: 0.2000 - val_loss: 15.1162 Epoch 16/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 104ms/step - accuracy: 0.9565 - loss: 1.0572 - val_accuracy: 0.2000 - val_loss: 15.9038 Epoch 17/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 106ms/step - accuracy: 0.8261 - loss: 1.9907 - val_accuracy: 0.4000 - val_loss: 14.8837 Epoch 18/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 111ms/step - accuracy: 1.0000 - loss: 1.0228 - val_accuracy: 0.0000e+00 - val_loss: 15.0257 Epoch 19/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 103ms/step - accuracy: 0.8696 - loss: 1.2061 - val_accuracy: 0.2000 - val_loss: 15.1873 Epoch 20/20 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 100ms/step - accuracy: 1.0000 - loss: 0.9996 - val_accuracy: 0.2000 - val_loss: 15.3104
In [33]:
def predict_tartan(image_path):
# 1. Load and resize the image
img = tf.keras.utils.load_img(image_path, target_size=(224, 224))
# 2. Convert to array and expand dimensions to (1, 224, 224, 3)
img_array = tf.keras.utils.img_to_array(img)
img_array = tf.expand_dims(img_array, axis=0)
# 3. Make prediction
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])
# 4. Get the result
predicted_class = class_names[np.argmax(score)]
confidence = 100 * np.max(score)
print(f"This image likely belongs to {predicted_class} with {confidence:.2f}% confidence.")
In [34]:
predict_tartan('predict_images/MacDonald Clanranald(1).png')
1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 181ms/step This image likely belongs to Henkel with 16.17% confidence.
In [35]:
from pathlib import Path
In [37]:
p = Path('predict_images')
for itm in p.iterdir():
print(itm.name)
predict_tartan(itm)
Abercrombie.JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 27ms/step This image likely belongs to Abergavenny with 16.24% confidence. Lamont and None.JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 26ms/step This image likely belongs to Abergavenny with 14.50% confidence. Lamont(1).JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 24ms/step This image likely belongs to Lamont with 15.99% confidence. Lamont(2).JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 27ms/step This image likely belongs to Abergavenny with 16.26% confidence. Lamont(3).jpeg 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 25ms/step This image likely belongs to Lamont with 12.66% confidence. MacDonald Clanranald(1).png 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 26ms/step This image likely belongs to Henkel with 16.17% confidence. MacDonald ClanRanald(2).JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 28ms/step This image likely belongs to Abergavenny with 16.26% confidence. MacDonald Clanranald(3).JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 29ms/step This image likely belongs to Abergavenny with 15.56% confidence. None.JPG 1/1 ━━━━━━━━━━━━━━━━━━━━ 0s 27ms/step This image likely belongs to Abergavenny with 16.25% confidence.
In [ ]: