Keras fit_generator() - 时间序列的批处理如何工作?

Keras fit_generator() - How does batch for time series work?

上下文:

我目前正在使用 Keras 和 Tensorflow 后端进行时间序列预测,因此学习了提供的教程 here

按照本教程,我来到了描述 fit_generator() 方法的生成器的地步。 此生成器生成的输出如下(左样本,右目标):

[[[10. 15.]
  [20. 25.]]] => [[30. 35.]]     -> Batch no. 1: 2 Samples | 1 Target
  ---------------------------------------------
[[[20. 25.]
  [30. 35.]]] => [[40. 45.]]     -> Batch no. 2: 2 Samples | 1 Target
  ---------------------------------------------
[[[30. 35.]
  [40. 45.]]] => [[50. 55.]]     -> Batch no. 3: 2 Samples | 1 Target
  ---------------------------------------------
[[[40. 45.]
  [50. 55.]]] => [[60. 65.]]     -> Batch no. 4: 2 Samples | 1 Target
  ---------------------------------------------
[[[50. 55.]
  [60. 65.]]] => [[70. 75.]]     -> Batch no. 5: 2 Samples | 1 Target
  ---------------------------------------------
[[[60. 65.]
  [70. 75.]]] => [[80. 85.]]     -> Batch no. 6: 2 Samples | 1 Target
  ---------------------------------------------
[[[70. 75.]
  [80. 85.]]] => [[90. 95.]]     -> Batch no. 7: 2 Samples | 1 Target
  ---------------------------------------------
[[[80. 85.]
  [90. 95.]]] => [[100. 105.]]   -> Batch no. 8: 2 Samples | 1 Target

在教程中使用了 TimeSeriesGenerator,但对于我的问题,使用自定义生成器或此 class 是次要的。 关于数据,我们有 8 steps_per_epoch 和一个形状样本 (8, 1, 2, 2)。 生成器被馈送到由 LSTM 实现的递归神经网络。

我的问题

fit_generator() 每批只允许一个目标,由 TimeSeriesGenerator 输出。 当我第一次阅读 fit() 的批处理选项时,我认为我可以有多个样本和相应数量的目标(它们是按批处理的,即逐行处理)。但是 fit_generator() 不允许这样做,因此显然是错误的。 这看起来像这样的例子:

[[[10. 15. 20. 25.]]] => [[30. 35.]]     
[[[20. 25. 30. 35.]]] => [[40. 45.]]    
    |-> Batch no. 1: 2 Samples | 2 Targets
  ---------------------------------------------
[[[30. 35. 40. 45.]]] => [[50. 55.]]    
[[[40. 45. 50. 55.]]] => [[60. 65.]]    
    |-> Batch no. 2: 2 Samples | 2 Targets
  ---------------------------------------------
...

其次,我认为,例如,[10, 15] 和 [20, 25] 被连续用作目标 [30, 35] 的 RNN 的输入,这意味着这类似于输入 [ 10、15、20、25]。由于使用第二种方法(我测试过),RNN 的输出不同,所以这也一定是错误的结论。

因此,我的问题是:

  1. 为什么每批只允许一个目标(我知道有一些 解决方法,但必须有一个原因)?
  2. 我怎么理解 计算一批?意思是,像 [[[40, 45], [50, 55]]] => [[60, 65]] 这样的输入是如何处理的,为什么它不类似于 [[[40, 45, 50, 55]]] => [[60, 65]]



根据今天的回答编辑
由于对我对样本和目标的定义存在一些误解 - 我遵循我理解的 Keras 在说时试图告诉我的内容:

ValueError: Input arrays should have the same number of samples as target arrays. Found 1 input samples and 2 target samples.

此错误发生在我创建批处理时,例如:

#This is just a single batch - Multiple batches would be fed to fit_generator()
(array([[[0, 1, 2, 3, 4],
        [5, 6, 7, 8, 9]]]), 
                           array([[ 5,  6,  7,  8,  9],
                           [10, 11, 12, 13, 14]]))

这应该是包含两个长度为 5 的时间序列(5 个连续数据点/时间步长)的单个批次,其目标也是两个相应的序列。 [ 5, 6, 7, 8, 9][0, 1, 2, 3, 4]的目标,[10, 11, 12, 13, 14][5, 6, 7, 8, 9]对应的目标。
这里的样本形状为 shape(number_of_batches, number_of_elements_per_batch, sequence_size),目标形状为 shape(number_of_elements_per_batch, sequence_size).
Keras 看到 2 个目标样本(在 ValueError 中),因为我有两个提供 3D 样本作为输入和 2D 目标作为输出(也许我只是不知道如何提供 3D 目标..)。

无论如何,根据@todays answer/comments,这被 Keras 解释为两个时间步长和五个特征。关于我的第一个问题(我仍然看到一个序列作为我的序列的目标,就像在这个编辑示例中一样),我寻求信息 how/if 我可以实现这个以及这样的批次看起来如何(就像我试图在问题中形象化)。

简答:

Why is only one target per batch allowed (I know there are some workarounds, but there has to be a reason)?

完全不是这样。对一批中的目标样本数量没有限制。唯一的要求是您应该在每批中具有相同数量的输入样本和目标样本。阅读长答案以进一步说明。

How may I understand the calculation of one batch? Meaning, how is some input like [[[40, 45], [50, 55]]] => [[60, 65]] processed and why is it not analog to [[[40, 45, 50, 55]]] => [[60, 65]]?

第一个是 multi-variate 时间序列(即每个时间步长有多个特征),第二个是 uni-variate 时间序列(即每个时间步长有一个特征)。所以他们不等价。阅读长答案以进一步说明。

长答案:

我会给出我在评论部分提到的答案,并尝试用例子详细说明:

