对如何实现时间分布式LSTM + LSTM感到困惑

时间:2017-10-21 03:16:59

标签: keras lstm

经过大量的阅读和图解,我想我已经提出了一个模型,我可以用它作为更多测试我需要调整哪些参数和功能的基础。但是,我对如何实现以下测试用例感到困惑(所有数字都比最终模型小,但我想从小开始):

  • 输入数据:5000x1时间序列向量,分为5个1000x1的历元
  • 对于每个时间步,3个epochs的数据将通过3个双向LSTM层的时间分布副本,并且每个将输出10x1的向量(提取10个特征),然后将其作为第二个双向LSTM层的输入。
  • 对于每个时间步,忽略第一个和最后一个标签,但中心标签是所需的。

example model

这是我提出的,编译的。但是,看看model.summary,我想我错过了我希望第一个LSTM在每个输出时间步长的3个输入序列上运行的事实。我做错了什么?

model = Sequential()
model.add(TimeDistributed(Bidirectional(LSTM(11, return_sequences=True, recurrent_dropout=0.1, unit_forget_bias=True), input_shape=(3, 3, epoch_len), merge_mode='sum'), input_shape=(n_epochs, 3, epoch_len)))
model.add(TimeDistributed(Dense(7)))
model.add(TimeDistributed(Flatten()))
model.add(Bidirectional(LSTM(12, return_sequences=True, recurrent_dropout=0.1, unit_forget_bias=True), merge_mode='sum'))
model.add(TimeDistributed(Dense(n_classes, activation='softmax')))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

1 个答案:

答案 0 :(得分:5)

由于你的问题有点困惑,我会采取以下假设。

  • 您有一个5000个时间步的时间序列,每个步骤都有一个功能。形状(1, 5000, 1)
  • 问题答案的主要部分:您希望运行“滑动窗口”案例,窗口大小等于3000,窗口的步幅为1000。
  • 您希望窗口大小分为3个内部时间序列,这3个系列中的每一个都有1000个步骤,每个步骤只有一个功能。这些系列中的每一个都输入与独立系列相同的LSTM(相当于具有3个LSTM副本) - 形状(slidingWindowSteps, 3, 1000, 1)
  • 重要事项:从这3个系列中,您需要3个无长度输出和10个功能。形状(1,3,10)。 (你的图像是1x10,但你的文字说10x1,我假设图像是正确的)。
  • 您希望将这3个输出合并为3个步骤的单个序列,形状(1,3,10)
  • 您希望处理此3步序列的LSTM也返回3步序列

准备滑动窗口案例

在滑动窗口的情况下,重复数据是不可避免的。您需要先输入您的输入。

采用初始时间序列(1,5000,1),我们需要在包含3组1000的样本的批处理中将其拆分。这里我只为X做这个,你必须对Y做类似的事情/ p>

numberOfOriginalSequences = 1
totalSteps = 5000
features = 1

#example of original input with 5000 steps
originalSeries = np.array(
                        range(numberOfOriginalSequences*totalSteps*features)
                 ).reshape((numberOfOriginalSequences,
                            totalSteps,
                            features))  

windowSize = 3000
windowStride = 1000

totalWindowSteps = ((totalSteps - windowSize)//windowStride) + 1

#at first, let's keep these dimensions for better understanding 
processedSequences = np.empty((numberOfOriginalSequences,
                               totalWindowSteps,
                               windowSize,
                               features))

for seq in range(numberOfOriginalSequences):
    for winStep in range(totalWindowSteps):
        start = winStep * windowStride
        end = start + windowSize
        processedSequences[seq,winStep,:,:] = originalSeries[seq,start:end,:]    

#now we reshape the array to transform each window step in independent sequences:
totalSamples = numberOfOriginalSequences*totalWindowSteps
groupsInWindow = windowSize // windowStride
processedSequences = processedSequences.reshape((totalSamples,
                                                 groupsInWindow,
                                                 windowStride,
                                                 features))

print(originalSeries)
print(processedSequences)

创建模型:

关于您首次添加的图层的一些评论:

  • 该模型仅考虑一个input_shape。这个形状是(groupsInWindow,windowStride,features)。它应该在最外部的包装器中:TimeDistributed。
  • 您不想保留1000个时间步,您只需要10个结果要素:return_sequences = False。 (如果你想要更多图层,你可以在第一阶段使用许多LSTM。在这种情况下,第一阶段可以保留步骤,只有最后一部分需要使用return_sequences=False
  • 您需要10个功能,因此units=10

我将使用功能API来查看摘要中的输入形状,这有助于理解事物。

from keras.models import Model

intermediateFeatures = 10

inputTensor = Input((groupsInWindow,windowStride,features))

out = TimeDistributed(
    Bidirectional(
        LSTM(intermediateFeatures, 
             return_sequences=False, 
             recurrent_dropout=0.1, 
             unit_forget_bias=True), 
        merge_mode='sum'))(inputTensor)

此时,您已经消除了1000个时间步骤。由于我们使用return_sequences=False,因此不需要展平或类似的东西。数据已经以(samples, groupsInWindow,intermediateFeatures)的形式进行了整形。 Dense图层也不是必需的。但只要最终形状相同,如果你想按照你的方式去做就不会“错”。

arbitraryLSTMUnits = 12
n_classes = 17

out = Bidirectional(
    LSTM(arbitraryLSTMUnits, 
         return_sequences=True, 
         recurrent_dropout=0.1, 
         unit_forget_bias=True), 
    merge_mode='sum')(out)

out = TimeDistributed(Dense(n_classes, activation='softmax'))(out)

如果您要丢弃边框,可以添加此图层:

out = Lambda(lambda x: x[:,1,:])(out) #model.add(Lambda(lambda x: x[:,1,:]))

完成模型:

model = Model(inputTensor,out)
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
model.summary()

以下是尺寸如何流经此模型。 我放在这里的第一个维度(totalSamples)在None中显示为model.summary()

  • 输入:(totalSamples,groupsInWindow,windowStride,features)
  • 时间分布式LSTM的工作原理如下:
    • TimeDistributed允许第四维,即groupsInWindow。 这个维度将被保留。
    • return_sequences=False的LSTM将消除windowStride并更改功能(windowStride,第二个最后一个维度位于此LSTM的时间步长位置):
    • 结果:(totalSamples, groupsInWindow, intermadiateFeatures)
  • 没有时间分配的其他LSTM将不具有第四维度。这样,groupsInWindow(倒数第二个)将成为“时间步长”。但return_sequences=True不会像第一个LSTM那样消除时间步长。结果:(totalSamples, groupsInWindow, arbitraryLSTMUnits)
  • 最后的Dense图层,因为它正在接收3D输入,会将第二个维度解释为时间分布并保持不变,仅将自身应用于要素维度。结果:(totalSamples, groupsInWindow, n_classes)