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

时间:2019-05-21 00:20:56

标签: python tensorflow keras generator

上下文:

我目前正在使用带有Tensorflow后端的Keras进行时间序列预测,因此,研究了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,但是对于我来说,如果使用自定义生成器或此类,它是次要的。 关于数据,我们有8个step_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]]

1 个答案:

答案 0 :(得分:1)

简短答案:

  

为什么每批只允许一个目标(我知道有一些解决方法,但是必须有原因)?

完全不是这样。批次中目标样品的数量没有限制。唯一的要求是每批中应有相同数量的输入和目标样品。阅读详细答案,以进一步澄清。

  

我如何理解一批的计算?意思是,如何处理诸如[[[40, 45], [50, 55]]] => [[60, 65]]之类的某些输入?为什么它不类似于[[[40, 45, 50, 55]]] => [[60, 65]]

第一个是多元时间序列(即每个时间步具有多个特征),第二个是单变量时间序列(即每个时间步具有一个特征)。因此它们不是等效的。阅读详细答案,以进一步澄清。

长答案:

我将给出我在评论部分提到的答案,并尝试使用示例进行详细阐述:

我认为您正在混合样本,时间步,功能和目标。让我描述一下我的理解方式:在您提供的第一个示例中,似乎每个输入样本都包含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提出的错误时没有足够的注意力。该错误明确指出:

  

...找到1个输入样本和2个目标样本。

因此,仔细阅读这篇文章后,如果我是您,我会对自己说:“好吧,Keras认为该输入批次有1个输入样本,但我想我提供了两个样本!!人(!),我认为我很可能比Keras错了,所以让我们找出我在做错什么!”。一个简单而快速的检查就是只检查输入数组的形状:

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

“哦,它说(1,2,5)!所以这意味着一个样本具有两个时间步长,每个时间步长具有五个功能!!!考虑到此数组由长度为5的两个样本组成,每个时间步长为1!所以现在我该怎么办???”好吧,您可以逐步解决它:

# 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)

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

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

差不多!缺少最后一个维度(即1)(注意:取决于模型的体系结构,您可能需要也可能不需要最后一个轴)。因此,我们可以使用上面的逐步方法来发现我们的错误,或者,我们可以更聪明一些,只需在末端添加一条轴即可。

>>> 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)

对不起,我无法解释得更好!但是无论如何,当您在我的注释和答案中一遍又一遍地看到某些东西(即输入/目标数组的形状)反复出现时,请假设它必须是重要的并且应该进行检查。