Using my own Images for TripletSemiHardLoss from Keras addons

Viewed 125

My image folder is set up as one main folder with 130 separate folders, each folder with its own images folder_with_130_folders-
folder1_class1-
img_in_class1_folder.jpg
img_in_class1_folder.jpg
...
folder130_class130-
img_in_class130_folder.jpg
img_in_class130_folder.jpg


train_dataset =  prod_images.flow_from_directory(directory, target_size=(225, 225), class_mode='categorical', subset='training', save_format='jpg')
validation_set =  prod_images.flow_from_directory(directory, target_size=(225, 225), class_mode='categorical', subset='validation', save_format='jpg')

(x_train, y_train), (x_test, y_test) = train_dataset.next(), validation_set.next()

model = models.Sequential()
model.add(layers.Conv2D(filters=128, kernel_size=2, padding='same', activation='relu', input_shape=(225, 225, 3)))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.3))
model.add(layers.Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.3))
model.add(layers.Conv2D(filters=32, kernel_size=2, padding='same', activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.3))
model.add(layers.Conv2D(filters=16, kernel_size=2, padding='same', activation='relu'))
model.add(layers.MaxPooling2D(pool_size=2))
model.add(layers.Dropout(0.3))
model.add(layers.Flatten())
model.add(layers.Dense(256, activation=None)) # No activation on final dense layer
model.add(layers.Lambda(lambda x: tf.math.l2_normalize(x, axis=1))) # L2 normalize embeddings

model.summary()

model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=0.001), loss=tfa.losses.TripletSemiHardLoss())

model_fit = model.fit(train_dataset, steps_per_epoch=4, epochs=20, verbose=1, validation_data = validation_set)```
1 Answers

As stated in the docs regarding the tfa.losses.TripletSemiHardLoss:

We expect labels y_true to be provided as 1-D integer Tensor with shape [batch_size] of multi-class integer labels. And embeddings y_pred must be 2-D float Tensor of l2 normalized embedding vectors

You should, therefore, use sparse integer labels (sparse_categorical) instead of one-hot encoded labels (categorical). Here is a working example:

import tensorflow as tf
import tensorflow_addons as tfa
import pathlib

dataset_url = "https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz"
data_dir = tf.keras.utils.get_file('flower_photos', origin=dataset_url, untar=True)
data_dir = pathlib.Path(data_dir)

batch_size = 32

train_ds = tf.keras.utils.image_dataset_from_directory(
  data_dir,
  validation_split=0.2,
  label_mode='int', # sparse categorical
  subset="training",
  seed=123,
  image_size=(225, 225),
  batch_size=batch_size)

model = tf.keras.Sequential()
model.add(tf.keras.layers.Conv2D(filters=128, kernel_size=2, padding='same', activation='relu', input_shape=(225, 225, 3)))
model.add(tf.keras.layers.MaxPooling2D(pool_size=2))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Conv2D(filters=64, kernel_size=2, padding='same', activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=2))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Conv2D(filters=32, kernel_size=2, padding='same', activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=2))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Conv2D(filters=16, kernel_size=2, padding='same', activation='relu'))
model.add(tf.keras.layers.MaxPooling2D(pool_size=2))
model.add(tf.keras.layers.Dropout(0.3))
model.add(tf.keras.layers.Flatten())
model.add(tf.keras.layers.Dense(256, activation=None)) # No activation on final dense layer
model.add(tf.keras.layers.Lambda(lambda x: tf.math.l2_normalize(x, axis=-1))) # L2 normalize embeddings

model.summary()

model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate=0.001), loss=tfa.losses.TripletSemiHardLoss())

model_fit = model.fit(train_ds, epochs=5, verbose=1)

In your case you have to set the parameter class_mode to sparse:

flow_from_directory(directory, target_size=(225, 225), class_mode='sparse', subset='training', save_format='jpg')
Related