我一直在尝试在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中,作者使用带logits的masking和softmax交叉熵。我还没有如何在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。
有什么想法吗?
谢谢
答案 0 :(得分:1)
问题在于您的目标值似乎是时间分布的。因此,您有109个时间步长,其单目标矢量大小为2。这就是为什么您需要return_sequences = True的原因。否则,您将只将最后一个时间步输入到Dense层,而您将只有一个输出。
因此,根据需要,可以将其保持为现在,或者如果只是最后一个时间步就足够了,就可以摆脱它,但是您需要相应地调整y值。
答案 1 :(得分:1)
作者使用logit的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 ,并且索引1的维将被视为时间维。
(强调是我的)
我不确定您的问题是在什么情况下发生空断言。
如果以前有一个带有return_sequences=False
的循环图层,那么您将再次缺少维度(不过,我不能告诉您为什么断言为空)。
如果您之前有一个return_sequences=True
的循环层,它应该可以工作,但是它将完全没用,因为无论如何Dense
都是以时间分布的方式应用的。如果我没记错的话,Dense
层的这种行为在某些较旧的Keras版本中已更改(他们应该在此处确实更新示例并停止使用Dense
!)。由于您所引用的代码已经很老了,很有可能当时需要TimeDistributed
,但现在不再需要了。
如果您计划恢复丢失的尺寸,TimeDistributed
将无济于事,但RepeatVector
会有所帮助。但是,正如已经说过的那样,首先最好使用return_sequences=True
。