我在《Python深度学习》的第7章第1节中发现了一段代码如下:
from keras.models import Modelfrom keras import layersfrom keras import Inputtext_vocabulary_size = 10000question_vocabulary_size = 10000answer_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 64embedded_text = layers.Embedding(64, text_vocabulary_size)(text_input)# Which we encoded in a single vector via a LSTMencoded_text = layers.LSTM(32)(embedded_text)# Same process (with different layer instances) for the questionquestion_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 textconcatenated = layers.concatenate([encoded_text, encoded_question], axis=-1)# And we add a softmax classifier on topanswer = 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'])
如您所见,这个模型的输入没有原始数据的形状信息,然后在Embedding层之后,LSTM的输入或Embedding的输出是一些变长序列。
所以我想知道:
- 在这个模型中,Keras如何确定LSTM层中的lstm_unit数量
- 如何处理变长序列
附加信息:为了解释lstm_unit是什么(我不知道该如何称呼它,所以就展示图片):
回答:
提供的循环层继承自基础实现keras.layers.Recurrent
,它包括选项return_sequences
,默认值为False
。这意味着默认情况下,循环层将消耗变长输入,并最终仅在最后一个序列步骤输出层的输出。
因此,使用None
来指定变长输入序列维度是没有问题的。
但是,如果您希望层返回完整的输出序列,即输入序列每个步骤的输出张量,那么您将需要进一步处理该输出的变长大小。
您可以通过让下一层进一步接受变长输入来做到这一点,并推迟到网络后期解决这个问题,最终您必须从某个变长事物中计算损失函数,或者在继续到后续层之前计算某个固定长度的表示,这取决于您的模型。
或者,您可以通过要求固定长度的序列来做到这一点,可能需要在序列末尾填充特殊的哨兵值,这些值仅用于填充长度,指示一个空序列项。
另外,Embedding
层是一个非常特殊的层,它也被设计为处理变长输入。输出形状将为输入序列的每个标记提供不同的嵌入向量,因此形状将是(批次大小,序列长度,嵌入维度)。由于下一层是LSTM,这没有问题…它也会愉快地消耗变长序列。
但正如在Embedding
的文档中提到的:
input_length: 当输入序列长度恒定时,输入序列的长度。 如果您打算连接 `Flatten`然后是`Dense`层,则需要此参数 (没有它,无法计算密集输出的形状)。
如果您想直接从Embedding
转换到非变长表示,那么您必须在层中提供固定的序列长度。
最后,请注意,当您表达LSTM层的维度时,例如LSTM(32)
,您是在描述该层的输出空间的维度。
# 输入序列的示例,例如批次大小为1。[ [34], [27], ...] --> # 输入到嵌入层[ [34标记的64-d表示 ...], [27标记的64-d表示 ...], ...] --> # 输入到LSTM层[32-d的LSTM最终序列步骤的输出向量]
为了避免批次大小为1的低效性,一种策略是按每个示例的序列长度对输入训练数据进行排序,然后根据常见的序列长度分组成批次,例如使用自定义的Keras DataGenerator。
这样做的优点是允许使用较大的批次大小,特别是如果您的模型可能需要批量归一化或涉及GPU密集型训练,甚至只是为了批量更新的梯度估计更不嘈杂的好处。但它仍然允许您处理具有不同示例不同批次长度的输入训练数据集。
更重要的是,它还具有一个很大的优势,即您不必管理任何填充以确保输入中的常见序列长度。