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

Ada*_*nes 2 lstm keras

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

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

示例模型

这是我提出的,编译的.但是,看看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'])
Run Code Online (Sandbox Code Playgroud)

Dan*_*ler 5

由于您的问题有点困惑,我将采取以下假设.

  • 您有一个5000个时间步的时间序列,每个步骤都有一个功能.形状(1, 5000, 1)
  • 你的问题答案的主要部分:你想运行一个"滑动窗口"的情况,窗口的大小等于3000,窗口的步幅是1000.
  • 您希望窗口大小分为3个内部时间序列,这3个系列中的每一个都有1000个步骤,每个步骤只有一个功能.这些系列中的每一个都与独立系列(相当于具有3个LSTM副本) - 形状进入相同的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执行类似的操作

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)
Run Code Online (Sandbox Code Playgroud)

创建模型:

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

  • 该模型仅考虑一个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)
Run Code Online (Sandbox Code Playgroud)

此时,您已经消除了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)
Run Code Online (Sandbox Code Playgroud)

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

out = Lambda(lambda x: x[:,1,:])(out) #model.add(Lambda(lambda x: x[:,1,:]))
Run Code Online (Sandbox Code Playgroud)

完成模型:

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

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

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