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

标签 python tensorflow machine-learning keras neural-network

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

我正在遵循 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/

相关文章:

python - 如何在virtualenv中设置环境变量

python - 有状态 RNN 在 Keras 功能模型中张量形状错误

tensorflow - 在自己的损失函数中计算预测导数

machine-learning - 如何在WEKA中重新评估模型?

language-agnostic - 主成分分析的工作示例?

python - Apache Spark 中的高效字符串匹配

python - 如何在表单中重新排序漏勺字段?

python - 端口未公开但仍可在内部 docker 网络上访问

python - TensorFlow - 如何使用每个示例一次且仅一次评估所有测试集

random - tensorflow 梯度更新中的确定性?