【问题标题】:Keras: BiLSTM only works when return_sequences=TrueKeras:BiLSTM 仅在 return_sequences=True 时有效
【发布时间】:2019-04-15 09:08:54
【问题描述】:

我一直在尝试在 Keras 中实现这个 BiLSTM:https://github.com/ffancellu/NegNN

这就是我所在的位置,而且它确实有效:

inputs_w = Input(shape=(sequence_length,), dtype='int32')
inputs_pos = Input(shape=(sequence_length,), dtype='int32')
inputs_cue = Input(shape=(sequence_length,), dtype='int32')

w_emb = Embedding(vocabulary_size+1, embedding_dim, input_length=sequence_length, trainable=False)(inputs_w)
p_emb = Embedding(tag_voc_size+1, embedding_dim, input_length=sequence_length, trainable=False)(inputs_pos)
c_emb = Embedding(2, embedding_dim, input_length=sequence_length, trainable=False)(inputs_cue)

summed = keras.layers.add([w_emb, p_emb, c_emb])

BiLSTM = Bidirectional(CuDNNLSTM(hidden_dims, return_sequences=True))(summed)

DPT = Dropout(0.2)(BiLSTM)

outputs = Dense(2, activation='softmax')(DPT)

checkpoint = ModelCheckpoint('bilstm_one_hot.hdf5', monitor='val_loss', verbose=1, save_best_only=True, mode='auto')
early = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=5, verbose=1, mode='auto')

model = Model(inputs=[inputs_w, inputs_pos, inputs_cue], outputs=outputs)

model.compile('adam', loss='categorical_crossentropy', metrics=['accuracy'])

model.summary()

model.fit([X_train, X_pos_train, X_cues_train], Y_train, batch_size=batch_size, epochs=num_epochs, verbose=1, validation_split=0.2, callbacks=[early, checkpoint])

在原始代码中,在Tensorflow中,作者使用了masking和softmax cross entropy with logits。我还不知道如何在 Keras 中实现这一点。如果您有任何建议,请不要犹豫。

我的主要问题是 return_sequences=True。作者似乎没有在他的 tensorflow 实现中使用它,当我将其设置为 False 时,我收到此错误:

ValueError: Error when checking target: expected dense_1 to have 2 dimensions, but got array with shape (820, 109, 2)

我也尝试过使用:

outputs = TimeDistributed(Dense(2, activation='softmax'))(BiLSTM)

返回和 AssertionError 没有任何信息。

有什么想法吗?

谢谢

