我对Keras中LSTM的序列长度变化有疑问。我正在将批量为200的批次和可变长度序列(= x)与序列中的每个对象(=> [200,x,100])的100个特征传递到LSTM中:
LSTM(100, return_sequences=True, stateful=True, input_shape=(None, 100), batch_input_shape=(200, None, 100))
我在以下随机创建的矩阵上拟合模型:
x_train = np.random.random((1000, 50, 100))
x_train_2 = np.random.random((1000, 10,100))
据我理解LSTM(和Keras实现),x应该指LSTM单元的数量。对于每个LSTM单元,必须学习状态和三个矩阵(用于单元的输入,状态和输出)。如何在不填充最大值的情况下将不同的序列长度传递到LSTM中。指定长度,就像我一样?代码正在运行,但它实际上不应该(在我的理解中)。 甚至可以在之后传递另一个序列长度为60的x_train_3,但是不应该有额外的10个单元格的状态和矩阵。
顺便说一句,我使用的是Keras版本1.0.8和Tensorflow GPU 0.9。
这是我的示例代码:
from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np
from keras import backend as K
with K.get_session():
# create model
model = Sequential()
model.add(LSTM(100, return_sequences=True, stateful=True, input_shape=(None, 100),
batch_input_shape=(200, None, 100)))
model.add(LSTM(100))
model.add(Dense(2, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# Generate dummy training data
x_train = np.random.random((1000, 50, 100))
x_train_2 = np.random.random((1000, 10, 100))
y_train = np.random.random((1000, 2))
y_train_2 = np.random.random((1000, 2))
# Generate dummy validation data
x_val = np.random.random((200, 50, 100))
y_val = np.random.random((200, 2))
# fit and eval models
model.fit(x_train, y_train, batch_size=200, nb_epoch=1, shuffle=False, validation_data=(x_val, y_val), verbose=1)
model.fit(x_train_2, y_train_2, batch_size=200, nb_epoch=1, shuffle=False, validation_data=(x_val, y_val), verbose=1)
score = model.evaluate(x_val, y_val, batch_size=200, verbose=1)
答案 0 :(得分:7)
首先:您似乎不需要stateful=True
和batch_input
。这些用于当您想要在部分中划分非常长的序列时,并且在没有模型认为序列已经结束的情况下单独训练每个部分。
使用有状态层时,必须在确定某个批次是长序列的最后一部分时手动重置/擦除状态/内存。
您似乎正在使用整个序列。不需要有状态。
填充不是绝对必要的,但似乎你可以使用填充+掩码来忽略其他步骤。如果您不想使用填充,则可以将数据分成较小的批次,每批次具有不同的序列长度。请参阅:stackoverflow.com/questions/46144191
序列长度(时间步长)不会改变细胞/单位数或重量。可以使用不同的长度进行训练。无法更改的维度是要素数量。
输入尺寸:
输入维度为(NumberOfSequences, Length, Features)
输入形状和单元数之间绝对没有关系。它只包含步骤或递归的数量,即Length
维度。
<强>细胞:强>
LSTM层中的单元格表现得像&#34;单位&#34;在密集的层。
细胞不是一个步骤。一个单元格只是&#34; parallel&#34;操作。每组单元一起执行循环操作和步骤。
细胞之间有对话,正如@Yu-Yang在评论中所注意到的那样。但是他们是通过步骤继承的同一个实体的想法仍然有效。
您在this等图片中看到的那些小块不是单元格,而是步骤。
可变长度:
也就是说,序列的长度不会影响LSTM层中所有参数(矩阵)的数量。它只会影响步骤数。
对于长序列,将重新计算层内固定数量的矩阵,对于短序列,将重新计算更少次数。但在所有情况下,它都是一个矩阵获得更新并被传递到下一步。
序列长度仅改变更新次数。
图层定义:
单元格的数量可以是任意数量,它只会定义多少并行的迷你大脑将一起工作(这意味着一个或多或少强大的网络,以及或多或少的输出功能)。
LSTM(units=78)
#will work perfectly well, and will output 78 "features".
#although it will be less intelligent than one with 100 units, outputting 100 features.
有一个独特的权重矩阵和一个独特的状态/记忆矩阵,可以继续传递给下一步。这些矩阵只是简单地更新了#34;在每个步骤中,但每个步骤都没有一个矩阵。
每个方框&#34; A&#34;是使用和更新同一组矩阵(状态,权重,...)的步骤。
没有4个单元,但是同一个单元执行4次更新,每次输入更新一次。
每个X1,X2,...是长度维度中序列的一个切片。
较长的序列将比较短的序列重复和更新矩阵更多次。但它仍然是一个细胞。
细胞数确实会影响基质的大小,但不取决于序列长度。所有细胞都将并行工作,并在它们之间进行一些对话。
在模型中,您可以像这样创建LSTM图层:
model.add(LSTM(anyNumber, return_sequences=True, input_shape=(None, 100)))
model.add(LSTM(anyOtherNumber))
通过在None
中使用input_shape
,您已经告诉您的模型它接受任意长度的序列。
你所要做的就是训练。你的培训代码还可以。 唯一不允许的是在里面创建一个不同长度的批次。因此,正如您所做的那样,为每个长度创建一个批次并训练每个批次。