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

V1n*_*3nt 8 padding sequence lstm keras 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))
Run Code Online (Sandbox Code Playgroud)

我将模型拟合到以下随机创建的矩阵中:

x_train = np.random.random((1000, 50, 100))
x_train_2 = np.random.random((1000, 10,100))
Run Code Online (Sandbox Code Playgroud)

据我所知,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)
Run Code Online (Sandbox Code Playgroud)

Dan*_*ler 10

第一:似乎你不需要stateful=Truebatch_input.这些用于当您想要在部分中划分非常长的序列时,并且在没有模型认为序列已经结束的情况下单独训练每个部分.

使用有状态层时,必须在确定某个批处理是长序列的最后一部分时手动重置/擦除状态/内存.

你好像在处理整个序列.不需要有状态.

填充不是严格必要的,但似乎您可以使用填充+屏蔽来忽略其他步骤.如果您不想使用填充,则可以将数据分成较小的批次,每批次具有不同的序列长度.请参阅:stackoverflow.com/questions/46144191

序列长度(时间步长)不会改变细胞/单位数或重量.可以使用不同的长度进行训练.无法更改的维度是要素数量.


输入尺寸:

输入维度是(NumberOfSequences, Length, Features).
输入形状和单元数之间绝对没有关系.它只携带数或递归,这是Length维度.

细胞:

LSTM层中的单元在密集层中表现得像"单元".

细胞不是一个步骤.单元格只是"并行"操作的数量.每组单元一起执行循环操作和步骤.

正如@ Yu-Yang在评论中注意到的那样,细胞之间有对话.但是他们是通过步骤继承的同一个实体的想法仍然有效.

你在图片看到这些小模块,如不是细胞,它们的步骤.

可变长度:

也就是说,序列的长度不会影响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.    
Run Code Online (Sandbox Code Playgroud)

有一个独特的权重矩阵和一个独特的状态/记忆矩阵,可以继续传递到下一步.这些矩阵在每个步骤中都只是"更新",但每个步骤都没有一个矩阵.

图片示例:

在此输入图像描述

每个框"A"是使用和更新相同组矩阵(状态,权重,......)的步骤.

没有4个单元,但是一个和相同的单元执行4次更新,每次输入更新一次.

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


在此输入图像描述

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


在此输入图像描述

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


你的模特

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

model.add(LSTM(anyNumber, return_sequences=True, input_shape=(None, 100)))
model.add(LSTM(anyOtherNumber))
Run Code Online (Sandbox Code Playgroud)

通过使用Noneinput_shape这样,你已经告诉你的模型,它接受任何长度的序列.

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