Сиамская модель ничего не изучает, всегда кодирует изображение в вектор нулей - PullRequest
0 голосов
/ 06 июня 2019

Я пытаюсь обучить сиамскую модель прогнозированию совпадения слов, написанных на двух изображениях.Помимо этой модели также следует уметь различать написание двух людей.Эта проблема аналогична проблеме проверки подписи.

Моя базовая сеть выглядит следующим образом:

def create_base_network_signet(input_shape):
    '''Base Siamese Network'''

    seq = Sequential()
    seq.add(Conv2D(96, kernel_size=(7,7), strides=2, input_shape= input_shape, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(ZeroPadding2D(padding=(2, 2)))

    seq.add(Conv2D(96, kernel_size=(7,7), strides=1, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(MaxPooling2D(pool_size=(3, 3), strides=2))
    seq.add(ZeroPadding2D(padding=(1, 1)))

    seq.add(Conv2D(128, kernel_size=(5,5), strides=1, activation='relu'))
    seq.add(Conv2D(128, kernel_size=(5,5), strides=1, activation='relu'))
    seq.add(MaxPooling2D(pool_size=(3, 3), strides=2))
    seq.add(Dropout(0.3))
    seq.add(ZeroPadding2D(padding=(1, 1)))

    seq.add(Conv2D(384, kernel_size=(3,3), strides=1, activation='relu'))
    seq.add(Conv2D(256, kernel_size=(3,3), strides=1, activation='relu'))
    seq.add(BatchNormalization())
    seq.add(MaxPooling2D(pool_size=(3,3), strides=2))
    seq.add(Dropout(0.3))
    seq.add(ZeroPadding2D(padding=(1,1)))

    seq.add(Conv2D(128, kernel_size=(2,2), strides=1, activation='relu'))
    seq.add(Dropout(0.3))

    seq.add(Flatten(name='flatten'))
    seq.add(Dense(1024, W_regularizer=l2(0.0005), activation='relu', init='glorot_uniform'))
    seq.add(Dropout(0.4))

    seq.add(Dense(128, W_regularizer=l2(0.0005), activation='relu', init='glorot_uniform')) # softmax changed to relu

    return seq

Конечная модель (для контрастных потерь):

base_network = create_base_network_signet(input_shape)
input_a = Input(shape=(input_shape), name="first")
input_b = Input(shape=(input_shape), name="second")

processed_a = base_network(input_a)
processed_b = base_network(input_b)

distance = Lambda(euclidean_distance, output_shape=eucl_dist_output_shape)([processed_a, processed_b])

model = Model(input=[input_a, input_b], output=distance)

Отдельноиз этой модели я также попробовал другие более простые модели в качестве базовой модели.Я также пытался обучать такие модели, как VGG16 и Inception в качестве базовой модели.Во время тренировки всех этих моделей я столкнулся с одной и той же проблемой.Модели в конечном итоге учатся кодировать входное изображение в вектор нулей.

Я пробовал триплетную потерю и контрастную потерю для обучения моделей.Оба в конечном итоге имеют одну и ту же проблему предсказания нулей.Функция контрастных потерь взята из keras учебников.И триплетная потеря определяется как:

def triplet_loss(y_true, y_pred, alpha = 0.5):
    anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]
    pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, positive)), axis=-1)
    neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, negative)), axis=-1)
    basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
    loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0))

    return loss

Я также хочу упомянуть, что когда я тренирую свою модель, используя binary_crossentropy функцию потери.Модель начинает изучать кодировки.Но после точности около 82% точность перестает улучшаться, а потери продолжают уменьшаться.

Вот как выглядит выходное кодирование в случае триплетной потери и контрастной потери:

output of model

Мои тренировочные данные выглядят так:

data example

1 Ответ

1 голос
/ 07 июня 2019

У меня была такая же проблема в одной из моих сиамских сетей, обученных с потерей триплета.Уловка для меня заключалась в том, чтобы удалить tf.reduce_sum() часть из loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0)) строки.Мой соответствующий фрагмент кода потери триплета выглядит следующим образом.

# distance between the anchor and the positive
pos_dist = K.sum(K.square(anchor-positive),axis=1)

# distance between the anchor and the negative
neg_dist = K.sum(K.square(anchor-negative),axis=1)

# compute loss
basic_loss = pos_dist-neg_dist+alpha
loss = K.maximum(basic_loss,0.0)

Наконец, когда вы компилируете модель, сделайте это следующим образом.

model.compile(optimizer=Adam(), loss=triplet_loss)

Я считаю, чтоreduce_sum() часть позаботилась о том, чтобы керасы обучались, когда triplet_loss задается как loss.

Попробуйте и посмотрите, поможет ли это.

...