【问题讨论】:

    标签: tensorflow keras nlp


    【解决方案1】:

    作者在 logits 中使用了 masking 和 softmax 交叉熵。我还不知道如何在 Keras 中实现它。

    关于 logits 的 softmax 交叉熵,你做得对。 softmax_cross_entropy_with_logits 作为损失函数 + 最后一层没有激活函数与你的方法相同,categorical_crossentropy 作为损失 + softmax 最后一层激活。唯一的区别是后者在数值上不太稳定。如果这对您来说是个问题,您可以(如果您的 Keras 后端是 tensorflow)只需传递 tf.softmax_cross_entropy_with_logits 作为您的损失。如果您有另一个后端,则必须在那里寻找等效的。

    关于屏蔽,我不确定我是否完全理解作者在做什么。但是,在 Keras 中,Embedding 层有一个 mask_zero 参数,您可以将其设置为 True。在这种情况下,所有具有0 的时间步将在所有进一步的计算中被忽略。但是,在您的来源中,被屏蔽的不是0,因此您必须相应地调整索引。如果这不起作用,您可以将 Keras 中的 Masking 层放在循环层之前,但我对此没有什么经验。

    我的主要问题是 return_sequences=True。作者不 似乎在使用它

    是什么让你认为他不使用它?仅仅因为该关键字没有出现在代码中并不意味着什么。但我也不确定。代码已经很老了,我在文档中找不到它可以说明默认值是什么。

    无论如何,如果您想使用return_sequences=False(无论出于何种原因),请注意这会改变图层的输出形状:

    • return_sequences=True 输出形状为(batch_size, timesteps, features)
    • return_sequences=False 输出形状为(batch_size, features)

    您得到的错误基本上是告诉您网络的输出比您提供的目标y 值少一维。 所以,在我看来,return_sequences=True 正是您所需要的,但如果没有进一步的信息,就很难说。

    那么,关于TimeDistributed。我不太确定你想用它实现什么,但引用文档:

    此包装器将层应用于输入的每个时间切片。

    输入至少应为 3D,索引一的维度将被视为时间维度。

    (重点是我的)

    我不确定你的问题,在哪种情况下会出现空断言。

    如果您之前有一个带有return_sequences=False 的循环层,那么您又会丢失一个维度(不过,我无法告诉您为什么断言为空)。

    如果你之前有一个带有return_sequences=True 的循环层,它应该可以工作,但它完全没用,因为Dense 无论如何都是以时间分布的方式应用的。如果我没记错的话,Dense 层的这种行为在一些较旧的 Keras 版本中发生了变化(他们应该真正更新那里的示例并停止使用Dense!)。由于您所指的代码已经很老了,很可能当时需要TimeDistributed,但现在不再需要了。

    如果您的计划是恢复缺失的维度,TimeDistributed 不会帮助您,但 RepeatVector 会。但是,如前所述,在这种情况下,最好首先使用return_sequences=True

    【讨论】:

    • 感谢您的解释!你猜对了。当 return_sequences=False 时出现空断言,这是正常的。显然,我的实现与 Fancellu 的非常相似。但是结果明显低于我更新到 tensorflow 1.13 的 tensorflow 实现所得到的结果。接下来我会调查的。
    • 屏蔽呢?在原始代码中,有一个占位符被输入然后用于计算损失:self.mask = tf.placeholder("float",name="input_mask") ... _mask = [1 if t!=vocsize - 1 else 0 for t in X] ... _bilstm.mask: _mask ... self.loss = tf.reduce_sum(tf.multiply(tf.nn.softmax_cross_entropy_with_logits_v2(labels = self.y, logits=outputs),self.mask))/tf.reduce_sum(self.mask)
    • @D.Clem 哦,对不起,我完全错过了你问题的掩蔽部分。很快就会更新我的答案
    • 感谢您的更新。我能够通过使用具有 -1 到 1 比例 keras.initializers.RandomUniform(minval=-1.0, maxval=1.0, seed=None) 的特定 RandomUniform 初始化嵌入来复制结果现在我正在尝试添加一个注意力层。但是这里的层输出一个二维张量,形状为:(样本,特征),它不适用于我的网络:kaggle.com/takuok/bidirectional-lstm-and-attention-lb-0-043
    • @D.Clem 不应该太复杂而无法适应您的形状。如果您遇到特定问题,我建议您打开一个新问题。
    【解决方案2】:

    问题是您的目标值似乎是时间分布的。因此,您有 109 个时间步长,其中 onehot 目标向量大小为 2。这就是您需要 return_sequences=True 的原因。否则,您只需将最后一个时间步提供给 Dense 层,您将只有一个输出。

    因此,根据您的需要,您需要保持它现在的样子,或者如果最后一个时间步对您来说足够了,您可以摆脱它,但是您需要相应地调整 y 值。

    【讨论】:

    • 好的,在这种情况下,每个单词都构成一个时间步长。顺便说一句:820:句子,109:单词(填充),2:标签(每个单词都是 O_scope 或 I_scope) 知道为什么这两个与 return_sequence=True 相同吗?输出=密集(2,激活='softmax')(BiLSTM)输出=时间分布(密集(2,激活='softmax'))(BiLSTM)
    • @D.Clem TimeDisributed 在较新的 Keras 版本中对 Dense 无效,请参阅我的回答
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-19
    • 1970-01-01
    相关资源
    最近更新 更多