连体网络,下部使用致密层而不是欧氏距离层

时间:2019-10-03 13:58:16

标签: python tensorflow machine-learning keras neural-network

对于暹罗网络来说,这是一个相当有趣的问题

我正在遵循https://keras.io/examples/mnist_siamese/中的示例。 我修改后的代码版本在此google colab

暹罗网络输入2个输入(2个手写数字)并输出它们是否为相同数字(1)(0)。

两个输入中的每个首先由共享的base_network处理(3个密集层,中间有2个Dropout层)。将input_a提取到created_a中,将input_b提取到created_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)

我的推理是,如果提取的特征相似,则减法层应产生一个小的张量,作为提取的特征之间的差异。下一层,密集层,可以知道如果输入较小,则输出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 个答案:

答案 0 :(得分:1)

在两个相似的示例中,减去两个n维特征向量(使用公共/基本特征提取模型提取)后,在所得n维向量的大部分位置上,您将得到零或大约为零,然后在该位置上进行下一步/ output密集层起作用。另一方面,我们都知道,在ANN模型中,权重的学习方式是,不太重要的特征产生的响应非常少,而有助于决策的突出/有趣的特征则产生很高的响应。现在您可以理解,我们减去的特征向量正好相反,因为当两个示例来自不同类别时,它们会产生较高的响应,而对于相同类别的示例则会产生相反的响应。此外,在输出层中只有一个节点(输出层之前没有其他隐藏层)的情况下,当两个样本属于同一类时,模型很难从零值生成高响应。这可能是解决您的问题的重要点。

基于以上讨论,您可能需要尝试以下想法:

  • 变换相减的特征向量以确保在相似时您可以得到较高的响应,这可能是通过对1进行减法或倒数(乘法逆)然后进行归一化。
  • 在输出层之前添加更多的密集层。

如果卷积神经网络(而不是堆叠的密集层)用于特征提取(正如您所考虑的那样)不会提高您的准确性,我只是感到惊讶,因为这只是另一种方法(特征提取)。