LSTM 如何处理变长序列

Ros*_*Liu 8 python machine-learning deep-learning lstm keras

我在用 Python进行深度深度学习的第 7 章第 1 节中找到了一段代码,如下所示?

from keras.models import Model
from keras import layers
from keras import Input

text_vocabulary_size = 10000
question_vocabulary_size = 10000
answer_vocabulary_size = 500

# Our text input is a variable-length sequence of integers.
# Note that we can optionally name our inputs!
text_input = Input(shape=(None,), dtype='int32', name='text')

# Which we embed into a sequence of vectors of size 64
embedded_text = layers.Embedding(64, text_vocabulary_size)(text_input)

# Which we encoded in a single vector via a LSTM
encoded_text = layers.LSTM(32)(embedded_text)

# Same process (with different layer instances) for the question
question_input = Input(shape=(None,), dtype='int32', name='question')
embedded_question = layers.Embedding(32, question_vocabulary_size)(question_input)
encoded_question = layers.LSTM(16)(embedded_question)

# We then concatenate the encoded question and encoded text
concatenated = layers.concatenate([encoded_text, encoded_question], axis=-1)

# And we add a softmax classifier on top
answer = layers.Dense(answer_vocabulary_size, activation='softmax')(concatenated)

# At model instantiation, we specify the two inputs and the output:
model = Model([text_input, question_input], answer)
model.compile(optimizer='rmsprop',
              loss='categorical_crossentropy',
              metrics=['acc'])
Run Code Online (Sandbox Code Playgroud)

正如你看到这个模型的输入没有原始数据的形状信息,那么在Embedding层之后,LSTM的输入或Embedding的输出是一些可变长度的序列。

模型摘要

所以我想知道:

  • 在这个模型中,keras 如何确定 LSTM 层中 lstm_unit 的数量
  • 如何处理变长序列

附加信息:为了解释 lstm_unit 是什么(我不知道如何称呼它,所以只显示它的图像):

lstm_unit

ely*_*ely 10

提供的循环层继承自基本实现keras.layers.Recurrent,其中包括return_sequences默认为False. 这意味着默认情况下,循环层将消耗可变长度的输入,并最终在最后的顺序步骤中仅产生层的输出。

因此,使用None指定可变长度的输入序列维度没有问题。

但是,如果您希望该层返回完整的输出序列,即输入序列每一步的输出张量,那么您必须进一步处理该输出的可变大小。

你可以通过让下一层进一步接受可变大小的输入来实现这一点,然后在你的网络中解决这个问题,最终你要么必须从一些可变长度的东西中计算一个损失函数,要么计算一些固定的——在继续到后面的层之前,长度表示,具体取决于您的模型。

或者您可以通过要求固定长度的序列来实现,可能用特殊的标记值填充序列的末尾,这些标记值仅指示一个空序列项,纯粹用于填充长度。

另外,该Embedding层是一个非常特殊的层,用于处理可变长度的输入。对于输入序列的每个标记,输出形状将具有不同的嵌入向量,因此形状为(批量大小、序列长度、嵌入维度)。由于下一层是 LSTM,所以这没问题……它也会很高兴地使用可变长度序列。

但正如文档中提到的Embedding

input_length: Length of input sequences, when it is constant.
      This argument is required if you are going to connect
      `Flatten` then `Dense` layers upstream
      (without it, the shape of the dense outputs cannot be computed).
Run Code Online (Sandbox Code Playgroud)

如果要直接从Embedding非可变长度表示转至非可变长度表示,则必须提供固定序列长度作为层的一部分。

最后,请注意,当您表示 LSTM 层的维数时,例如LSTM(32),您是在描述该层的输出空间的维数。

# example sequence of input, e.g. batch size is 1.
[
 [34], 
 [27], 
 ...
] 
--> # feed into embedding layer

[
  [64-d representation of token 34 ...],
  [64-d representation of token 27 ...],
  ...
] 
--> # feed into LSTM layer

[32-d output vector of the final sequence step of LSTM]
Run Code Online (Sandbox Code Playgroud)

为了避免批量大小为 1 的低效率,一种策略是按每个示例的序列长度对输入的训练数据进行排序,然后根据常见的序列长度将其分组,例如使用自定义 Keras DataGenerator。

这具有允许大批量大小的优势,特别是如果您的模型可能需要批量标准化或涉及 GPU 密集型训练,甚至只是为了减少批量更新梯度的噪声估计。但它仍然可以让您处理输入训练数据集,该数据集针对不同的示例具有不同的批次长度。

但更重要的是,它还有一个很大的优势,即您不必管理任何填充来确保输入中的公共序列长度。