这个“flatten层”在我的LSTM中有什么作用?

5

我正在使用Keras为情感分析创建一个LSTM,使用IMDB数据库的(子集)。如果我在最后一个密集层之前添加一个flatten层,我的训练、验证和测试准确性会显着提高:

def lstm_model_flatten():
    embedding_dim = 128
    model = Sequential()
    model.add(layers.Embedding(vocab_size, embedding_dim, input_length=maxlen))
    model.add(layers.LSTM(128, return_sequences = True,  dropout=0.2)) 
    # Flatten layer
    model.add(layers.Flatten())
    model.add(layers.Dense(1,activation='sigmoid'))
    model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
    model.summary()
    return model

这会很快过拟合,但验证准确率可以达到约76%:
Model: "sequential_43"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding_42 (Embedding)     (None, 500, 128)          4768256   
_________________________________________________________________
lstm_63 (LSTM)               (None, 500, 128)          131584    
_________________________________________________________________
flatten_10 (Flatten)         (None, 64000)             0         
_________________________________________________________________
dense_40 (Dense)             (None, 1)                 64001     
=================================================================
Total params: 4,963,841
Trainable params: 4,963,841
Non-trainable params: 0
_________________________________________________________________
Epoch 1/7
14/14 [==============================] - 26s 2s/step - loss: 0.6911 - accuracy: 0.5290 - val_loss: 0.6802 - val_accuracy: 0.5650
Epoch 2/7
14/14 [==============================] - 23s 2s/step - loss: 0.6451 - accuracy: 0.6783 - val_loss: 0.6074 - val_accuracy: 0.6950
Epoch 3/7
14/14 [==============================] - 23s 2s/step - loss: 0.4594 - accuracy: 0.7910 - val_loss: 0.5237 - val_accuracy: 0.7300
Epoch 4/7
14/14 [==============================] - 23s 2s/step - loss: 0.2566 - accuracy: 0.9149 - val_loss: 0.4753 - val_accuracy: 0.7650
Epoch 5/7
14/14 [==============================] - 23s 2s/step - loss: 0.1397 - accuracy: 0.9566 - val_loss: 0.6011 - val_accuracy: 0.8050
Epoch 6/7
14/14 [==============================] - 23s 2s/step - loss: 0.0348 - accuracy: 0.9898 - val_loss: 0.7648 - val_accuracy: 0.8100
Epoch 7/7
14/14 [==============================] - 23s 2s/step - loss: 0.0136 - accuracy: 0.9955 - val_loss: 0.8829 - val_accuracy: 0.8150

如果在LSTM层上没有使用展开层(并且设置return_sequences = False),则仅能产生约50%的验证准确度。

这篇文章的评论中建议在密集层之前使用return_sequences = False,而不是使用展开层。

但是为什么要这样做呢?如果使用展开层可以提高模型性能,是否可以使用它?展开层在这里到底起到了什么作用,并为什么会提高准确度?


我投票关闭此问题,因为它与[帮助中]定义的编程不相关,而是涉及ML理论和/或方法 - 请参见machine-learning 标签信息中的介绍和注意事项。 - desertnaut
抱歉,我已经移除了机器学习标签。 - treen
很抱歉,您可能误解了重点。请注意,一个问题是否适合在这里发布只与问题的内容有关,而不能仅通过标签操作来解决。如果问题是标签本身,我会自己将其删除而不采取任何进一步的行动。 - desertnaut
精度的变化很可能更多地来自于使用 return_sequences = True 而不是使用 Flattenreturn_sequences = True 会使 LSTM 的每一步输出一个值而不仅仅是最后一步。这意味着网络的最后部分有更多的输出值可供使用。Flatten 层只是改变了输出的维度形状。 - golmschenk
1个回答

7
一个LSTM层由不同的LSTM单元依次处理。如下图所示,第一个单元接受输入/嵌入并计算隐藏状态,下一个单元使用其输入和上一个时间步骤中的隐藏状态来计算自己的隐藏状态。基本上,单元之间的箭头也传递隐藏状态。如果您设置return_sequences=False,则lstm层仅输出最后一个隐藏状态! (在图中为h_4)。 因此,所有输入和单元的信息都嵌入在单个固定大小的信息中,它不能包含大量信息。 这就是为什么仅使用最后一个隐藏状态时准确性不高的原因。
当你设置return_sequences=True时,lstm层会输出每个隐藏状态,因此下一层可以访问所有隐藏状态,并且它们包含更多的信息。然而,LSTM层返回一个矩阵。您也可以在模型摘要中看到这一点。它返回一个大小为(None,500,128)的矩阵。None基本上是批处理中样本的数量,您可以忽略它。500是您的输入大小,128是您的隐藏状态大小。密集层无法处理矩阵,它必须是向量。这就是为什么您需要应用flatten,它的作用基本上只是打开2D矩阵并将其表示为1D向量。因此,您的Flatten层的大小为64000,因为500 * 128 = 64000。当然,随着隐藏状态越多,准确性越好,因为它们包含更多信息。 LSTM网络示例

1
非常感谢,这非常有帮助。我一直认为只有在有多个LSTM层时才会使用return_sequences=True,以将一个LSTM层的输出传递到下一个层。我曾经理解最后(或单个)LSTM层应该具有return_sequences=False。但听起来将所有隐藏状态输出传递给密集层也是可以的? - treen
1
很高兴我能帮到你!如果你觉得我的回答有用的话,能否给我点个赞并接受答案呢?你说得没错。这是最常见的用例,但并没有规定单层必须返回 return_seq false。这取决于你想要如何使用隐藏状态、如何组合它们等等。而且,使用所有隐藏状态输出是可以的,甚至推荐这样做,因为后续层可以访问更多信息。 - Berkay Berabi

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