Сиамская нейронная сеть с двумя предварительно обученными ResNet 50 - странное поведение при тестировании модели - PullRequest
0 голосов
/ 27 мая 2019

Я построил сиамскую нейронную сеть, используя для этого Keras lib.Моя модель имеет два входа с формой (64,64,3), два предварительно обученных ResNet-50.Функция потерь - это двоичная кросс-энтропия.

Модель основана на этой статье ссылка

Во время поезда у меня очень хорошая точность / добротность, около 0,99 / 0,98,и низкие потери 0,01 / 0,05.

Но когда я тестирую свою сохраненную модель, я получаю плохие результаты.Модель не может распознать даже две одинаковые картинки.

Также я заметил странное поведение: чем больше количество эпох, тем хуже результат.Например, сравнивая два идентичных изображения, обученная модель с 10 эпохами дает прогноз: "8.jpg": 0.5180479884147644 , но та же модель обучается с 100 Эпоха дает "8.jpg": 5.579867080537926E-13 Однако для 100 эпох у меня есть лучшие результаты обучения.

Я пробовал другую модельдля CNN: ResNet18, различные формы ввода, например (224,224,3) или (128,128,3) .

Также я использую триаду без предварительной подготовки, только ResNet50 / ResNet18 без предварительно обученных весов.Но у меня такие же плохие результаты при тестировании реальной модели.

Мой код

def create_base_model(image_shape, dropout_rate, suffix=''):
    I1 = Input(shape=image_shape)
    model = ResNet50(include_top=False, weights='imagenet', input_tensor=I1, pooling=None)
    model.layers.pop()
    model.outputs = [model.layers[-1].output]
    model.layers[-1].outbound_nodes = []

    for layer in model.layers:
        layer.name = layer.name + str(suffix)
        layer.trainable = False

    flatten_name = 'flatten' + str(suffix)

    x = model.output
    x = Flatten(name=flatten_name)(x)
    x = Dense(1024, activation='relu')(x)
    x = Dropout(dropout_rate)(x)
    x = Dense(512, activation='relu')(x)
    x = Dropout(dropout_rate)(x)

    return x, model.input


def create_siamese_model(image_shape, dropout_rate):

    output_left, input_left = create_base_model(image_shape, dropout_rate)
    output_right, input_right = create_base_model(image_shape, dropout_rate, suffix="_2")

    L1_layer = Lambda(lambda tensors: tf.abs(tensors[0] - tensors[1]))
    L1_distance = L1_layer([output_left, output_right])
    L1_prediction = Dense(1, use_bias=True,
                          activation='sigmoid',
                          kernel_initializer=RandomNormal(mean=0.0, stddev=0.001),
                          name='weighted-average')(L1_distance)

    prediction = Dropout(0.2)(L1_prediction)

    siamese_model = Model(inputs=[input_left, input_right], outputs=prediction)

    return siamese_model

siamese_model = create_siamese_model(image_shape=(64, 64, 3),
                                         dropout_rate=0.2)

siamese_model.compile(loss='binary_crossentropy',
                      optimizer=Adam(lr=0.0001),
                      metrics=['binary_crossentropy', 'acc'])
siamese_model.fit_generator(train_gen,
                            steps_per_epoch=1000,
                            epochs=10,
                            verbose=1,
                            callbacks=[checkpoint, tensor_board_callback, lr_reducer, early_stopper, csv_logger],
                            validation_data=validation_data,
                            max_q_size=3)

siamese_model.save('siamese_model.h5')



# and the my prediction
siamese_net = load_model('siamese_model.h5', custom_objects={"tf": tf})

X_1 = [image, ] * len(markers)
batch = [markers, X_1]
result = siamese_net.predict_on_batch(batch)

# I've tried also to check identical images 
markers = [image]
X_1 = [image, ] * len(markers)
batch = [markers, X_1]
result = siamese_net.predict_on_batch(batch)

У меня есть некоторые сомнения относительно моего метода прогнозирования.Может ли кто-нибудь помочь мне выяснить, что не так с предсказаниями?

1 Ответ

1 голос
/ 27 мая 2019

Ожидается то, что вы получаете. Я не уверен, что вы подразумеваете под

Также я заметил странное поведение: чем больше количество эпох, тем хуже результат.

Но показанные вами результаты действительны и ожидаемы. Давайте начнем с того, что выводит модель. Выход вашей модели - это (нормализованное) расстояние между первым и вторым входами. Если входы похожи, то расстояние должно быть близко к нулю. По мере увеличения числа этапов обучения модель учится идентифицировать входы, то есть, если входы похожи, модель учится выводить значения, близкие к нулю, а если входы различаются, модель учится выводить значения, близкие к единице. Итак,

... обученная модель с 10 эпохами дает прогноз: "8.jpg": 0.5180479884147644, но та же модель, обученная с 100 эпохами, дает "8.jpg": 5.579867080537926E-13 Однако для 100 эпох у меня есть лучшие результаты обучения.

, подтверждает, что модель узнала, что два входа аналогичны, а выходные данные 5.579867080537926E-13 ~ 0 (приблизительно близки к 0).

Несмотря на то, что модель работает хорошо, есть одна проблема, которую я заметил в определении модели: - Выходной слой - это слой исключения. Dropout не является допустимым выходным слоем. Этим параметром вы, случайно, с вероятностью 0,2 устанавливаете выход модели равным нулю.

Давайте предположим, что целевая переменная имеет 1 (два входа различны), и модель научилась правильно идентифицировать изображения и выводит значение, близкое к 1, перед выпадающим слоем. Далее давайте предположим, что выпадающий слой решил установить выход равным нулю. Таким образом, вывод модели будет нулевым. Даже если слои перед выпадающим слоем работали хорошо, из-за выпадающего слоя они будут наказаны. Если это не то, что вы ищете, удалите последний выпадающий слой.

L1_prediction = Dense(1, use_bias=True,
                    activation='sigmoid',
                    kernel_initializer=RandomNormal(mean=0.0, stddev=0.001),
                    name='weighted-average')(L1_distance)


siamese_model = Model(inputs=[input_left, input_right], outputs=L1_prediction)

Однако иногда такое поведение необходимо, если вы хотите добавить шум к модели. Это имеет тот же эффект со случайным изменением целевой переменной, когда значение равно 1.

...