时间序列数据必须被转换为具有输入和输出组件的样本结构,然后才能用于拟合监督学习模型。
如果您必须手动执行此转换,可能会很困难。Keras 深度学习库提供了 TimeseriesGenerator,可以自动将单变量和多变量时间序列数据转换为样本,为训练深度学习模型做好准备。
在本教程中,您将了解如何使用 Keras TimeseriesGenerator 为深度学习方法准备时间序列数据进行建模。
完成本教程后,您将了解:
- 如何定义 TimeseriesGenerator 生成器并使用它来拟合深度学习模型。
- 如何为单变量时间序列准备生成器并拟合 MLP 和 LSTM 模型。
- 如何为多变量时间序列准备生成器并拟合 LSTM 模型。
开始您的项目,阅读我的新书《时间序列预测深度学习》,其中包含分步教程和所有示例的Python源代码文件。
让我们开始吧。

如何在 Keras 中使用 TimeseriesGenerator 进行时间序列预测
图片来源:Chris Fithall,保留部分权利。
教程概述
本教程分为六个部分;它们是:
- 时间序列用于监督学习的问题
- 如何使用 TimeseriesGenerator
- 单变量时间序列示例
- 多变量时间序列示例
- 多变量输入和相关序列示例
- 多步预测示例
注意:本教程假设您使用的是 Keras v2.2.4 或更高版本。
时间序列用于监督学习的问题
在将时间序列数据用于训练监督学习模型(如深度学习模型)之前,需要进行准备。
例如,单变量时间序列表示为观察向量
1 |
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10] |
监督学习算法要求数据以样本集合的形式提供,其中每个样本都有一个输入组件 (X) 和一个输出组件 (y)。
1 2 3 4 5 |
X, y 示例输入,示例输出 示例输入,示例输出 示例输入,示例输出 ... |
模型将从提供的示例中学习如何将输入映射到输出。
1 |
y = f(X) |
时间序列必须转换为具有输入和输出组件的样本。这种转换既告知模型将学习什么,也告知您将来在进行预测时如何使用该模型(例如,预测需要什么(X),以及进行的预测是什么(y))。
对于感兴趣进行一步预测的单变量时间序列,将先前时间步长的观察值(即滞后观察值)用作输入,并将当前时间步长的观察值作为输出。
例如,上述 10 步单变量序列可以表示为监督学习问题,其中三个时间步长作为输入,一个时间步长作为输出,如下所示:
1 2 3 4 5 |
X, y [1, 2, 3], [4] [2, 3, 4], [5] [3, 4, 5], [6] ... |
您可以编写代码自己执行此转换;例如,请参阅帖子
或者,当您有兴趣使用 Keras 训练神经网络模型时,可以使用 TimeseriesGenerator 类。
时间序列深度学习需要帮助吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
如何使用 TimeseriesGenerator
Keras 提供了 TimeseriesGenerator,可用于自动将单变量或多变量时间序列数据集转换为监督学习问题。
使用 TimeseriesGenerator 分为两个部分:定义它以及使用它来训练模型。
定义 TimeseriesGenerator
您可以创建该类的实例,并指定时间序列问题的输入和输出方面,它将提供一个 Sequence 类的实例,然后可以使用该实例在序列的输入和输出之间进行迭代。
在大多数时间序列预测问题中,输入和输出序列将是相同的序列。
例如
1 2 3 4 5 6 7 8 |
# 加载数据 inputs = ... outputs = ... # 定义生成器 generator = TimeseriesGenerator(inputs, outputs, ...) # 迭代生成器 for i in range(len(generator)): ... |
严格来说,该类不是生成器,因为它不是 Python Generator,您不能对其使用 next() 函数。
除了指定时间序列问题的输入和输出方面之外,还有一些额外的参数应进行配置;例如:
- length:每个样本的输入部分中要使用的滞后观察值数量(例如,3)。
- batch_size:每次迭代要返回的样本数量(例如,32)。
您必须根据您设计的有问题框架定义 length 参数。即要用作输入的所需滞后观察值数量。
您还必须定义 batch size,也就是训练期间模型的 batch size。如果数据集中的样本数量少于 batch size,您可以将生成器和模型中的 batch size 设置为生成器中的样本总数,方法是计算其长度;例如:
1 |
print(len(generator)) |
还有其他参数,例如定义数据中的起始和结束偏移量、采样率、步幅等。您不太可能使用这些功能,但您可以在 完整 API 中找到更多详细信息。
默认情况下,样本不进行洗牌。这对于一些在批次中跨样本维护状态的循环神经网络(如 LSTM)很有用。
对于一些神经网络(如 CNN 和 MLP),在训练时洗牌样本会受益。通过将 ‘shuffle‘ 参数设置为 True 可以启用洗牌。这将起到对每个批次返回的样本进行洗牌的作用。
在撰写本文时,TimeseriesGenerator 仅限于一步输出。不支持多步时间序列预测。
使用 TimeseriesGenerator 训练模型
一旦定义了 TimeseriesGenerator 实例,就可以使用它来训练神经网络模型。
可以使用 TimeseriesGenerator 作为数据生成器来训练模型。这可以通过使用 fit_generator() 函数拟合定义的模型来实现。
此函数将生成器作为参数。它还接受一个 steps_per_epoch 参数,该参数定义每个 epoch 中要使用的样本数量。可以将其设置为 TimeseriesGenerator 实例的长度,以使用生成器中的所有样本。
例如
1 2 3 4 5 6 |
# 定义生成器 generator = TimeseriesGenerator(...) # 定义模型 model = ... # 拟合模型 model.fit_generator(generator, steps_per_epoch=len(generator), ...) |
同样,可以通过调用 evaluate_generator() 函数使用生成器来评估已拟合的模型,并使用 predict_generator() 函数使用已拟合的模型对新数据进行预测。
使用数据生成器拟合的模型不必使用生成器版本的评估和预测函数。只有当您希望数据生成器为模型准备数据时,才能使用它们。
单变量时间序列示例
我们可以通过一个关于小型人为单变量时间序列数据集的实际示例来具体说明 TimeseriesGenerator。
首先,让我们定义数据集。
1 2 |
# 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) |
我们将选择这样构建问题:使用最后两个滞后观察值来预测序列中的下一个值。例如:
1 2 |
X, y [1, 2] 3 |
目前,我们将 batch size 设置为 1,以便我们可以探索生成器中的数据。
1 2 3 |
# 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, series, length=n_input, batch_size=1) |
接下来,我们可以查看数据生成器为此时间序列准备了多少样本。
1 2 |
# 样本数量 print('Samples: %d' % len(generator)) |
最后,我们可以打印每个样本的输入和输出组件,以确认数据已按预期准备好。
1 2 3 |
for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 单变量一步问题 from numpy import array from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, series, length=n_input, batch_size=1) # 样本数量 print('Samples: %d' % len(generator)) # 打印每个样本 for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
运行此示例将首先打印生成器中的样本总数,即八个。
然后,我们可以看到每个输入数组的形状为 [1, 2],每个输出的形状为 [1,]。
观察结果符合我们的预期,有两个滞后观察值将用作输入,随后的值将用作输出。
1 2 3 4 5 6 7 8 9 10 |
Samples: 8 [[1. 2.]] => [3.] [[2. 3.]] => [4.] [[3. 4.]] => [5.] [[4. 5.]] => [6.] [[5. 6.]] => [7.] [[6. 7.]] => [8.] [[7. 8.]] => [9.] [[8. 9.]] => [10.] |
现在我们可以用这个数据拟合一个模型,学习将输入序列映射到输出序列。
我们将从一个简单的多层感知器(MLP)模型开始。
将生成器定义为使用每个批次的所有样本,鉴于样本数量很少。
1 2 3 |
# 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, series, length=n_input, batch_size=8) |
我们可以定义一个具有 50 个节点的隐藏层和一个进行预测的输出层的简单模型。
1 2 3 4 5 |
# 定义模型 model = Sequential() model.add(Dense(100, activation='relu', input_dim=n_input)) model.add(Dense(1)) model.compile(optimizer='adam', loss='mse') |
然后,我们可以使用 fit_generator() 函数,用生成器拟合模型。生成器中只有一小批数据,因此我们将 steps_per_epoch 设置为 1。模型将训练 200 个 epoch。
1 2 |
# 拟合模型 model.fit_generator(generator, steps_per_epoch=1, epochs=200, verbose=0) |
拟合完成后,我们将进行一个样本外的预测。
给定输入 [9, 10],我们将进行预测,并期望模型预测 [11] 或接近它的值。模型未经优化,这只是一个如何使用生成器的示例。
1 2 3 |
# 进行样本外的单步预测 x_input = array([9, 10]).reshape((1, n_input)) yhat = model.predict(x_input, verbose=0) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 使用 MLP 进行单变量单步问题 from numpy import array from keras.models import Sequential from keras.layers import Dense from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, series, length=n_input, batch_size=8) # 定义模型 model = Sequential() model.add(Dense(100, activation='relu', input_dim=n_input)) model.add(Dense(1)) model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit_generator(generator, steps_per_epoch=1, epochs=200, verbose=0) # 进行样本外的单步预测 x_input = array([9, 10]).reshape((1, n_input)) yhat = model.predict(x_input, verbose=0) print(yhat) |
注意:您的 结果可能因算法或评估程序的随机性、或数值精度的差异而有所不同。考虑运行该示例几次并比较平均结果。
运行该示例会准备生成器、拟合模型并进行样本外预测,正确预测出接近 11 的值。
1 |
[[11.510406]] |
我们也可以使用生成器来拟合循环神经网络,例如长短期记忆网络(LSTM)。
LSTM 期望数据输入具有 [samples, timesteps, features] 的形状,而到目前为止所述的生成器将滞后观察值作为特征提供,形状为 [samples, features]。
我们可以将单变量时间序列在准备生成器之前重塑为 [10, 1],代表 10 个时间步长和 1 个特征;例如:
1 2 3 |
# 重塑为 [10, 1] n_features = 1 series = series.reshape((len(series), n_features)) |
TimeseriesGenerator 然后会将序列拆分为具有 [batch, n_input, 1] 或 [8, 2, 1] 形状的样本,其中包含生成器中的所有八个样本以及用作时间步长的两个滞后观察值。
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
# 使用 LSTM 进行单变量单步问题 from numpy import array from keras.models import Sequential from keras.layers import Dense 从 keras.layers 导入 LSTM from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) # 重塑为 [10, 1] n_features = 1 series = series.reshape((len(series), n_features)) # 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, series, length=n_input, batch_size=8) # 定义模型 model = Sequential() model.add(LSTM(100, activation='relu', input_shape=(n_input, n_features))) model.add(Dense(1)) model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit_generator(generator, steps_per_epoch=1, epochs=500, verbose=0) # 进行样本外的单步预测 x_input = array([9, 10]).reshape((1, n_input, n_features)) yhat = model.predict(x_input, verbose=0) print(yhat) |
注意:您的 结果可能因算法或评估程序的随机性、或数值精度的差异而有所不同。考虑运行该示例几次并比较平均结果。
再次,运行示例将准备数据、拟合模型并预测序列中的下一个样本外值。
1 |
[[11.092189]] |
多变量时间序列示例
TimeseriesGenerator 也支持多变量时间序列问题。
这些问题是指您有多个并行序列,每个序列在同一时间步长都有观察值。
我们可以通过一个示例来演示这一点。
首先,我们可以人为地创建两个并行序列的数据集。
1 2 3 |
# 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) |
将多变量时间序列格式化为每个时间序列是一个单独的列,行是每个时间步长的观察值,这是一种标准结构。
我们定义了序列为向量,但我们可以将它们转换为列。我们可以将每个序列重塑为一个形状为 [10, 1] 的数组,代表 10 个时间步长和 1 个特征。
1 2 3 |
# 重塑序列 in_seq1 = in_seq1.reshape((len(in_seq1), 1)) in_seq2 = in_seq2.reshape((len(in_seq2), 1)) |
现在,我们可以通过调用 hstack() NumPy 函数将列水平堆叠到一个数据集中。
1 2 |
# 水平堆叠列 dataset = hstack((in_seq1, in_seq2)) |
现在,我们可以直接将此数据集提供给 TimeseriesGenerator。我们将使用每个序列的先前两个观察值作为输入,并使用每个序列的下一个观察值作为输出。
1 2 3 |
# 定义生成器 n_input = 2 generator = TimeseriesGenerator(dataset, dataset, length=n_input, batch_size=1) |
每个样本将是一个三维数组 [1, 2, 2],代表 1 个样本、2 个时间步长和 2 个特征(或并行序列)。输出将是一个二维序列 [1, 2],代表 1 个样本和 2 个特征。第一个样本将是:
1 2 |
X, y [[10, 15], [20, 25]] [[30, 35]] |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# 多变量单步问题 from numpy import array from numpy import hstack from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) # 重塑序列 in_seq1 = in_seq1.reshape((len(in_seq1), 1)) in_seq2 = in_seq2.reshape((len(in_seq2), 1)) # 水平堆叠列 dataset = hstack((in_seq1, in_seq2)) print(dataset) # 定义生成器 n_input = 2 generator = TimeseriesGenerator(dataset, dataset, length=n_input, batch_size=1) # 样本数量 print('Samples: %d' % len(generator)) # 打印每个样本 for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
运行该示例将首先打印准备好的数据集,然后是数据集中样本的总数。
接下来,打印每个样本的输入和输出部分,确认了我们的预期结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[[ 10 15] [ 20 25] [ 30 35] [ 40 45] [ 50 55] [ 60 65] [ 70 75] [ 80 85] [ 90 95] [100 105]] Samples: 8 [[[10. 15.] [20. 25.]]] => [[30. 35.]] [[[20. 25.] [30. 35.]]] => [[40. 45.]] [[[30. 35.] [40. 45.]]] => [[50. 55.]] [[[40. 45.] [50. 55.]]] => [[60. 65.]] [[[50. 55.] [60. 65.]]] => [[70. 75.]] [[[60. 65.] [70. 75.]]] => [[80. 85.]] [[[70. 75.] [80. 85.]]] => [[90. 95.]] [[[80. 85.] [90. 95.]]] => [[100. 105.]] |
样本的三维结构意味着生成器不能直接用于 MLP 等简单模型。
这可以通过在将时间序列数据集提供给 TimeseriesGenerator 之前将其展平为一维向量,并将 length 设置为要用作输入的步数乘以序列中的列数(n_steps * n_features)来实现。
这种方法的一个限制是,生成器只允许您预测一个变量。对于多变量时间序列,您几乎肯定最好自己编写一个函数来准备数据,而不是使用 TimeseriesGenerator。
样本的三维结构可以直接用于 CNN 和 LSTM 模型。下面列出了使用 TimeseriesGenerator 进行多变量时间序列预测的完整示例。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# 使用 LSTM 进行多变量单步问题 from numpy import array from numpy import hstack from keras.models import Sequential from keras.layers import Dense 从 keras.layers 导入 LSTM from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) # 重塑序列 in_seq1 = in_seq1.reshape((len(in_seq1), 1)) in_seq2 = in_seq2.reshape((len(in_seq2), 1)) # 水平堆叠列 dataset = hstack((in_seq1, in_seq2)) # 定义生成器 n_features = dataset.shape[1] n_input = 2 generator = TimeseriesGenerator(dataset, dataset, length=n_input, batch_size=8) # 定义模型 model = Sequential() model.add(LSTM(100, activation='relu', input_shape=(n_input, n_features))) model.add(Dense(2)) model.compile(optimizer='adam', loss='mse') # 拟合模型 model.fit_generator(generator, steps_per_epoch=1, epochs=500, verbose=0) # 进行样本外的单步预测 x_input = array([[90, 95], [100, 105]]).reshape((1, n_input, n_features)) yhat = model.predict(x_input, verbose=0) print(yhat) |
注意:您的 结果可能因算法或评估程序的随机性、或数值精度的差异而有所不同。考虑运行该示例几次并比较平均结果。
运行示例将准备数据、拟合模型,并预测每个输入时间序列的下一个值,我们期望为 [110, 115]。
1 |
[[111.03207 116.58153]] |
多变量输入和相关序列示例
存在一些多变量时间序列问题,其中有一个或多个输入序列和一个需要预测的单独输出序列,该序列依赖于输入序列。
为了具体说明,我们可以人为地创建一个包含两个输入时间序列和一个输出序列的示例,该输出序列是输入序列的总和。
1 2 3 4 |
# 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) out_seq = array([25, 45, 65, 85, 105, 125, 145, 165, 185, 205]) |
其中输出序列中的值是输入时间序列中同一时间步长值的总和。
1 |
10 + 15 = 25 |
这与之前的示例不同,在这些示例中,给定输入,我们希望预测目标时间序列中的下一个时间步长值,而不是输入相同的当前时间步长。
例如,我们想要如下所示的样本:
1 2 3 4 5 |
X, y [10, 15], 25 [20, 25], 45 [30, 35], 65 ... |
我们不想要如下所示的样本:
1 2 3 4 5 |
X, y [10, 15], 45 [20, 25], 65 [30, 35], 85 ... |
尽管如此,TimeseriesGenerator 类假定我们要预测下一个时间步长,并将按上述第二种情况提供数据。
例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
# 多变量单步问题 from numpy import array from numpy import hstack from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) out_seq = array([25, 45, 65, 85, 105, 125, 145, 165, 185, 205]) # 重塑序列 in_seq1 = in_seq1.reshape((len(in_seq1), 1)) in_seq2 = in_seq2.reshape((len(in_seq2), 1)) out_seq = out_seq.reshape((len(out_seq), 1)) # 水平堆叠列 dataset = hstack((in_seq1, in_seq2)) # 定义生成器 n_input = 1 generator = TimeseriesGenerator(dataset, out_seq, length=n_input, batch_size=1) # 打印每个样本 for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
运行示例将打印样本的输入和输出部分,输出值是下一个时间步长的值,而不是我们对此类问题可能期望的当前时间步长的值。
1 2 3 4 5 6 7 8 9 |
[[[10. 15.]]] => [[45.]] [[[20. 25.]]] => [[65.]] [[[30. 35.]]] => [[85.]] [[[40. 45.]]] => [[105.]] [[[50. 55.]]] => [[125.]] [[[60. 65.]]] => [[145.]] [[[70. 75.]]] => [[165.]] [[[80. 85.]]] => [[185.]] [[[90. 95.]]] => [[205.]] |
因此,我们可以修改目标序列(out_seq)并在开头插入一个额外的值,以将所有观察值向下移动一个时间步长。
这种人工移位将允许我们偏好的问题构建。
1 2 |
# 将目标样本移位一个时间步长 out_seq = insert(out_seq, 0, 0) |
包含此移位的完整示例将在下面提供。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# 多变量单步问题 from numpy import array from numpy import hstack from numpy import insert from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100]) in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105]) out_seq = array([25, 45, 65, 85, 105, 125, 145, 165, 185, 205]) # 重塑序列 in_seq1 = in_seq1.reshape((len(in_seq1), 1)) in_seq2 = in_seq2.reshape((len(in_seq2), 1)) out_seq = out_seq.reshape((len(out_seq), 1)) # 水平堆叠列 dataset = hstack((in_seq1, in_seq2)) # 将目标样本移位一个时间步长 out_seq = insert(out_seq, 0, 0) # 定义生成器 n_input = 1 generator = TimeseriesGenerator(dataset, out_seq, length=n_input, batch_size=1) # 打印每个样本 for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
运行示例将显示问题偏好的构建方式。
这种方法将适用于输入样本的长度,无论其长度如何。
1 2 3 4 5 6 7 8 9 |
[[[10. 15.]]] => [25.] [[[20. 25.]]] => [45.] [[[30. 35.]]] => [65.] [[[40. 45.]]] => [85.] [[[50. 55.]]] => [105.] [[[60. 65.]]] => [125.] [[[70. 75.]]] => [145.] [[[80. 85.]]] => [165.] [[[90. 95.]]] => [185.] |
多步预测示例
与许多其他经典和机器学习模型相比,神经网络模型的一个优点是它们可以进行多步预测。
也就是说,模型可以学习将一个或多个特征的输入模式映射到多个特征的输出模式。这可以在时间序列预测中用于直接预测多个未来时间步。
这可以通过模型直接输出向量来实现,通过将所需的输出数量指定为输出层中的节点数,或者可以通过专门的序列预测模型(如编码器-解码器模型)来实现。
TimeseriesGenerator 的一个限制是它不直接支持多步输出。具体来说,它不会创建目标序列中可能需要的多个时间步。
尽管如此,如果您准备的目标序列有多个时间步,它将遵守并将其作为每个样本的输出部分。这意味着您有责任为每个时间步准备预期的输出。
我们可以用一个简单的单变量时间序列来演示这一点,该序列在输出序列中有两个时间步。
您可以看到目标序列中的行数必须与输入序列中的行数相同。在这种情况下,我们必须知道超出输入序列的值,或者将输入序列截断到目标序列的长度。
1 2 3 |
# 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) target = array([[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11]]) |
完整的示例如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 单变量多步问题 from numpy import array from keras.preprocessing.sequence import TimeseriesGenerator # 定义数据集 series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) target = array([[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11]]) # 定义生成器 n_input = 2 generator = TimeseriesGenerator(series, target, length=n_input, batch_size=1) # 打印每个样本 for i in range(len(generator)): x, y = generator[i] print('%s => %s' % (x, y)) |
运行示例会打印样本的输入和输出部分,显示两个滞后观测作为输入,以及多步预测问题中的两个时间步作为输出。
1 2 3 4 5 6 7 8 |
[[1. 2.]] => [[3. 4.]] [[2. 3.]] => [[4. 5.]] [[3. 4.]] => [[5. 6.]] [[4. 5.]] => [[6. 7.]] [[5. 6.]] => [[7. 8.]] [[6. 7.]] => [[8. 9.]] [[7. 8.]] => [[ 9. 10.]] [[8. 9.]] => [[10. 11.]] |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
- 如何在 Python 中将时间序列转换为监督学习问题
- TimeseriesGenerator Keras API
- Sequence Keras API
- Sequential Model Keras API
- Python Generator
总结
在本教程中,您了解了如何使用 Keras TimeseriesGenerator 为深度学习模型准备时间序列数据。
具体来说,你学到了:
- 如何定义 TimeseriesGenerator 生成器并使用它来拟合深度学习模型。
- 如何为单变量时间序列准备生成器并拟合 MLP 和 LSTM 模型。
- 如何为多变量时间序列准备生成器并拟合 LSTM 模型。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
嗨 Jason
很棒的教程。
当我运行您的代码时。单变量单步问题与 LSTM。
在运行 model.fit 时出现错误
回溯(最近一次调用)
文件“”,第2行,在
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\keras\legacy\interfaces.py”, line 91, in wrapper
return func(*args, **kwargs)
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\keras\engine\training.py”, line 1415, in fit_generator
initial_epoch=initial_epoch)
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\keras\engine\training_generator.py”, line 177, in fit_generator
generator_output = next(output_generator)
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\keras\utils\data_utils.py”, line 793, in get
six.reraise(value.__class__, value, value.__traceback__)
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\six.py”, line 693, in reraise
raise value
File “C:\Program Files (x86)\Microsoft Visual Studio\Shared\Python36_64\lib\site-packages\keras\utils\data_utils.py”, line 658, in _data_generator_task
generator_output = next(self._generator)
TypeError: ‘TimeseriesGenerator’ object is not an iterator
有什么办法可以解决吗?
您能确认您的 Keras 库是最新的吗?
例如,v2.2.4 或更高版本?
嗨 Jason
谢谢您的快速回复。
不,我运行的是 v2.2.2,但现在已更新到 2.2.4,并且它有效了:)
谢谢你
很高兴听到这个。我在教程中添加了一个注释。
嗨,Jason,
谢谢您的教程,对我帮助很大。
但是我在处理我的数据集时仍然有一个大问题。我认为这是一个多站点多变量时间序列预测数据集(多辆汽车在一段时间内的轨迹数据)。我不知道在使用 TimeseriesGenerator 之前如何对其进行预处理。
您能给我一些建议吗?
非常感谢。
在预处理之前,也许可以从对问题的有力定义开始——它将指导您如何准备数据。
谢谢您的建议。但什么是框架?像模型一样?我不太明白。您能给一个简单的例子或链接吗?
先谢谢您了。
框架是问题类型(分类/回归)的选择以及输入和输出的选择。更多信息请参见此处
https://machinelearning.org.cn/how-to-define-your-machine-learning-problem/
我读了您博客上另一篇题为“标准多变量、多步、多站点时间序列预测问题”的文章。我对问题框架有了一些理解。
我的项目很像“空气质量预测”项目。您认为是否可以使用 LSTM 进行全局预测问题?
也许可以尝试一下。
很棒的教程 Jason。我想知道如何包含其他独立变量来预测输出。在我的例子中,我想预测一系列测量站点的空气污染。除了历史污染,我还有温度和湿度等其他变量。您知道如何处理吗?谢谢!
我展示了如何将其用于具有相关序列的多变量数据,这有帮助吗?
嘿,感谢您提供如此出色的教程。
我在多变量案例中遇到错误。当我插入 0 时,输入和输出序列的长度不再相同
ValueError: 数据和目标必须长度相同。数据长度为 10,目标长度为 11
嗯,也许发到 stackoverflow 或 Keras 帮助
https://machinelearning.org.cn/get-help-with-keras/
嗨,Jason 和 Evan。
numpy.insert() 会将新值添加到现有数组中。
因此,在您提供的示例中,“out_seq = insert(out_seq, 0, 0)”会使 out_seq 的大小增加 1。
我认为这就是导致 Evan 错误的原因。
您需要在创建生成器之前执行以下操作。
from numpy import delete
out_seq = delete(out_seq, -1)
感谢分享。
感谢您提供如此出色的教程,我复制了您的代码并在我的 pycharm 中运行它,发现结果与您不同,样本数量总是比您的少一个,当您的为 8 时,我的为 7。
# 单变量一步问题
from numpy import array
from keras.preprocessing.sequence import TimeseriesGenerator
# 定义数据集
series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
# 定义生成器
n_input = 2
generator = TimeseriesGenerator(series, series, length=n_input, batch_size=1)
# 样本数量
print(‘Samples: %d’ % len(generator))
# 打印每个样本
for i in range(len(generator))
x, y = generator[i]
print(‘%s => %s’ % (x, y))
#结果
Samples: 7
[[1. 2.]] => [3.]
[[2. 3.]] => [4.]
[[3. 4.]] => [5.]
[[4. 5.]] => [6.]
[[5. 6.]] => [7.]
[[6. 7.]] => [8.]
[[7. 8.]] => [9.]
您能否确认您的库是最新的?
是的,我检查了我的 keras 版本并更新到最新版本,现在结果与您相同。谢谢!!
很高兴听到这个消息。
你好 jason,
感谢您提供如此出色的教程!~
我现在有一个问题。
我想生成给定特定种子和结束的序列,就像句子以“hello”开头并以“bye”结尾一样
您有什么想法吗?
非常感谢。
是的,如果您的训练数据有这个,那么模型就会学习到它。
嗨 Jason 先生
正如 Evan 在上面提到的,我遇到了与 Evan 相同的错误,针对相同的示例
ValueError: 数据和目标必须长度相同。数据长度为 10,目标长度为 11
确认您的 Keras 版本为 2.2.4 或更高版本,tensorflow 为 1.12 或更高版本。
我在多变量输入和相关序列示例中收到相同的错误消息
当目标偏移时
# 将目标样本移位一个时间步长
out_seq = insert(out_seq, 0, 0)
目标长度为 11,数据长度为 10
# 确认 Keras 版本
import keras;
print(keras.__version__)
2.2.4
您使用的是哪个版本的 tensorflow?
如果您移动目标,您也应该移动数据
dataset = np.append(dataset, [[0] * np.size(dataset, axis=1)], axis=0)
out_seq = np.insert(out_seq, 0, 0)
“TimeseriesGenerator”与您在许多其他教程中使用的“series_to_supervised”函数有什么区别?
在很多方面。您具体对哪些差异感兴趣?
嗨 Jason,非常感谢您的博客,它非常有帮助,并且是一个很棒的资源!
Tamer 上面从未回复,但我实际上对同一个问题感兴趣。我理解用您的“series_to_supervised”函数重构的时间序列与 TimeSeriesGenerator 的拟合方式不同。我的问题是:它们在功能上是相同的吗?
从我所能看到的,“series_to_supervised”虽然方式不同,但起到了相同的作用。我的理解正确吗?
再次感谢
不客气。
我认为它们可以配置为做同样的事情。内部它们是不同的。
谢谢 Jason!
不客气。
假设单变量序列的多步(2 步)预测(使用 3 个滞后),如下所示
series = array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
target = array([[1,2],[2,3],[3,4],[4,5],[5,6],[6,7],[7,8],[8,9],[9,10],[10,11]])
# 定义生成器
n_input = 3
generator = TimeseriesGenerator(series, target, length=n_input, batch_size=1)
n_features=1
n_output=2
# 定义模型
model_lstm2 = Sequential()
model_lstm2.add(LSTM(10, activation=’relu’,
input_shape=(n_input, n_features)))
model_lstm2.add(Dense(n_output))
model_lstm2.compile(optimizer=’sgd’, loss=’mse’)
# 拟合模型
history_lstm2=model_lstm2.fit_generator(generator, steps_per_epoch=1, epochs=50, verbose=1)
plt.plot(history_lstm2.history[‘loss’])
我收到一个错误
“检查输入时出错:期望 lstm_26_input 具有 3 个维度,但得到形状为 (1, 3) 的数组”
我认为“generator”有问题,因为我认为 LSTM input_shape 是正确的,但如何为此类情况进行更改?
谢谢。
是的,LSTM 的输入必须是 3D 的,例如,一些样本,每个样本具有相同的时序和特征数。也许这会有帮助
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-samples-timesteps-and-features-for-lstm-input
只想说声谢谢,我为构建 x 和 y(多变量 x)而抓狂,直到我偶然发现这里……这篇文章帮助我保持(我有点)理智!
谢谢,坚持下去!
嗨 Jason,非常出色的教程!它确实回答了我过去一周困扰我的关于时间序列预测的许多问题。
只有一个问题请教!
您能否给出一个非常简单的实际用例,说明多变量输入和相关序列问题?我只是想在我脑海中更清楚地了解何时需要应用它。
谢谢。
是的,我有很多例子,也许可以从这里开始
https://machinelearning.org.cn/start-here/#deep_learning_time_series
嗨 Jason,再次感谢您发布本教程。
我正在做一个项目,对股票数据进行未来预测。我有 13 个特征和 2.5 年的数据来训练我的 LSTM。我尝试实现一个生成器来做一些未来预测(提前 5 天),但我收到了错误
ValueError: 检查输入时出错:期望 lstm_1_input 的形状为 (529, 13),但得到形状为 (5, 13) 的数组
这会是我的输入和输出形状造成的吗?现在我将它们设置为同一个数组
generator = TimeseriesGenerator(stock_dataset, stock_dataset, length = n_lag, batch_size = 8)
在这种情况下,使用我的数组“stock_dataset”作为输入(数据)和输出(目标)是否有意义,因为我正在寻找的数据输出的形状与输入数据相同。如果您能就此提供一些指导,并告诉我这是否是导致我的 ValueError 的原因。非常感谢!
这表明生成器提供的样本形状与模型的期望不匹配。
您可以更改生成器以匹配模型,也可以更改模型以匹配数据。
更多关于 LSTM 所需的 3D 形状的信息
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-samples-timesteps-and-features-for-lstm-input
嗨 Jason,再次感谢您提供的链接。我有点困惑,因为在您提供的链接中,您说 LSTM 的输入层期望一个 3D 数组作为输入,但您上面的示例中只从生成器传递了一个 2D 数组
model.add(LSTM(100, activation=’relu’, input_shape=(n_input, n_features)))
此外,在 Keras 中 TimeseriesGenerator 的文档中也提到输入形状应该是一个 2D 数组。
是的,我们指定了单个样本的形状,但总是提供许多样本,因此它总是 3D 的。抱歉造成混淆。
这意味着在模型准备期间,我们只指定样本的形状。
嗨 Jason,有什么方法可以将两个目标传递给 timeseriesgenerator 吗?我的意思是,我的模型有一个输入和两个目标,这是一个有两个输出的分类问题。谢谢。
可能有,据我所知没有,也许使用自定义函数
https://machinelearning.org.cn/convert-time-series-supervised-learning-problem-python/
嗨 Jason
我向您的代码添加了一个循环,并进行了少量修改。我想预测 t+1 天的多个时间步。在验证步骤中,预测值根据架构变为 +infinity 或零。我的完整代码在 gist.github 上。有什么建议吗?
”’
x1=495 # 训练期结束
valid=pred[x1:x1+n_input] # 验证初始 = 训练期结束
print (valid,n_input, n_features)
for n_phase in range(0,n_valid-5)
x_input = valid[n_phase+0: n_phase+n_input].reshape((1, n_input, n_features))
yhat = model.predict(x_input, verbose=0)
valid=np.append (valid, yhat)
valid=valid[n_input:len(pred)-1]
绘图
https://imgur.com/a/1RFeqEM
完整代码
https://gist.github.com/yusufmet/84a5c8f0c535132256bee08db43b3206
干得不错。
误解我了。为什么预测会变成无穷大或零?我该如何纠正 LSTM 架构?
也许您有梯度消失或爆炸?
也许可以尝试在建模之前缩放数据?
也许可以尝试使用 relu 激活?
也许可以尝试权重约束?
嗨,Jason,
您是否有关于在 Keras 中为时间序列预测/分类进行数据增强的帖子?这是否合乎逻辑?
不太有,抱歉。也许可以添加高斯噪声
https://machinelearning.org.cn/how-to-improve-deep-learning-model-robustness-by-adding-noise/
你好 jason,
我目前正在使用 timeseriesgenerator 进行销售预测项目。
一切似乎都很顺利,直到拟合部分。它返回
AttributeError: ‘TimeseriesGenerator’ object has no attribute ‘shape’
代码如下
n_input = 30
n_features = 1
generator = TimeseriesGenerator(X_train,y_train,length = n_input,batch_size=16)
model = keras.models.Sequential()
model.add(keras.layers.LSTM(100,activation = ‘relu’,return_sequences=True,input_shape (n_input,n_features)))
model.add(keras.layers.LSTM(50,activation = ‘relu’,return_sequences = True))
model.add(keras.layers.LSTM(25))
model.add(keras.layers.Dense(1))
当它到达拟合部分时,它显示此错误。
您能否告诉我可能的原因是什么?
看起来您在第一个隐藏层中缺少一个“=”。
抱歉 Jason,那是复制代码时的一个错误。
代码中存在“=”。
除此之外,您认为时间序列生成器在接受形状作为属性时有什么问题吗?
我遇到了同样的错误,如何解决?
尝试直接从教程中复制代码。
这会有帮助
https://machinelearning.org.cn/faq/single-faq/how-do-i-copy-code-from-a-tutorial
感谢 Jason 提供如此有用的教程!
我没有看到 Keras 函数可以归一化生成器的输出。尽管我宁愿使用生成器拆分测试/训练集——似乎必须先拆分,然后归一化,然后生成。是这样吗?
谢谢
是的。获取训练数据的 min/max 或 mean/stdev,然后将缩放应用于训练和测试。
趋势或季节性差分与生成器有什么关系?
据我所知没有。
你好,
我的数据是 x_train.shape (1100, 3000),y_train (1100,1)
当我使用生成器时,我得到批次大小为 (batch_size, 1, 3000),这很好,但我希望将其重塑为 (batch_size, 3000, 1)。
这是否可能,以及如何做到?
已经很久了,我不记得了。你可能需要试验一下生成器的参数。
也许可以从帖子中的示例开始,并将其改编为你想要实现的目标的原型。
完成多变量示例到 model.fit 的过程中会产生一个错误,我在其中行内注释了“检查目标时出错:期望 dense_14 的形状为 (2,),但得到形状为 (1,) 的数组”
# 使用 LSTM 进行多变量单步问题
from numpy import array
from numpy import hstack
from numpy import insert
来自 keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.preprocessing.sequence import TimeseriesGenerator
# 定义数据集
in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90, 100])
in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95, 105])
out_seq = array([25, 45, 65, 85, 105, 125, 145, 165, 185, 205])
# 重塑序列
in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
# 水平堆叠列
dataset = hstack((in_seq1, in_seq2))
”’
问题:
将目标样本移一位
out_seq = insert(out_seq, 0, 0)
忽略移位,我们只尝试拟合模型。
注意:错误在 “model.fit_generator…”
检查目标时出错:期望 dense_14 的形状为 (2,),但得到形状为 (1,) 的数组
”’
# 定义生成器
n_input = 1
generator = TimeseriesGenerator(dataset, out_seq, length=n_input, batch_size=1)
# 定义模型
model = Sequential()
model.add(LSTM(100, activation=’relu’, input_shape=(n_input, n_features)))
model.add(Dense(2))
model.compile(optimizer=’adam’, loss=’mse’)
# 拟合模型
model.fit_generator(generator, steps_per_epoch=1, epochs=5, verbose=1)
# 进行样本外的单步预测
x_input = array([[90, 95], [100, 105]]).reshape((1, n_input, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)
你好 Jason,我使用了窗口大小,通过移位函数转换为监督数据,所以
你能告诉我使用生成器和窗口移位函数的主要区别是什么吗?
我尝试了几篇文章但无法理解,你能帮助我理解吗?
我认为它们很可能在功能上是等效的,只是实现方式不同。
嗨,Jason,
感谢您的精彩教程。
我购买了您在这篇文章中宣传的书“深度学习在时间序列预测中的应用”,但找不到任何关于 TimeseriesGenerator 的参考。
TimeseriesGenerator 是否已经过时,还是您未能更新您的书?
期待阅读您的书:)
谢谢!
不,我只是不推荐使用它(例如,它对我来说不够灵活),因此它没有在教程或书中被使用。
你好 Jason,我遇到了这个错误
我的 keras 版本 = 2.3.0-tf
感谢您的博客!
—————————————————————————
ValueError 回溯 (最近一次调用)
in ()
15 # 定义模型
16 model = Sequential()
--> 17 model.add(LSTM(100, activation=’relu’, input_shape=(n_input, n_features)))
18 model.add(Dense(1))
19 model.compile(optimizer=’adam’, loss=’mse’)
~\AppData\Roaming\Python\Python36\site-packages\keras\engine\sequential.py in add(self, layer)
164 # 并创建连接当前层的节点
165 # 到我们刚刚创建的输入层。
--> 46 layer(x)
167 set_inputs = True
168 else
~\AppData\Roaming\Python\Python36\site-packages\keras\layers\recurrent.py in __call__(self, inputs, initial_state, constants, **kwargs)
539
540 if initial_state is None and constants is None
--> 51 return super(RNN, self).__call__(inputs, **kwargs)
542
543 # 如果指定了 any of
initial_state
或constants
并且它们是 Keras~\AppData\Roaming\Python\Python36\site-packages\keras\backend\tensorflow_backend.py in symbolic_fn_wrapper(*args, **kwargs)
73 if _SYMBOLIC_SCOPE.value
74 with get_graph().as_default()
--> 75 return func(*args, **kwargs)
76 else
77 return func(*args, **kwargs)
~\AppData\Roaming\Python\Python36\site-packages\keras\engine\base_layer.py in __call__(self, inputs, **kwargs)
461 ‘You can build it manually via: ‘
462 ‘
layer.build(batch_input_shape)
‘)--> 62 self.build(unpack_singleton(input_shapes))
463 self.built = True
465
~\AppData\Roaming\Python\Python36\site-packages\keras\layers\recurrent.py in build(self, input_shape)
500 self.cell.build([step_input_shape] + constants_shape)
501 else
--> 67 self.cell.build(step_input_shape)
503
504 # set or validate state_spec
~\AppData\Roaming\Python\Python36\site-packages\keras\layers\recurrent.py in build(self, input_shape)
1917 initializer=self.kernel_initializer,
1918 regularizer=self.kernel_regularizer,
-> 1919 constraint=self.kernel_constraint)
1920 self.recurrent_kernel = self.add_weight(
1921 shape=(self.units, self.units * 4),
~\AppData\Roaming\Python\Python36\site-packages\keras\engine\base_layer.py in add_weight(self, name, shape, dtype, initializer, regularizer, trainable, constraint)
277 if dtype is None
278 dtype = self.dtype
--> 279 weight = K.variable(initializer(shape, dtype=dtype),
280 dtype=dtype,
281 name=name,
~\AppData\Roaming\Python\Python36\site-packages\keras\initializers.py in __call__(self, shape, dtype)
225 limit = np.sqrt(3. * scale)
226 x = K.random_uniform(shape, -limit, limit,
--> 227 dtype=dtype, seed=self.seed)
228 if self.seed is not None
229 self.seed += 1
~\AppData\Roaming\Python\Python36\site-packages\keras\backend\tensorflow_backend.py in random_uniform(shape, minval, maxval, dtype, seed)
4355 with tf_ops.init_scope()
4356 return tf_keras_backend.random_uniform(
-> 4357 shape, minval=minval, maxval=maxval, dtype=dtype, seed=seed)
4358
4359
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\keras\backend.py in random_uniform(shape, minval, maxval, dtype, seed)
5684 seed = np.random.randint(10e6)
5685 return random_ops.random_uniform(
-> 5686 shape, minval=minval, maxval=maxval, dtype=dtype, seed=seed)
5687
5688
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\ops\random_ops.py in random_uniform(shape, minval, maxval, dtype, seed, name)
286 maxval_is_one = maxval is 1 # pylint: disable=literal-comparison
287 if not minval_is_zero or not maxval_is_one or dtype.is_integer
--> 287 minval = ops.convert_to_tensor(minval, dtype=dtype, name=”min”)
289 maxval = ops.convert_to_tensor(maxval, dtype=dtype, name=”max”)
290 seed1, seed2 = random_seed.get_seed(seed)
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\ops.py in convert_to_tensor(value, dtype, name, as_ref, preferred_dtype, dtype_hint, ctx, accepted_result_types)
1339
1340 if ret is None
-> 1341 ret = conversion_func(value, dtype=dtype, name=name, as_ref=as_ref)
1342
1343 if ret is NotImplemented
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\tensor_conversion_registry.py in _default_conversion_function(***failed resolving arguments***)
50 def _default_conversion_function(value, dtype, name, as_ref)
51 del as_ref # Unused.
--> 52 return constant_op.constant(value, dtype, name=name)
53
54
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\constant_op.py in constant(value, dtype, shape, name)
260 “””
261 return _constant_impl(value, dtype, shape, name, verify_shape=False,
-> 262 allow_broadcast=True)
263
264
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\constant_op.py in _constant_impl(value, dtype, shape, name, verify_shape, allow_broadcast)
268 ctx = context.context()
269 if ctx.executing_eagerly()
-> 270 t = convert_to_eager_tensor(value, ctx, dtype)
271 if shape is None
272 return t
~\AppData\Roaming\Python\Python36\site-packages\tensorflow\python\framework\constant_op.py in convert_to_eager_tensor(value, ctx, dtype)
94 dtype = dtypes.as_dtype(dtype).as_datatype_enum
95 ctx.ensure_initialized()
--> 96 return ops.EagerTensor(value, ctx.device_name, dtype)
97
98
ValueError: object __array__ method not producing an array
听到这个消息很抱歉,这可能会有帮助
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
感谢您的精彩教程,Jason。
我可以问一个问题吗?
我想预测一些地方的 AQI(空气质量指数)。这些地方之间存在关联。所以我对每个地方都使用了 TimeseriesGenerator。
然后我想将 generator1、generator2……连接起来训练一个模型。我该如何做到?
也许是连续在同一个模型上?
或者也许使用一些自定义代码来创建您自己的生成器,以加载所有数据集并在一次运行中进行训练。
感谢您的回复!但我不知道如何创建自己的生成器。
我发现了一种方法,使用 np.vstack 连接 generator1[0][0], generator1[1][0]…,然后使用 fit() 而不是 fit_generator() 来训练模型。
我正在测试它,希望它可用。
如果您不熟悉 Python 生成器,这将有所帮助
https://wiki.python.org/moin/Generators
我也无法使用此示例拟合生成器。问题在于数据集的维度
检查目标时出错:期望 dense_6 具有 3 个维度,但得到形状为 (1000, 1) 的数组
有人能详细解释一下这里的维度概念吗?很难理解生成器的维度,它当前是什么以及它应该是什么?
很抱歉听到您在使用示例时遇到麻烦,也许这些建议会有些帮助
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
非常感谢!
您的书(深度学习在时间序列预测中的应用)是否基于
TimeseriesGenerator 构建模型?
不,所有示例都使用自定义代码来进行预测模型的受控前向验证。
非常感谢!我只是想问一个关于使用 TimeseriesGenerator 进行“验证”的问题。通常,TimeseriesGenerator 的长度必须小于测试数据集的长度。
您是否碰巧知道这个?
如果不知道,对我来说完全没问题。我不想让您费心解释这个!
我不使用验证集进行时间序列预测,我看不到直接实现它的方法。
你好 Jason,感谢您的精彩教程。
我可以问个问题吗?
在上面的多步预测案例中,如果需要使用生成器处理包含多个特征(独立)行(当前和之前的一些行)但只有当前依赖输出的数据集,该怎么办?
其想法是,当前输出可以通过下图进行预测。
在这种情况下可以写什么?
[[[10. 15.] 25.] [[20. 25.]]] => [45.]
[[[20. 25.][45.]] [[30. 35.]]] => [65.]
[[[30. 35.][65.]] [[40. 45.]]] => [85.]
……..
不客气。
也许可以。
也许自己编写生成器会更容易——为你的数据定制?例如,请参阅此处的数据准备示例
https://machinelearning.org.cn/how-to-develop-lstm-models-for-time-series-forecasting/
非常感谢,我没有刷新页面看到您的回复。
不客气。
换句话说:对于下面的 31、32、33 是独立输出,模型无需预测。只有 36 是预测对象。
Generator[0] => (array([[[ 1, 2, 3, 6],
[11, 12, 13, 16],
[21, 22, 23, 26]]]), array([[31, 32, 33, 36]]))
嗨,Jason,
感谢您的教程。我正在尝试用我的数据集来实现这个,数据集的形状是 (1821, 137),其中 1821 是时间步长,137 是特征。我定义了生成器并打印了样本,但我一直得到“1”作为样本计数,而它显然应该更高。您知道是什么问题吗?
#1820 这样就可以有一个观测值是当前时间步
generator = TimeseriesGenerator(data, data, length=1820, batch_size=1)
print(‘Samples: %d’ % len(generator))
样本: 1
谢谢你,
抱歉,我不知道您出故障的原因。也许这些提示中的一些会有帮助
https://machinelearning.org.cn/faq/single-faq/can-you-read-review-or-debug-my-code
嗨,Jason,
我找到了问题所在。在 Keras TimeseriesGenerator 文档中 (https://keras.org.cn/api/preprocessing/timeseries/),他们将 length 定义为“输出序列的长度(以时间步为单位)”……所以在我上面的问题中,通过设置 length = 1820,我实际上将我的输出序列的长度定义为 1820,因此只剩下 1 个样本作为输入。
当我将 length 改为 1,然后打印样本数时,我得到了我想要的正确数字 1820。
你觉得呢?
也许用一些样本数据进行测试,看看它是否符合您的预期。
我只是好奇,它是否适用于 Landsat 和 MODIS 数据的 .tif 文件?
抱歉,我不知道“Landsat 和 MODIS 数据”是什么意思。
只想说谢谢您一直以来提供的高质量教程。我的谷歌搜索总是回到您的网站,您的解释和示例是一些最好的。我也发现我对您解释的有效性有信心,与许多其他我不得不质疑培训结果是否合法的网站相比。
谢谢克里斯!
嗨,Jason,
是否有办法通过 KerasRegressor 包装器在 RandomizedGridSearch 中使用时间序列生成器对象?我正在尝试优化我的 LSTM 模型。
我正在尝试这样做,但首先,它需要 X 和 y 作为单独的数组;当我解决这个问题时,我认为它在模型评估方面存在问题。
是否有任何示例可以提供帮助?
我不这么认为,我建议直接使用 Keras API 并手动运行您自己的随机/网格搜索。
我利用了这个机会并创建了以下 Keras 独立包:https://time-series-generator.readthedocs.io/
如果我们能够增强其功能,克服此处帖子中提到的 TimeseriesGenerator 的限制,那将是很棒的。在这方面,欢迎拉取请求!
干得好!
这里有一个针对此限制的候选解决方案:https://time-series-generator.readthedocs.io/en/latest/#advanced-usage
对于我的项目,我正在研究机器学习领域。我的 yolo 输出包含四个类别:1) not_empty 2) empty 3) hand 4) tool 以及检测到的对象的坐标。任务是构建一个用于过程分类的理论数据集。
例如,如果我们考虑 10 秒的时间序列,那么从第 1 秒到第 8 秒,Yolo 只检测到 hand 类及其坐标 X 和 Y(为简化起见,我使用 X 和 Y 而不是 Xmin,Xmax,Ymin,Ymax),并且在第 9 秒和第 10 秒,它还检测到 tool 类及其附近的 hand 坐标,基于此,我们需要将其分类为提取工具的新过程。
例如,我们需要手动定义 3 个进程,格式为 Excel 或 CSV,并将其作为输入仅在密集层中使用,然后对进程进行分类。我的输入是一个系列,有 8 个特征,10 个时间戳,这样我总共有 3 个系列。我的输出将是每个系列的 1 个类别。为此,我使用了时间序列生成器,但它没有帮助,因为输入长度和目标长度不同。我应该使用什么其他方法?
我不确定我是否理解,抱歉。也许这里的教程会给你一些想法
https://machinelearning.org.cn/start-here/#deep_learning_time_series
嗨,Jason,
我创建了一个 CNN-LSTM 网络来处理实时卫星图像和电力数据。
CNN 处理时间分布的时间序列卫星图像,将其展平,然后添加其他时间序列电力数据(连接)。
使用 n_input 时间步来预测 n_output 时间步
结构
# 定义模型 CNN
visible1 = Input(shape=(n_input, pixels, pixels, 3))
vgg_cnn = TimeDistributed(vggmodel)(visible1)
flat1 = TimeDistributed(Flatten())(vgg_cnn)
# 实际电力输入(4 个变量)
visible2 = Input(shape=(n_input,4))
# 合并两个模型
merge = concatenate([flat1, visible2])
# 编码器 – LSTM
LSTM1 = LSTM(400, activation=’relu’, return_sequences=True)(merge)
LSTM2 = LSTM(400, activation=’relu’, return_sequences=True)(LSTM1)
LSTM3 = LSTM(400, activation=’relu’, return_sequences=False)(LSTM2)
# 解码器 – LSTM
Repeater = RepeatVector(n_out)(LSTM3)
LSTM4 = LSTM(400, activation=’relu’, return_sequences=True)(Repeater)
LSTM5 = LSTM(400, activation=’relu’, return_sequences=True)(LSTM4)
LSTM6 = LSTM(400, activation=’relu’, return_sequences=True)(LSTM5)
hidden1 = TimeDistributed(Dense(400, activation=’relu’))(LSTM6)
hidden2 = TimeDistributed(Dense(100, activation=’relu’))(hidden1)
output = TimeDistributed(Dense(1))(hidden2)
# 组合模型
model = Model(inputs=[visible1, visible2], outputs=output)
# 编译方法
model.compile(loss=’mse’, optimizer=’adam’, metrics=[‘mse’,’mae’,
metrics.RootMeanSquaredError()])
现在我可以直接使用数据拟合模型,使用
model.fit([X_train_images_steps, X_train_power_steps] , y_train_steps, batch_size=96, …ect]
但是,由于显而易见的原因,对于大量的图像数据来说这是不可能的。
所以我需要使用一个生成器来实现这一点,但是标准的 TimeseriesGenerator 不支持多个输出 ([x1, x2], y)。
我创建了一个变通方法,但是这会将对象类型从 Sequence(TimeseriesGenerator 是什么)更改为通用生成器。
变通方法
def generate_generator_multiple(X_train, y_train, y_train_steps)
batch_size = 96
# 输入 1 – 图像生成器
data_gen1 = TimeseriesGenerator(X_train_image, y_train_steps_out, length=n_input, batch_size=batch_size)
# 输入 2 – 实际生成器
data_gen2 = TimeseriesGenerator(X_train_power, y_train_steps_out, length=n_input, batch_size=batch_size)
i = -1
while True
if i == -1
print(‘inititation’)
x1, y1 = data_gen1[0]
x2, y2 = data_gen2[0]
i+=1
elif i>=0
print(‘generation with i: ‘ + str(i))
x1, y1 = data_gen1[i]
x2, y2 = data_gen2[i]
i+=1
if i==len(data_gen2): i=0
else: i = i
print(‘next i: ‘ + str(i))
yield [x1, x2], y1
使用
model.fit(generate_generator_multiple(X_train, y_train, y_train_steps), steps_per_epoch=365, …ect)
没有错误,但训练错误乱七八糟(上下跳动而不是像直接输入方法那样持续下降),模型也无法学习做出好的预测。
您认为有什么好的变通方法吗?创建自己的 TimeSeriesGenerator 类版本?
问题很长,但希望您能提供一些想法。
从您的所有博客中我学到了很多,非常感谢!
诚挚的问候,
Gijs
我没有能力审查您的代码,抱歉。
也许您可以将您的问题总结为一两句话?
嗨,Jason,
我解决了这个问题。
问题是:如何操作 TimeSeriesGenerator 来输出类似 [x1, x2], y 的内容,以便在具有各种输入流的模型训练中使用?
我的变通方法不起作用,因为 keras fit() 需要一个 Sequence 而不是一个通用生成器。
解决方案是:为了您自己的目的,操作 keras.utils.Sequence.TimeseriesGenerator 功能。
如果有人遇到同样的问题,这是我的解决方案代码
[已删除]
很高兴听到您解决了问题!
也许您可以尝试在一些测试数据上使用 TimeSeriesGenerator——原型化几种方法,直到达到您想要的效果?
嗨,Jason,
我是否可以删除我自己的评论?或者您可以做到吗?
我在这里分享了我的部分代码,这些代码被 Turnitin 抓取了。我不喜欢这样。
此致,Gijs
我已经为您删除了评论中的代码。希望有所帮助。
嗨,Jason,
非常感谢!只删除代码部分即可。
然而,我的问题也适用于上面的评论(#599918)。
您能否也删除该评论中的代码部分?
最后,我想非常感谢您提供的这个网站以及您撰写的所有博客。它在我毕业项目期间给了我很大的帮助!
非常感谢,Gijs
你好 Jason,谢谢你的教程,我想预测 300 个数据点(我有 1200 个数据点)。我该如何使用单一变量预测 300 个数据点?
最简单的方法是一次预测一个步骤,然后将预测结果重新用于预测下一个时间步。但是,您应该预期在 300 步之后的预测准确性会大大下降。
嗨,Jason,
对于下面(摘自上述教程的示例),如果我使用 input_shape 而不是 “input_dim”,那么我应该使用的 “input_shape” 是什么?谢谢
我尝试了 input_shape= (n_input,),但我得到的 yhat 与 input_dim=n_input 不同
非常感谢!
# 使用 MLP 进行单变量单步问题
# 定义生成器
n_input = 2
generator = TimeseriesGenerator(series, series, length=n_input, batch_size=8)
# 定义模型
model = Sequential()
model.add(Dense(100, activation=’relu’, input_dim=n_input))
嗨,Jason,
对于下面的代码,如果我在“generator”中更改n_input和length,我会收到一个错误,并且它无法正常运行。我不知道n_input和n_features之间的关系,因为如果它们不同且相互独立,我仍然会收到错误。
我也不知道我是否从正确的轴连接了我的网络中的特征。
如果您能帮助我解决这个问题,我将不胜感激,因为我已经卡在这里很久了。
from locale import normalize
import tensorflow as tf
from sklearn.preprocessing import MinMaxScaler
from focal_loss import BinaryFocalLoss
from sklearn.model_selection import train_test_split
SIGNAL_WIDTH = 61862
import h5py
import numpy as np
import os
import scipy.io
from keras.layers import Input
def build_model(input_layer)
#input_shape = (16,None,640)
#input_layer = Input((None,100))
c1 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(input_layer)
c1 = tf.keras.layers.BatchNormalization()(c1)
c1 = tf.keras.layers.LeakyReLU(alpha=0.01)(c1)
c1 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(c1)
c1 = tf.keras.layers.BatchNormalization()(c1)
c1 = tf.keras.layers.LeakyReLU(alpha=0.01)(c1)
p1 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c1)
c2 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p1)
c2 = tf.keras.layers.BatchNormalization()(c2)
c2 = tf.keras.layers.LeakyReLU(alpha=0.01)(c2)
p2 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c2)
c3 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p2)
c3 = tf.keras.layers.BatchNormalization()(c3)
c3 = tf.keras.layers.LeakyReLU(alpha=0.01)(c3)
p3 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c3)
c4 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p3)
c4 = tf.keras.layers.BatchNormalization()(c4)
c4 = tf.keras.layers.LeakyReLU(alpha=0.01)(c4)
p4 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c4)
c5 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p4)
c5 = tf.keras.layers.BatchNormalization()(c5)
c5 = tf.keras.layers.LeakyReLU(alpha=0.01)(c5)
p5 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c5)
c6 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p5)
c6 = tf.keras.layers.BatchNormalization()(c6)
c6 = tf.keras.layers.LeakyReLU(alpha=0.01)(c6)
p6 = tf.keras.layers.MaxPool1D(pool_size=2, strides=2, padding=”same”)(c6)
c7 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(p6)
c7 = tf.keras.layers.BatchNormalization()(c7)
c7 = tf.keras.layers.LeakyReLU(alpha=0.01)(c7)
c7 = tf.keras.layers.Conv1D(filters=32,kernel_size=3,strides=1, padding=”same”)(c7)
c7 = tf.keras.layers.BatchNormalization()(c7)
c7 = tf.keras.layers.LeakyReLU(alpha=0.01)(c7)
# Up_sampling & Output part
u8 = tf.keras.layers.UpSampling1D(size=2)(c7)
u8 = tf.keras.layers.concatenate([u8,c2],axis=1)
c8 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u8)
#c8 = tf.keras.layers.BatchNormalization()(c8)
#c8 = tf.keras.layers.LeakyReLU(alpha=0.01)(c8)
u9 = tf.keras.layers.UpSampling1D(size=2)(c8)
u9 = tf.keras.layers.concatenate([u9,c5],axis=1)
c9 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u9)
#c9 = tf.keras.layers.BatchNormalization()(c9)
c9 = tf.keras.layers.LeakyReLU(alpha=0.01)(c9)
u10 = tf.keras.layers.UpSampling1D(size=2)(c9)
u10 = tf.keras.layers.concatenate([u10,c4],axis=1)
c10 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u10)
#c10 = tf.keras.layers.BatchNormalization()(c10)
c10 = tf.keras.layers.LeakyReLU(alpha=0.01)(c10)
u11 = tf.keras.layers.UpSampling1D(size=2)(c10)
u11 = tf.keras.layers.concatenate([u11,c3],axis=1)
c11 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u11)
#c11 = tf.keras.layers.BatchNormalization()(c11)
c11 = tf.keras.layers.LeakyReLU(alpha=0.01)(c11)
u12 = tf.keras.layers.UpSampling1D(size=2)(c11)
u12 = tf.keras.layers.concatenate([u12,c2],axis=1)
c12 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u12)
#c12 = tf.keras.layers.BatchNormalization()(c12)
c12 = tf.keras.layers.LeakyReLU(alpha=0.01)(c12)
u13 = tf.keras.layers.UpSampling1D(size=2)(c12)
u13 = tf.keras.layers.concatenate([u13,c1],axis=1)
c13 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(u13)
#c13 = tf.keras.layers.BatchNormalization()(c13)
#c13 = tf.keras.layers.LeakyReLU(alpha=0.01)(c13)
c13 = tf.keras.layers.Conv1DTranspose(filters=32,kernel_size=3,strides=1, padding=”same”)(c13)
#c13 = tf.keras.layers.BatchNormalization()(c13)
#c13 = tf.keras.layers.LeakyReLU(alpha=0.01)(c13)
c13 = tf.keras.layers.Conv1DTranspose(filters=2,kernel_size=3,strides=1, padding=”same”)(c13)
#c13 = tf.keras.layers.BatchNormalization()(c13)
#c13 = tf.keras.layers.LeakyReLU(alpha=0.01)(c13)
outputs = tf.keras.layers.Conv1DTranspose(filters=1,kernel_size=1,strides=1, padding=”same”,activation=’sigmoid’)(c13)
return outputs
input = h5py.File(‘pseudo_test_640.mat’)
# create scaler
缩放器 = MinMaxScaler()
# fit scaler on data
# dx = input[‘x’]
# dy = input[‘y’]
dx = np.random.randn(4724,5000)
y = np.random.randn(4724,5000)
scaler.fit(dx)
# apply transform
normalized_data = scaler.transform(dx)
#y = np.array(input[“y”][:])
#inputs = np.expand_dims(normalized_data.transpose(), axis=2)
train_x, test_x , train_mask , test_mask = train_test_split(normalized_data.transpose(), y.transpose(), test_size =0.2,random_state=42)
n_features = 4724
n_input = 4000
input_layer = Input((n_input, n_features))
output_layer = build_model(input_layer)
model = tf.keras.Model([input_layer],[output_layer])
#model = tf.keras.Model([input_layer],[outputs])
import keras.backend as K
ALPHA = 2
GAMMA = 4
def FocalLoss(targets,inputs, alpha = ALPHA , gamma = GAMMA)
targets = K.cast(targets,’float32′)
BCE = K.binary_crossentropy(targets,inputs)
BCE_EXP = K.exp(-BCE)
focal_loss = K.mean(alpha*K.pow((1-BCE_EXP),gamma)*BCE)
return focal_loss
model.compile(metrics=[‘accuracy’],optimizer = ‘adam’,loss = FocalLoss) #loss=[BinaryFocalLoss(gamma=2)],loss = tf.keras.losses.Huber()
model.summary()
generator = tf.keras.preprocessing.sequence.TimeseriesGenerator(train_x,train_mask,length = 1,batch_size= 10)
history = model.fit_generator(generator,steps_per_epoch= (len(train_x))//200,epochs = 5) #,validation_data=(test_x, test_mask)
# generator = tf.keras.preprocessing.sequence.TimeseriesGenerator(train_x,train_mask,length = 212,batch_size= 50)
# history = model.fit_generator(generator,steps_per_epoch= (len(train_x))//200,epochs = 5) #,validation_data=(test_x, test_mask)
”’
n_features = 640
n_input = 4000
input_layer = Input((n_input, n_features))
#input_layer = Input((10,640))
#train_mask = np.asarray(train_mask).astype(‘float64’).reshape((-1,1))
output_layer = build_model(input_layer)
model = tf.keras.Model([input_layer],[output_layer])
#model = tf.keras.Model([input_layer],[outputs])
model.compile(loss = ‘BinaryCrossentropy’,optimizer = ‘adam’,metrics=[‘accuracy’]) #loss=[BinaryFocalLoss(gamma=2)],loss = tf.keras.losses.Huber()
model.summary()
#train_x1 = train_x.reshape(4000,-1)
#train_x1 = np.expand_dims(train_x , axis = -1)
#train_mask1 = np.expand_dims(train_mask , axis = -1)
generator = tf.keras.preprocessing.sequence.TimeseriesGenerator(train_x,train_mask,length = 1,batch_size= 32)
history = model.fit_generator(generator,steps_per_epoch= (len(train_x))//32,validation_data=(test_x, test_mask),epochs = 5) #
#history = model.fit(train_x1,train_mask,epochs = 5,batch_size = 10)
您好 SF_mir…请详细说明您收到的确切错误消息,以便我们更好地帮助您。
你好。
tensorflow timeseries_dataset_from_array 或 timeseriesgenerator 生成的数据是否可以作为 sklearn 的输入?
我想它的类型需要被转换。