在没有填充的情况下改变Keras中的序列长度

时间:2017-07-02 17:24:14

标签: sequence keras padding lstm recurrent-neural-network

我对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)

1 个答案:

答案 0 :(得分:7)

首先:您似乎不需要stateful=Truebatch_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;在每个步骤中,但每个步骤都没有一个矩阵。

图片示例:

enter image description here

每个方框&#34; A&#34;是使用和更新同一组矩阵(状态,权重,...)的步骤。

没有4个单元,但是同一个单元执行4次更新,每次输入更新一次。

每个X1,X2,...是长度维度中序列的一个切片。

enter image description here

较长的序列将比较短的序列重复和更新矩阵更多次。但它仍然是一个细胞。

enter image description here

细胞数确实会影响基质的大小,但不取决于序列长度。所有细胞都将并行工作,并在它们之间进行一些对话。

您的模型

在模型中,您可以像这样创建LSTM图层:

model.add(LSTM(anyNumber, return_sequences=True, input_shape=(None, 100)))
model.add(LSTM(anyOtherNumber))

通过在None中使用input_shape,您已经告诉您的模型它接受任意长度的序列。

你所要做的就是训练。你的培训代码还可以。 唯一不允许的是在里面创建一个不同长度的批次。因此,正如您所做的那样,为每个长度创建一个批次并训练每个批次。