我认为您在混合样本、时间步长、特征和目标。让我描述一下我是如何理解它的:在你提供的第一个例子中,似乎每个输入样本都包含 2 个时间步长,例如[10, 15][20, 25],其中每个时间步包含两个特征,例如10 和 15 或 20 和 25。此外,相应的目标由一个时间步组成,例如[30, 35],这也有两个特点。换句话说,批处理中的每个输入样本 必须 具有相应的目标。但是,每个输入样本的形状与其对应的目标不一定相同。

例如,考虑一个输入和输出都是时间序列的模型。如果我们将 每个输入样本 的形状表示为 (input_num_timesteps, input_num_features) 并将 每个目标(即输出)数组 的形状表示为 (output_num_timesteps, output_num_features),我们会有以下情况:

1)输入和输出时间步数相同(即input_num_timesteps == output_num_timesteps)。举个例子,以下模型可以实现这一点:

from keras import layers
from keras import models

inp = layers.Input(shape=(input_num_timesteps, input_num_features))

# a stack of RNN layers on top of each other (this is optional)
x = layers.LSTM(..., return_sequences=True)(inp)
# ...
x = layers.LSTM(..., return_sequences=True)(x)

# a final RNN layer that has `output_num_features` unit
out = layers.LSTM(output_num_features, return_sequneces=True)(x)

model = models.Model(inp, out)

2) 输入和输出时间步数不同(即input_num_timesteps ~= output_num_timesteps)。这通常是通过首先使用一个或多个 LSTM 层的堆栈将输入时间序列编码为一个向量,然后将该向量重复 output_num_timesteps 次以获得所需长度的时间序列来实现的。对于重复操作,我们可以很容易地使用 Keras 中的 RepeatVector 层。同样,作为示例,以下模型可以实现此目的:

from keras import layers
from keras import models

inp = layers.Input(shape=(input_num_timesteps, input_num_features))

# a stack of RNN layers on top of each other (this is optional)
x = layers.LSTM(..., return_sequences=True)(inp)
# ...
x = layers.LSTM(...)(x)  # The last layer ONLY returns the last output of RNN (i.e. return_sequences=False)

# repeat `x` as needed (i.e. as the number of timesteps in output timseries)
x = layers.RepeatVector(output_num_timesteps)(x)

# a stack of RNN layers on top of each other (this is optional)
x = layers.LSTM(..., return_sequences=True)(x)
# ...
out = layers.LSTM(output_num_features, return_sequneces=True)(x)

model = models.Model(inp, out)

作为一种特殊情况,如果输出时间步数为 1(例如,网络试图在给定最后一个 t 时间步的情况下预测下一个时间步),我们可能不需要使用重复,而是我们可以只使用 Dense 层(在这种情况下,模型的输出形状将是 (None, output_num_features),而不是 (None, 1, output_num_features)):

inp = layers.Input(shape=(input_num_timesteps, input_num_features))

# a stack of RNN layers on top of each other (this is optional)
x = layers.LSTM(..., return_sequences=True)(inp)
# ...
x = layers.LSTM(...)(x)  # The last layer ONLY returns the last output of RNN (i.e. return_sequences=False)

out = layers.Dense(output_num_features, activation=...)(x)

model = models.Model(inp, out)

请注意,上面提供的架构仅供说明,您可能需要调整或调整它们,例如根据您的用例和您要解决的问题,添加更多层,例如 Dense 层。


更新: 问题是你看的时候不够用心,无论是我的评论和回答,还是Keras报错。该错误明确指出:

... Found 1 input samples and 2 target samples.

所以,仔细阅读后,如果我是你,我会对自己说:"OK, Keras thinks that the input batch has 1 input sample, but I think I am providing two samples!! Since I am a very good person(!), I think it's very likely that I would be wrong than Keras, so let's find out what I am doing wrong!"。一个简单快速的检查是只检查输入数组的形状:

>>> np.array([[[0, 1, 2, 3, 4],
               [5, 6, 7, 8, 9]]]).shape
(1,2,5)

"Oh, it says (1,2,5)! So that means one sample which has two timesteps and each timestep has five features!!! So I was wrong into thinking that this array consists of two samples of length 5 where each timestep is of length 1!! So what should I do now???" 嗯,可以修了,step-by-step:

# step 1: I want a numpy array
s1 = np.array([])

# step 2: I want it to have two samples
s2 = np.array([
               [],
               []
              ])

# step 3: I want each sample to have 5 timesteps of length 1 in them
s3 = np.array([
               [
                [0], [1], [2], [3], [4]
               ],
               [
                [5], [6], [7], [8], [9]
               ]
              ])

>>> s3.shape
(2, 5, 1)

瞧!我们做到了!这是输入数组;现在检查目标数组,它必须有两个长度为 5 的目标样本,每个样本具有一个特征,即形状为 (2, 5, 1):

>>> np.array([[ 5,  6,  7,  8,  9],
              [10, 11, 12, 13, 14]]).shape
(2,5)

差不多!最后一个维度(即 1)缺失(注意: 根据模型的架构,您可能需要也可能不需要最后一个轴)。所以我们可以使用上面的 step-by-step 方法来找到我们的错误,或者我们可以稍微聪明一点,只在末尾添加一个轴:

>>> t = np.array([[ 5,  6,  7,  8,  9],
                  [10, 11, 12, 13, 14]])
>>> t = np.expand_dims(t, axis=-1)
>>> t.shape
(2, 5, 1)

抱歉,我没有比这更好的解释了!但无论如何,当你看到某些东西(即 input/target 数组的形状)在我的评论和我的回答中一遍又一遍地重复时,假设它一定是重要的东西并且应该被检查。