在Keras中实现因果卷积神经网络以进行多变量时间序列预测。

6
这个问题是我之前的问题的后续,链接在这里:多特征因果卷积神经网络 - Keras实现,然而,有许多不清楚的事情,我认为这值得一个新的问题。这里的模型是根据上述帖子中的被接受答案构建的。
我正在尝试对10个序列、每个序列包含5个特征的多变量时间序列数据应用因果卷积神经网络模型。
lookback, features = 10, 5
  • 过滤器和内核应该设为什么?

    • 过滤器和内核对网络有什么影响?
    • 它们只是任意的数字吗,比如ANN层中的神经元数量?
    • 还是它们会影响网络解释时间步的方式?
  • 扩张率应该设为什么?

    • 这只是任意的数字吗,还是表示模型的回溯?
filters = 32
kernel = 5
dilations = 5
dilation_rates = [2 ** i for i in range(dilations)]

model = Sequential()
model.add(InputLayer(input_shape=(lookback, features)))
model.add(Reshape(target_shape=(features, lookback, 1), input_shape=(lookback, features)))


根据前面提到的答案,输入需要根据以下逻辑进行重新整形:
  • 经过 Reshape 后,5个输入特征现在被视为TimeDistributed层的时间层
  • 当Conv1D应用于每个输入特征时,它认为该层的形状为(10, 1)

  • 使用默认的"channels_last",因此...

  • 10个时间步是时间维度
  • 1是“通道”,也是特征映射的新位置
# Add causal layers
for dilation_rate in dilation_rates:
    model.add(TimeDistributed(Conv1D(filters=filters,
                              kernel_size=kernel,
                              padding='causal',
                              dilation_rate=dilation_rate,
                              activation='elu')))

根据上述答案,模型需要根据以下逻辑进行重新整形:
  • 将特征映射叠加在一起,以便每个时间步可以查看先前产生的所有特征 - (10个时间步,5个特征*32个滤波器)
接下来,因果层现在独立地应用于5个输入特征。
  • 为什么最初它们是独立应用的?
  • 为什么现在它们是依赖应用的?
model.add(Reshape(target_shape=(lookback, features * filters)))

next_dilations = 3
dilation_rates = [2 ** i for i in range(next_dilations)]
for dilation_rate in dilation_rates:
    model.add(Conv1D(filters=filters,
                     kernel_size=kernel,
                     padding='causal',
                     dilation_rate=dilation_rate,
                     activation='elu'))
    model.add(MaxPool1D())

model.add(Flatten())
model.add(Dense(units=1, activation='linear'))

model.summary()

摘要

  • 滤波器和卷积核应设置为多少?
    • 它们会影响网络如何解释时间步骤吗?
  • 将扩张设置为表示10个回顾的值是多少?

  • 为什么因果层最初是独立应用的?

  • 为什么在改变形状后它们被依赖地应用?
    • 为什么不从一开始就依赖地应用它们?

===========================================================================

完整代码

lookback, features = 10, 5

filters = 32
kernel = 5
dilations = 5
dilation_rates = [2 ** i for i in range(dilations)]

model = Sequential()
model.add(InputLayer(input_shape=(lookback, features)))
model.add(Reshape(target_shape=(features, lookback, 1), input_shape=(lookback, features)))

# Add causal layers
for dilation_rate in dilation_rates:
    model.add(TimeDistributed(Conv1D(filters=filters,
                              kernel_size=kernel,
                              padding='causal',
                              dilation_rate=dilation_rate,
                              activation='elu')))


model.add(Reshape(target_shape=(lookback, features * filters)))

next_dilations = 3
dilation_rates = [2 ** i for i in range(next_dilations)]
for dilation_rate in dilation_rates:
    model.add(Conv1D(filters=filters,
                     kernel_size=kernel,
                     padding='causal',
                     dilation_rate=dilation_rate,
                     activation='elu'))
    model.add(MaxPool1D())

model.add(Flatten())
model.add(Dense(units=1, activation='linear'))

model.summary()

编辑:

感谢你的问题,Daniel。

问题:

如果你能够“确切地”解释你的数据结构是如何构造的,原始数据是什么以及如何将其转换为输入形状、是否有独立的序列、是否创建滑动窗口等。这个过程的更好理解可以被实现。

