上下文:
我目前正在使用带有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的输出有所不同,所以这也必须是错误的结论。
因此,我的问题是:
[[[40,
45], [50, 55]]] => [[60, 65]]
之类的某些输入是如何处理的,为什么不类似于
[[[40, 45, 50, 55]]] => [[60, 65]]
答案 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)
对不起,我无法解释得更好!但是无论如何,当您在我的注释和答案中一遍又一遍地看到某些东西(即输入/目标数组的形状)反复出现时,请假设它必须是重要的并且应该进行检查。