【问题标题】:Keras fit_generator() - How does batch for time series work?Keras fit_generator() - 时间序列的批处理如何工作?
【发布时间】:2019-10-07 08:05:21
【问题描述】:

上下文:

我目前正在使用带有 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 个 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:输入数组的样本数应与目标数组相同。找到 1 个输入样本和 2 个目标样本。

当我创建一个看起来像这样的批处理时,就会发生这个错误:

#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/cmets,这被 Keras 解释为两个时间步长和五个特征。关于我的第一个问题(我仍然看到一个序列作为我的序列的目标,如在这个编辑示例中),我寻求信息如何/如果我能实现这一点以及这样一个批次的外观(就像我试图在问题)。

【问题讨论】:

  • 您能否澄清一下“每批单个目标”的含义?您的模型可以有一个或多个输出,并且这些层中的每一个都可以有不同的输出形状。所以我不明白你在这里所说的“单一目标”是什么意思。请详细说明。
  • 我更新了我的问题 - 你现在更清楚了吗?
  • 不幸的是,没有。我认为您正在混合样本、时间步长、特征和目标。让我描述一下我是如何理解它的:在您提供的第一个示例中,似乎每个输入样本都包含 2 个 timesteps,例如[10, 15][20, 25],其中每个时间步由两个特征组成,例如10 和 15 或 20 和 25。此外,相应的目标由一个时间步长组成,例如[30, 35],它也有两个特点。换句话说,批次中的每个输入样本必须有一个对应的目标。但是每个输入样本的形状和它的目标可能不一样。
  • 这显然是一个多变量时间序列:每个时间步长有多个(在本例中为两个)特征。这就是为什么作者使用hstack 通过并排堆叠两个单变量时间序列来构造该时间序列的原因。它只是在给定前两个时间步长的情况下预测下一个时间步长。
  • 从该教程中引用:“每个样本将是一个由 [1, 2, 2] 组成的 1 个样本、2 个时间步长和 2 个特征或平行序列的三维数组。输出将是 1 个样本和 2 个特征的二维序列 [1, 2]。”这证实了我的假设和解释。

标签: python tensorflow keras generator recurrent-neural-network


【解决方案1】:

简短回答:

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

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

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

第一个是多变量时间序列(即每个时间步有多个特征),第二个是单变量时间序列(即每个时间步有一个特征)。所以它们是不等价的。阅读长答案以获得进一步说明。

长答案:

我将给出我在 cmets 部分中提到的答案,并尝试使用示例进行详细说明:

我认为您正在混合样本、时间步长、特征和目标。让我描述一下我是如何理解它的:在您提供的第一个示例中,似乎每个输入样本都包含 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 层。


更新:问题是你在阅读时没有足够的注意力,无论是我的cmets和answer以及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)

瞧!我们做到了!这是输入数组;现在检查目标数组,它必须有两个长度为 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)

对不起,我无法比这更好地解释它!但无论如何,当您在我的 cmets 和我的答案中看到某些东西(即输入/目标数组的形状)一遍又一遍地重复时,假设它一定很重要并且应该检查。

【讨论】:

  • 感谢您的努力 - 在 cmets 中,我可以关注您,[[10 15]] 是一个时间步长和两个特征,这回答了我的第二个问题。不幸的是,我们对我的第一个问题仍然存在误解,我试图用我的第二个例子来澄清。您说的是单个时间步长和特征,我说的是处理一批中的多个序列样本和目标。我需要一个可视化的问题,比如这样一个批次的外观以及它是如何处理的,而不是架构信息。我对这个问题进行了第三次更新。
猜你喜欢
  • 2019-09-17
  • 2018-03-30
  • 2016-12-20
  • 2019-01-05
  • 2019-10-26
  • 1970-01-01
  • 2017-09-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多