对于暹罗网络来说,这是一个相当有趣的问题
我正在遵循 https://keras.io/examples/mnist_siamese/ 中的示例。 我修改后的代码版本在这个 google colab
孪生网络接受 2 个输入(2 个手写数字)并输出,无论它们是否是相同的数字(1)或不同的数字(0)。
两个输入首先由共享的 base_network 处理(3 个 Dense 层,中间有 2 个 Dropout 层)。 input_a被提取到processed_a中,input_b被提取到processed_b中。
孪生网络的最后一层是两个提取的张量之间的欧氏距离层:
distance = Lambda(euclidean_distance,
output_shape=eucl_dist_output_shape)([processed_a, processed_b])
model = Model([input_a, input_b], distance)
我理解对网络下部使用欧几里德距离层背后的推理:如果特征提取得很好,那么相似的输入应该具有相似的特征。
我在想,为什么下部不使用普通的 Dense 层,如下:
# 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 层应该产生一个小张量,作为提取的特征之间的差异。下一层,Dense层,可以学习到如果输入很小,则输出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。我对 Siamese 网络的下部使用 Substract + Dense 的推理有什么问题吗?
<强>2。我们可以解决这个问题吗?我有两个可能的解决方案,但我没有信心,(1)用于特征提取的卷积神经网络(2)用于暹罗网络下部的更密集的层。
最佳答案
在两个类似的示例中,在减去两个 n 维特征向量(使用公共(public)/基本特征提取模型提取)后,您将在生成的 n 维向量的大部分位置中得到零或大约零值,下一个/output 密集层有效。另一方面,我们都知道,在 ANN 模型中,权重的学习方式是不太重要的特征产生的响应非常少,而有助于决策的突出/有趣的特征产生高响应。现在您可以理解,我们减去的特征向量只是在相反的方向,因为当两个示例来自不同的类时,它们会产生高响应,而对于来自同一类的示例则相反。此外,对于输出层中的单个节点(输出层之前没有额外的隐藏层),当两个样本属于同一类时,模型很难学习从零值生成高响应。这可能是解决您的问题的重要一点。
根据上述讨论,您可能想尝试以下想法:
- 可以通过从 1 或倒数(乘法逆)中进行减法,然后进行归一化来转换相减后的特征向量,以确保在存在相似性时获得高响应。
- 在输出层之前添加更多 Dense 层。
如果卷积神经网络而不是用于特征提取的堆叠密集层(正如您所想的那样)并不能提高您的准确性,我不会感到惊讶,因为它只是执行相同操作(特征提取)的另一种方式。
关于python - 连体网络,下部使用密集层而不是欧氏距离层,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58220747/