答案:

我希望我正确理解了你的问题。

每个特征都是一系列时间序列数据的序列数组。它们是相互独立的,也就是说,它们不是一张图片,但是它们有某种程度上的相关性。

这就是为什么我尝试使用Wavenet,因为它非常擅长预测单个时间序列数组,然而我的问题需要我使用多个特征。

1个回答

7

对给出答案的评论

问题:

  • 为什么因果层最初是独立应用的?
  • 为什么在重塑后它们被依赖地应用?
    • 为什么不从一开始就依赖地应用它们?

那个答案有点奇怪。我不是专家,但我认为没有必要用 TimeDistributed 层保留独立特征。但我也不能说它是否会产生更好的结果。起初我会说这只是多余的。但是它可能会带来额外的智能,因为它可能看到涉及两个特征之间的远程步骤的关系,而不仅仅是看“相同步骤”。(这应该进行测试)

然而,这种方法存在错误

旨在交换回顾和特征大小的重塑并未达到预期的效果。答案的作者显然想要 交换轴(保持特征和回顾的解释),这与 重塑 不同(混合所有内容,数据失去了意义)。

A correct approach would need actual axis swapping, like model.add(Permute((2,1))) instead of the reshapes.
So, I don't know these answers, but nothing seems to create that need. One sure thing is: you will certainly want the dependent part. A model will not get any near the intelligence of your original model if it doesn't consider relations between features. (Unless you're lucky to have your data completely independent)
Now, explaining the relation between LSTM and Conv1D
An LSTM can be directly compared to a Conv1D and the shapes used are exactly the same, and they mean virtually the same, as long as you're using channels_last.
That said, the shape (samples, input_length, features_or_channels) is the correct shape for both LSTM and Conv1D. In fact, features and channels are exactly the same thing in this case. What changes is how each layer works regarding the input length and calculations.
Concept of filters and kernels.
Kernel是卷积层内的整个张量,将与输入相乘以得到结果。一个kernel包括它的空间大小(kernel_size)和filters数量(输出特征)。还有自动输入过滤器。
没有kernel数量,但有kernel_size。kernel size是每个输出步骤将连接在一起的长度步骤数。(这篇tutorial对于理解2D卷积及kernel size非常好 - 只需想象1D图像即可-- 该教程并未显示“filters”的数量,就像是1-filter动画) filters的数量直接与features的数量相关,它们完全相同。
引用:

filters和kernel应该设置为什么?

因此,如果您的LSTM层使用units=256,表示它将输出256个特征,您应该使用filters=256,表示您的卷积将输出256个通道/特征。 这不是一条规则,你可能会发现使用更多或更少的滤波器可以带来更好的结果,因为各层毕竟有不同的功能。也没有必要让所有层具有相同数量的滤波器!在这里,你应该进行参数调整。测试以查看哪些数字最适合你的目标和数据。 现在,卷积核大小是一种无法与LSTM进行比较的新东西,它被添加到模型中。
数字3是一种非常常见的选择。它意味着卷积将花费三个时间步骤来产生一个时间步骤。然后向右移动一步,以取另一组三步来产生下一步,依此类推。 扩张 扩张意味着卷积滤波器之间的步长有多少个空格。
  • 卷积 dilation_rate = 1 需要 kernel_size 个连续步骤来产生一个步骤。
  • 例如,扩张率为dilation_rate = 2 的卷积需要步骤0、2和4来产生一个步骤。然后需要步骤1、3、5来产生下一个步骤,以此类推。

如何设置膨胀来表示10个时间步的回顾?

range = 1 + (kernel_size - 1) * dilation_rate

因此,对于内核大小=3:

  • 膨胀=0(膨胀率=1):内核大小将在3步范围内变化
  • 膨胀=1(膨胀率=2):内核大小将在5步范围内变化
  • 膨胀=2(膨胀率=4):内核大小将在9步范围内变化
  • 膨胀=3(膨胀率=8):内核大小将在17步范围内变化

我的问题是

如果您能“确切地”解释您如何构造数据,原始数据是什么以及如何将其转换为输入形状,是否有独立序列,是否正在创建滑动窗口等。可以更好地理解这个过程。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接