如何为分类任务构建LSTM神经网络

5
我有一些记录两个人之间对话的数据。每个句子都有某种分类。我试图使用NLP网络对每个句子进行分类。我尝试了卷积网络并获得了不错的结果(虽然没有突破性的)。我想既然这是前后交替的对话,LSTM网络可能会产生更好的结果,因为之前说过的话可能会对接下来的话产生很大影响。

Type of RNN nets

如果我按照上面的结构进行操作,我会认为我正在进行多对多操作。我的数据如下。
X_train = [[sentence 1],  
           [sentence 2],
           [sentence 3]]
Y_train = [[0],
           [1],
           [0]]

数据已使用word2vec进行处理。然后我按以下方式设计了我的网络...
model = Sequential()      
model.add(Embedding(len(vocabulary),embedding_dim,
          input_length=X_train.shape[1]))
model.add(LSTM(88))
model.add(Dense(1,activation='sigmoid'))
model.compile(optimizer='rmsprop',loss='binary_crossentropy',
              metrics['accuracy'])
model.fit(X_train,Y_train,verbose=2,nb_epoch=3,batch_size=15)

我假设这个设置一次只输入一个句子批。然而,如果在model.fit中shuffle不等于false,则会接收到打乱顺序的批,那么在这种情况下,LSTM网络有什么用处呢?从对该主题的研究来看,要实现多对多结构,需要改变LSTM层。
model.add(LSTM(88,return_sequence=True))

而输出层需要...

model.add(TimeDistributed(Dense(1,activation='sigmoid')))

当切换到这种结构时,我在输入大小上遇到了错误。我不确定如何重新格式化数据以满足此要求,也不知道如何编辑嵌入层以接收新的数据格式。
非常感谢任何帮助!如果您有任何更好的方法或建议,我很乐意听取!
1个回答

4
您的第一次尝试很好。洗牌发生在句子之间,只是训练样本在它们之间进行洗牌,以便它们不总是以相同的顺序出现。句子内部的单词不会被洗牌。
或者我可能没有正确理解问题?
编辑:更好地理解问题后,这是我的建议。
数据准备:将语料库分成n个句子块(它们可以重叠)。您应该有一个形状类似于(number_blocks_of_sentences, n, number_of_words_per_sentence)的列表,因此基本上是包含n个句子块的2D数组列表。n不应太大,因为LSTM在训练时无法处理巨大数量的序列元素(梯度消失)。您的目标应该是形状数组(number_blocks_of_sentences, n, 1),因此也是包含句子块中每个句子的类别的2D数组列表。
模型:
n_sentences = X_train.shape[1]  # number of sentences in a sample (n)
n_words = X_train.shape[2]      # number of words in a sentence

model = Sequential()
# Reshape the input because Embedding only accepts shape (batch_size, input_length) so we just transform list of sentences in huge list of words
model.add(Reshape((n_sentences * n_words,),input_shape = (n_sentences, n_words)))
# Embedding layer - output shape will be (batch_size, n_sentences * n_words, embedding_dim) so each sample in the batch is a big 2D array of words embedded 
model.add(Embedding(len(vocabaulary), embedding_dim, input_length = n_sentences * n_words ))
# Recreate the sentence shaped array
model.add(Reshape((n_sentences, n_words, embedding_dim))) 
# Encode each sentence - output shape is (batch_size, n_sentences, 88)
model.add(TimeDistributed(LSTM(88)))
# Go over lines and output hidden layer which contains info about previous sentences - output shape is (batch_size, n_sentences, hidden_dim)
model.add(LSTM(hidden_dim, return_sequence=True))
# Predict output binary class - output shape is (batch_size, n_sentences, 1)
model.add(TimeDistributed(Dense(1,activation='sigmoid')))
...

这应该是一个不错的开始。

希望这能帮助到您。


如果我没有正确表达我的问题,我很抱歉。由于数据是一段对话,前一句话所说的对后一句话有影响。因此,我正在尝试设置网络来学习对话流程并对每个句子进行分类。这就是为什么我尝试使用return_sequence的原因,这样网络就可以在分类当前句子的同时保留有关先前句子的信息。 - DJK
一个LSTM被馈送一系列向量。在您的情况下,它是一系列单词嵌入。它会为您的每个句子返回长度为88的向量,您可以使用密集层将其缩减为1个输出。因此,它只关心一次处理一个句子。这就是您目前所做的。这是否是您想要做的? - Nassim Ben
好的,这是一个全新的故事。然后,您应该重新塑造您的输入数据,并将其作为多个句子块发送。然后,在每个句子上使用LSTM进行时间分布式编码。您将获得一系列由88长度向量表示的句子序列。然后使用第二个LSTM,返回序列=True,它将再次输出每个句子的向量,但考虑到先前的句子。然后像您现在在最后一层上所做的那样进行时间分布。 - Nassim Ben
我理解你所解释的总体概念,但是我不确定如何实现它。这是我第一次尝试使用LSTM。我尝试了调整数组的形状,因为我看到其他人建议这样做,但是我遇到了错误,特别是在嵌入层上,它似乎只能接受2D输入。如果您可以添加一个代码示例,我将非常感激。 - DJK
这是一个非常出色的答案。代码运行没有任何问题,只是运行了一组虚假数据测试以确保其正常运行。你不知道你刚刚帮我摆脱了什么困境! - DJK
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接