对于暹罗网络来说,这是一个相当有趣的问题
我正在遵循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)暹罗网络下部的密集层。
答案 0 :(得分:1)
在两个相似的示例中,减去两个n维特征向量(使用公共/基本特征提取模型提取)后,在所得n维向量的大部分位置上,您将得到零或大约为零,然后在该位置上进行下一步/ output密集层起作用。另一方面,我们都知道,在ANN模型中,权重的学习方式是,不太重要的特征产生的响应非常少,而有助于决策的突出/有趣的特征则产生很高的响应。现在您可以理解,我们减去的特征向量正好相反,因为当两个示例来自不同类别时,它们会产生较高的响应,而对于相同类别的示例则会产生相反的响应。此外,在输出层中只有一个节点(输出层之前没有其他隐藏层)的情况下,当两个样本属于同一类时,模型很难从零值生成高响应。这可能是解决您的问题的重要点。
基于以上讨论,您可能需要尝试以下想法:
如果卷积神经网络(而不是堆叠的密集层)用于特征提取(正如您所考虑的那样)不会提高您的准确性,我只是感到惊讶,因为这只是另一种方法(特征提取)。