【问题标题】:Confused about how to implement time-distributed LSTM + LSTM对如何实现时间分布的 LSTM + LSTM 感到困惑
【发布时间】:2018-04-02 06:02:19
【问题描述】:

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

  • 输入数据:5000x1 时间序列向量,分成 5 个 1000x1 的 epoch
  • 对于每个时间步,3 个 epoch 的数据将通过双向 LSTM 层的 3 个时间分布副本,每个副本将输出一个 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'])

【问题讨论】:

    标签: keras lstm


    【解决方案1】:

    由于您的问题有点混乱,我将采取以下假设。

    • 您有一个包含 5000 个时间步长的时间序列,每一步都有一个特征。造型(1, 5000, 1)
    • 回答你的问题的主要部分:你想运行一个“滑动窗口”的情况,窗口的大小等于 3000,窗口的步幅是 1000。
    • 您希望将窗口大小划分为 3 个内部时间序列,这 3 个序列中的每一个都有 1000 个步骤,每个步骤只有一个特征。这些系列中的每一个都进入与独立系列相同的LSTM(相当于拥有3个LSTM副本)-Shape(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)
    

    创建模型:

    关于你的第一个添加层的一些信息:

    • 模型只考虑了一个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)在model.summary() 中显示为None

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

    【讨论】:

    • 感谢您的详细回复,我今天就开始尝试。在我发布这篇文章几个小时后,我收到了重复数据。不过,感谢您纠正我的问题中的一些错别字和误解。
    • 很抱歉,花了比计划更长的时间才回到这里。我以前没有接触过功能 API 模型,但现在我意识到这就是我所需要的。我可以编译你的代码,甚至测试 fit 函数是否可以与model.fit(processedSequences, labels) 一起使用。但是,这仅在标签是 (3, 3, n_classes) 的数组时才有效。没有意义的是那些 3s 之一来自哪里。如果“外层”(第二个 LSTM,具有密集输出)运行 3 步,那么我只期望 (3, n_classes)。你能解释一下我的误解吗?
    • 哎呀。我忘了添加 Lambda 层(之后我可以使用 (3, n_classes) 的数组。但问题仍然存在,第三维是怎么来的,计数 3 是从哪里来的?“外层”只能运行 3 次,而不是 3x3 次。
    • 在我的答案末尾查看尺寸的行为方式。
    • 明白了。我喜欢您将尺寸描述为“流动”通过模型的方式,因为起初某些尺寸的目的已经改变并不明显。然而,当我把它画在纸上时,我可以看到发生了什么。我很高兴地报告,通过一些我没有在我的问题中提出的更改,测试模型可以编译和训练。但是,它开辟了新的追逐问题。
    猜你喜欢
    • 2021-01-09
    • 2022-07-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多