I am trying put together arcface with inception resnet using Keras, the training looks likes be right, it means, it increases accuracy the loss decreases while the batches and epochs are processed, but when I test the model to get the embeddeds, any face that I test this with, returns the same embedded.
The code of ArcFace layer is based on: https://github.com/4uiiurz1/keras-arcface
class ArcFace(Layer):
def __init__(self, n_classes=8631 , s=30.0, m=0.50, regularizer=None,
**kwargs):
super(ArcFace, self).__init__(**kwargs)
self.n_classes = n_classes
self.s = s
self.m = m
self.regularizer = regularizers.get(regularizer)
def build(self, input_shape):
super(ArcFace, self).build(input_shape[0])
self.W = self.add_weight(name='W',
shape=(input_shape[0][-1], self.n_classes),
initializer='glorot_uniform',
trainable=True,
regularizer=self.regularizer)
def call(self, inputs):
x, y = inputs
c = K.shape(x)[-1]
# normalize feature
x = tf.nn.l2_normalize(x, axis=1)
# normalize weights
W = tf.nn.l2_normalize(self.W, axis=0)
# dot product
logits = x @ W
# add margin
# clip logits to prevent zero division when backward
theta = tf.acos(K.clip(logits, -1.0 + K.epsilon(), 1.0 - K.epsilon()))
target_logits = tf.cos(theta + self.m)
logits = logits * (1 - y) + target_logits * y
# feature re-scale
logits *= self.s
out = tf.nn.softmax(logits)
return out
My model:
def build_model(num_classes):
label_input = Input(shape=(num_classes,))
inception_resnet = inception_resnet_v2.InceptionResNetV2(
include_top=False,
input_shape=(299, 299, 3))
x = MaxPooling2D(pool_size=(2, 2))(inception_resnet.layers[-3].output)
x = BatchNormalization()(x)
x = Dropout(0.5)(x)
x = Flatten()(x)
x = Dense(512, kernel_initializer='he_normal')(x)
x = BatchNormalization()(x)
output = ArcFace(n_classes=num_classes)([x, label_input])
model = Model(inputs=[inception_resnet.input, label_input],
outputs=output)
# model.summary()
return model
The training loop:
def train(model, train_gen, validate_gen, batch_size, out_dir):
opt_adam = optimizers.Adam(clipvalue=5.0)
model.compile(optimizer=opt_adam, loss='categorical_crossentropy',
metrics=['accuracy'])
now = datetime.now()
str_date = now.strftime("%Y-%m-%d-%H")
path = out_dir + '/'
filepath = path + "arcface-weights_" + str_date + \
"_{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1,
save_best_only=True, mode='min')
logdir = "logs/scalars/" + datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = keras.callbacks.TensorBoard(log_dir=logdir,
update_freq='batch', batch_size=batch_size)
callbacks_list = [checkpoint, tensorboard_callback]
history = model.fit_generator(
train_gen,
steps_per_epoch=train_gen.samples/train_gen.batch_size,
epochs=200,
validation_data=validate_gen,
validation_steps=validate_gen.samples/validate_gen.batch_size,
verbose=1,
callbacks=callbacks_list)
Decrease parameters
s = 16.0, m = 0.2