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

Это довольно интересный вопрос для сиамской сети

Я следую примеру из 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) более плотные слои для нижней части сиамской сети.

1 Ответ

1 голос
/ 03 октября 2019

В случае двух аналогичных примеров, после вычитания двух n-мерных векторов объектов (извлеченных с использованием модели извлечения общих / базовых объектов), вы получите нулевое или около нулевого значения в большей части местоположения результирующего n-мерного вектора, на котором следующий/ output Плотный слой работает. С другой стороны, мы все знаем, что в модели ANN веса изучаются таким образом, что менее важные функции дают очень меньше откликов, а заметные / интересные функции, способствующие принятию решений, дают высокие отклики. Теперь вы можете понять, что наш вектор вычитаемых объектов находится в противоположном направлении, потому что, когда два примера относятся к разному классу, они дают высокие отклики и противоположны для примеров из одного класса. Кроме того, с одним узлом в выходном слое (без дополнительного скрытого слоя перед выходным слоем) модели довольно сложно научиться генерировать высокий отклик из нулевых значений, когда два образца одного и того же класса. Это может быть важным моментом для решения вашей проблемы.

Исходя из вышеизложенного, вы можете попробовать следующие идеи:

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

Я не удивлюсь, еслисверточная нейронная сеть вместо сложенного плотного слоя для извлечения объектов (как вы думаете) не сильно повышает вашу точность, поскольку это просто еще один способ сделать то же самое (извлечение объектов).

...