(17 категорий и около 6K дополненных изображений)
Изображения монет обрезаны, поэтому устанавливаются фоновые пиксели чтобы быть прозрачным.
(для справки я загрузил данные обучения в Dropbox (coin_catalog/augmented/crops/...)
https://www.dropbox.com/scl/fo/ipygjqdv ... y2zvf&dl=0)
Я ожидал, что эта задача будет похожа на классификацию изображений такие задачи, как распознавание цветов. Однако, несмотря на использование нескольких архитектур, включая ResNet152V2, модели не смогли достичь разумной точности. Например, они часто неправильно классифицируют даже четко определенные типы монет.
Настройка обучения:
- Мои данные обучения или текущая модель на основе ResNet не подходят для этой задачи?
- Есть ли в моем сценарии обучения (см. ниже) какие-либо очевидные проблемы, которые могут привести к снижению производительности?
- Можете ли вы порекомендовать какие-либо ресурсы или примеры подобных задач классификации изображений, особенно с небольшими наборы данных или изображения с прозрачным фоном?
- train.py: сценарий обучения
- model_ResNet50V2.py: определение модели
- test.py: сценарий вывода для оценки обученной модели
train.py
import os
from pathlib import Path
import numpy as np
import tensorflow as tf
from sklearn.model_selection import train_test_split
from tensorflow.keras import layers
from tensorflow.keras.callbacks import ModelCheckpoint, EarlyStopping
from core.utilities.helper import get_directories
from kunstkammer.object_recognition.model_ResNet50V2 import build_model
if __name__=="__main__":
catalog_path = Path("coin_catalog/augmented")
""" Hyperparemeters """
image_shape = (128, 128)
testrun_name = "ResNet152V2"
num_epochs = 50
validation_split = 0.2
batch_size = 1
lr = 1e-3
seed = 42
np.random.seed(seed)
tf.random.set_seed(seed)
""" Directory for storing files """
if not os.path.exists(output_dir := Path(os.path.dirname(__file__), "trained")):
os.makedirs(output_dir)
crops_path = Path(catalog_path, "crops")
model_path = Path(output_dir, f"object_recognition_{testrun_name}.keras")
crops_dataset_path = Path(output_dir, f"crops_dataset_{testrun_name}.tfrecord")
enum_path = f"trained/enumerations/train_enum_{testrun_name}.json"
enumerations = [str(coin.stem) for coin in get_directories(Path(catalog_path, "images"))]
try:
crop_dataset = tf.data.Dataset.load(str(crops_dataset_path))
train_dataset, val_dataset = train_test_split(crop_dataset, test_size=validation_split, random_state=seed)
print("=== Dataset loaded ===")
except:
crop_dataset = tf.keras.utils.image_dataset_from_directory(str(crops_path),
seed=seed,
batch_size=batch_size,
image_size=image_shape)
""" Split dataset into train and validation subsets """
dataset_size = tf.data.experimental.cardinality(crop_dataset).numpy()
val_size = int(dataset_size * validation_split)
train_size = dataset_size - val_size
train_dataset = crop_dataset.take(train_size)
val_dataset = crop_dataset.skip(train_size)
AUTOTUNE = tf.data.AUTOTUNE
train_ds = train_dataset.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
val_dataset = val_dataset.cache().shuffle(1000).prefetch(buffer_size=AUTOTUNE)
print("=== Save datasets ===")
crop_dataset.save(str(crops_dataset_path))
""" Model """
if not os.path.exists(model_path):
model = build_model(input_shape=(*image_shape, 3), num_classes=len(enumerations))
else:
print("Model already exists. Loading the model...")
model = tf.keras.models.load_model(model_path)
""" Training """
lr_schedule = tf.keras.optimizers.schedules.ExponentialDecay(
initial_learning_rate=lr,
decay_steps=1000, # Adjust this based on dataset size and batch size
decay_rate=0.96, # Factor by which to decay
staircase=True # If True, the learning rate decays in discrete steps
)
model.compile(
optimizer=tf.keras.optimizers.SGD(learning_rate=lr_schedule),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False),
metrics=['accuracy']
)
callbacks = [
ModelCheckpoint(model_path, save_best_only=True),
# ReduceLROnPlateau(factor=0.1, patience=5),
EarlyStopping(patience=10)
]
history = model.fit(
train_dataset,
validation_data=val_dataset,
epochs=num_epochs,
callbacks=callbacks
)
model.save(model_path)
model_ResNet50V2.py
import tensorflow as tf
from tensorflow.keras import layers, Model
def build_model(input_shape=(224, 224, 3), num_classes=10, use_pretrained=True):
base_model = tf.keras.applications.ResNet152V2(
weights="imagenet" if use_pretrained else None,
include_top=False,
input_shape=input_shape
)
base_model.trainable = not use_pretrained
inputs = tf.keras.Input(shape=input_shape)
x = base_model(inputs, training=False)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.5)(x)
outputs = layers.Dense(num_classes, activation="softmax")(x)
model = Model(inputs, outputs, name="ResNet50V2_Custom")
return model
test.py
import os
from pathlib import Path
import numpy as np
import tensorflow as tf
from core.utilities.helper import get_directories
if __name__ == "__main__":
catalog_path = Path("coin_catalog/augmented")
shape = (128, 128)
testrun_name = "ResNet152V2"
# enum_path = f"trained/enumerations/train_enum_{testrun_name}.json"
enumerations = [str(coin.parts[-1]) for coin in get_directories(Path(catalog_path, "images"))]
model_path = Path(os.path.dirname(__file__), f"trained/object_recognition_{testrun_name}.keras")
model = tf.keras.models.load_model(model_path)
samples = [
"coin_catalog/augmented/crops/(Czech Republic, 50 Korun, 2008)/0_10.png",
"coin_catalog/augmented/crops/(Czech Republic, 1 Koruna, 2018)/0_19.png",
"coin_catalog/augmented/crops/(USA, 2.5 Dollar, 1909)/1_7.png",
"coin_catalog/augmented/crops/(Great britain, 0.5 Souvereign, 1906)/0_13.png",
"coin_catalog/augmented/crops/(Iran, 0.5 Souvereign, 1925)/4_3.png",
"coin_catalog/augmented/crops/(Austria-Hungary, 20 Korona, 1893)/0_8.png",
"coin_catalog/augmented/crops/(Czech Republic, 10 Korun, 2020)/0_3.png",
"coin_catalog/augmented/crops/(France, 2 Franc, 1917)/0_20.png",
"coin_catalog/augmented/crops/(Czech Republic, 5 Korun, 2002)/0_17.png",
"coin_catalog/augmented/crops/(India, 1 Rupee, 1840)/4_26.png",
"coin_catalog/augmented/crops/(Austria-Hungary, 20 Korona, 1893)/0_11.png",
]
results = []
for sample_path in samples:
input_image = tf.keras.utils.load_img(sample_path, target_size=shape)
input_image_array = tf.keras.utils.img_to_array(input_image)
input_image_exp_dim = tf.expand_dims(input_image_array, 0)
predictions = model.predict(input_image_exp_dim)
result = tf.nn.softmax(predictions)
sample_dir = Path(sample_path).parts[-2]
predict_dir = enumerations[np.argmax(result)]
results.append(f"[{'PASS' if sample_dir == predict_dir else 'FAIL'}] {sample_dir} -> {predict_dir}")
[print(result) for result in results]
Подробнее здесь: https://stackoverflow.com/questions/792 ... tensorflow