【问题标题】:Improve Accuracy for a Siamese Network提高连体网络的准确性
【发布时间】:2020-02-12 01:56:27
【问题描述】:

我使用 Keras 功能 API 编写了这个小模型,以查找两个人之间对话的相似性。我正在使用 Gensim 的 Doc2Vec 嵌入将文本数据转换为向量(词汇大小:4117)。我的数据平均分为 56 个阳性病例和 64 个阴性病例。 (是的,我知道数据集很小 - 但我暂时只有这些)。

def euclidean_distance(vects):
    x, y = vects
    sum_square = K.sum(K.square(x - y), axis=1, keepdims=True)
    return K.sqrt(K.maximum(sum_square, K.epsilon()))

ch_inp = Input(shape=(38, 200))
csr_inp = Input(shape=(38, 200))

inp = Input(shape=(38, 200))
net = Embedding(int(vocab_size), 16)(inp)
net = Conv2D(16, 1, activation='relu')(net)
net = TimeDistributed(LSTM(8, return_sequences=True))(net)
out = Activation('relu')(net)

sia = Model(inp, out)

x = sia(csr_inp)
y = sia(ch_inp)

sub = Subtract()([x, y])
mul = Multiply()([sub, sub])

mul_x = Multiply()([x, x])
mul_y = Multiply()([y, y])
sub_xy = Subtract()([x, y])

euc = Lambda(euclidean_distance)([x, y])
z = Concatenate(axis=-1)([euc, sub_xy, mul])
z = TimeDistributed(Bidirectional(LSTM(4)))(z)
z = Activation('relu')(z)
z = GlobalMaxPooling1D()(z)
z = Dense(2, activation='relu')(z)
out = Dense(1, activation = 'sigmoid')(z)

model = Model([ch_inp, csr_inp], out)
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])

问题是:我的准确率不会从 60.87% 提高 - 我跑了 10 个 epoch 并且准确率保持不变。我在代码中所做的事情是否导致了这种情况?还是我的数据有问题?

我还对一些 Sklearn 模型进行了 K-Fold 验证,并从数据集中得到了这些结果:

另外,下面附上我的数据集的概述:

我肯定在这个问题上苦苦挣扎 - 所以这里的任何帮助都将不胜感激。谢谢!

更新: 我将数据大小增加到 1875 个训练样本。其准确率提高到 70.28%。但它在所有迭代中仍然保持不变。

【问题讨论】:

  • 对于将来遇到这个问题的任何人,我也在这里发布了这个问题:(以防stackoverflow上没有人回答)groups.google.com/forum/#!topic/keras-users/_uwgRTQUKbU
  • 您好,我建议您学习更多基础知识,特别是什么是过拟合、训练和验证集,然后再尝试阅读有关如何将机器学习方法应用于数量很少的 NLP 问题的现代技术训练示例。
  • 嗯,这不是很有帮助。我确实为上面链接的相同数据集尝试了统计模型,但事实证明它们的准确性也较小。我将数据大小增加到 1875 个样本,这将 Keras 模型的准确度提高到了 70.28%,但它仍然几乎保持不变。如果您对我要测试的模型类型或当前模型的更改有任何建议,请分享。
  • 问题是这种问题在 SO 中是题外话,它不是编程问题,而是研究问题,所以你不太可能在这里得到有用的答案。
  • 也许你的模型对于这个任务来说太简单了?

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


【解决方案1】:

我在那里看到了两件可能很重要的事情。

  • 您在LSTM 之后使用'relu'。 Keras 中的LSTM 已经将'tanh' 作为默认激活。所以,虽然你没有锁定你的模型,但你让它更难学习,激活将结果限制在小范围加上一个减少负值的范围内

  • 您正在使用'relu' 和很少 个单位!单元少、初始化差、学习率大和运气不好的 Relu 会卡在没有任何梯度的零区域。

如果您的损失完全冻结,很可能是由于上述第二点。即使它没有冻结,它也可能只使用 2 个 Dense 单元中的一个单元,例如,使层非常差。

你应该从下面做一些事情:

  • 您的模型很小,因此请停止使用 'relu' 并改用 'tanh'。这将为您的模型提供应有的预期功能。
  • 否则,您绝对应该增加单元数,无论是LSTM 还是Dense,这样'relu' 才不会轻易卡住。
  • 您可以在Dense 之后和'relu' 之前添加BatchNormalization 层,这样可以保证大量单位始终高于零。

无论如何,不​​要在LSTM 之后使用'relu'。


另一种方法是使模型更强大。

例如:

z = TimeDistributed(Bidirectional(LSTM(4)))(z)
z = Conv1D(10, 3, activation = 'tanh')(z) #or 'relu' maybe
z = MaxPooling1D(z)
z = Conv1D(15, 3, activation = 'tanh')(z) #or 'relu' maybe
z = Flatten()(z) #unless the length is variable, then GlobalAveragePooling1D()(z)
z = Dense(10, activation='relu')(z)
out = Dense(1, activation = 'sigmoid')(z)

【讨论】:

  • 我改成了:net = TimeDistributed(LSTM(32, return_sequences=True))(net) net = BatchNormalization()(net) out = Activation('tanh')(net) 但是准确率还是一样的! :(
  • 问题不只是LSTM,看一下整个模型。
  • 不要在 LSTM 之后添加激活,它已经有一个,这是标准的。
  • 移除了激活层——我最初关注的是article,他们使用了 Relu 激活层,但即使移除了它——你认为可能是 TimeDistributedLSTM 造成的吗? net = TimeDistributed(LSTM(32, return_sequences=True))(net) out = BatchNormalization()(net)
  • 说实话我不知道。那将是我的第一次尝试,但我也会尝试使模型更大。请参阅问题中的示例。
猜你喜欢
  • 2016-08-02
  • 2018-01-10
  • 2017-09-06
  • 2017-08-05
  • 1970-01-01
  • 2020-12-09
  • 2018-06-05
  • 2012-08-30
相关资源
最近更新 更多