Это довольно интересный вопрос для сиамской сети
Я следую примеру из https://keras.io/examples/mnist_siamese/. Моя модифицированная версия кода находится в этом google colab
Сиамская сеть принимает 2 входа (2 рукописных цифры) и выводит, имеют ли они одинаковую цифру (1) или нет (0).
Каждый из двух входов сначала обрабатывается общей base_network (3 плотных слоя с 2 выпадающими слоями между ними). Input_a извлекается в processing_a, а input_b - в process_b.
Последний слой сиамской сети представляет собой евклидово расстояние между двумя извлеченными тензорами:
distance = Lambda(euclidean_distance,
output_shape=eucl_dist_output_shape)([processed_a, processed_b])
model = Model([input_a, input_b], distance)
Я понимаю,рассуждение об использовании евклидова слоя расстояний для нижней части сети: если объекты извлекаются правильно, то аналогичные входные данные должны иметь аналогичные функции.
Я думаю, почему бы не использовать обычный плотный слойдля нижней части, как:
# distance = Lambda(euclidean_distance,
# output_shape=eucl_dist_output_shape)([processed_a, processed_b])
# model = Model([input_a, input_b], distance)
#my model
subtracted = Subtract()([processed_a, processed_b])
out = Dense(1, activation="sigmoid")(subtracted)
model = Model([input_a,input_b], out)
Я считаю, что если извлеченные объекты похожи, то слой Subtract должен создать небольшой тензор, как разница между извлеченными объектами. Следующий слой, Плотный слой, может узнать, что если входной сигнал мал, выведите 1, в противном случае 0 .
Поскольку евклидовый слой расстояния выводит значение, близкое к 0, когда два входа похожи, а 1 - в противном случае,Мне также нужно инвертировать функцию точности и потерь, как:
# the version of loss and accuracy for Euclidean distance layer
# def contrastive_loss(y_true, y_pred):
# '''Contrastive loss from Hadsell-et-al.'06
# http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
# '''
# margin = 1
# square_pred = K.square(y_pred)
# margin_square = K.square(K.maximum(margin - y_pred, 0))
# return K.mean(y_true * square_pred + (1 - y_true) * margin_square)
# def compute_accuracy(y_true, y_pred):
# '''Compute classification accuracy with a fixed threshold on distances.
# '''
# pred = y_pred.ravel() < 0.5
# return np.mean(pred == y_true)
# def accuracy(y_true, y_pred):
# '''Compute classification accuracy with a fixed threshold on distances.
# '''
# return K.mean(K.equal(y_true, K.cast(y_pred < 0.5, y_true.dtype)))
### my version, loss and accuracy
def contrastive_loss(y_true, y_pred):
margin = 1
square_pred = K.square(y_pred)
margin_square = K.square(K.maximum(margin - y_pred, 0))
# return K.mean(y_true * square_pred + (1-y_true) * margin_square)
return K.mean(y_true * margin_square + (1-y_true) * square_pred)
def compute_accuracy(y_true, y_pred):
'''Compute classification accuracy with a fixed threshold on distances.
'''
pred = y_pred.ravel() > 0.5
return np.mean(pred == y_true)
def accuracy(y_true, y_pred):
'''Compute classification accuracy with a fixed threshold on distances.
'''
return K.mean(K.equal(y_true, K.cast(y_pred > 0.5, y_true.dtype)))
Точность для старой модели: * Точность на тренировочном наборе: 99,55% * Точность на тестовом наборе: 97,42% Это небольшое изменение приводит кмодель, которая ничего не изучает: * Точность на тренировочном наборе: 48,64% * Точность на тестовом наборе: 48,29%
Поэтому мой вопрос:
1,Что не так с моим рассуждением об использовании Substract + Dense для нижней части сиамской сети?
2. Можем ли мы это исправить? Я имею в виду два возможных решения, но я не уверен, (1) извилистая нейронная сеть для выделения признаков (2) более плотные слои для нижней части сиамской сети.