Arcface architecture returning the same embedding for any face

1k views Asked by At

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)
1

There are 1 answers

0
Sonfire On

Decrease parameters s = 16.0, m = 0.2