原文链接:http://tecdat.cn/?p=8461
工夫序列预测是指咱们必须依据工夫相干的输出来预测后果的问题类型。工夫序列数据的典型示例是股市数据,其中股价随工夫变动。
递归神经网络(RNN)已被证实能够无效解决序列问题。特地地,作为 RNN 的变体的长期短期记忆网络(LSTM)以后正在各种畛域中用于解决序列问题。
序列问题的类型
序列问题能够大抵分为以下几类:
- 一对一:其中有一个输出和一个输入。一对一序列问题的典型示例是您领有一幅图像并且想要为该图像预测单个标签的状况。
- 多对一:在多对一序列问题中,咱们将数据序列作为输出,并且必须预测单个输入。文本分类是多对一序列问题的次要示例,其中咱们有一个单词输出序列,并且咱们心愿预测一个输入标签。
- 一对多:在一对多序列问题中,咱们只有一个输出和一个输入序列。典型示例是图像及其相应的阐明。
- 多对多:多对多序列问题波及序列输出和序列输入。例如,将 7 天的股票价格作为输出,并将接下来 7 天的股票价格作为输入。聊天机器人还是多对多序列问题的一个示例,其中文本序列是输出,而另一个文本序列是输入。
在本文中,咱们将理解如何应用 LSTM 及其不同的变体来解决一对一和多对一的序列问题。
浏览本文后,您将可能基于历史数据解决诸如股价预测,天气预报等问题。因为文本也是单词序列,因而本文中取得的常识也能够用于解决自然语言解决工作,例如文本分类,语言生成等。
一对一序列问题
正如我之前所说,在一对一序列问题中,只有一个输出和一个输入。在本节中,咱们将看到两种类型的序列问题。首先,咱们将理解如何应用单个性能解决一对一的序列问题,而后咱们将理解如何应用多个性能解决一对一的序列问题。
繁多特色的一对一序列问题
在本节中,咱们将看到如何解决每个工夫步都有一个性能的一对一序列问题。
首先,咱们导入将在本文中应用的必须库:
from numpy import arrayfrom keras.preprocessing.text import one_hotfrom keras.preprocessing.sequence import pad_sequencesfrom keras.models import Sequentialfrom keras.layers.core import Activation, Dropout, Densefrom keras.layers import Flatten, LSTMfrom keras.layers import GlobalMaxPooling1Dfrom keras.models import Modelfrom keras.layers.embeddings import Embeddingfrom sklearn.model_selection import train_test_splitfrom keras.preprocessing.text import Tokenizerfrom keras.layers import Inputfrom keras.layers.merge import Concatenatefrom keras.layers import Bidirectionalimport pandas as pdimport numpy as npimport reimport matplotlib.pyplot as plt
创立数据集
在下一步中,咱们将筹备本节要应用的数据集。
X = list()Y = list()X = [x+1 for x in range(20)]Y = [y * 15 for y in X]print(X)print(Y)
在下面的脚本中,咱们创立 20 个输出和 20 个输入。每个输出都蕴含一个工夫步,而该工夫步又蕴含一个性能。每个输入值是_相应输出值的 15 倍_。如果运行下面的脚本,应该看到如下所示的输出和输入值:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20][15, 30, 45, 60, 75, 90, 105, 120, 135, 150, 165, 180, 195, 210, 225, 240, 255, 270, 285, 300]
LSTM 层的输出应为 3D 形态,即(样本,工夫步长,特色)。样本是输出数据中样本的数量。输出中有 20 个样本。工夫步长是每个样本的工夫步长数。咱们有 1 个工夫步。最初,特色对应于每个工夫步的特色数量。每个工夫步都有一个性能。
X = array(X).reshape(20, 1, 1)
通过简略 LSTM 解决方案
当初,咱们能够创立具备一个 LSTM 层的简略 LSTM 模型。
model = Sequential()model.add(LSTM(50, activation='relu', input_shape=(1, 1)))model.add(Dense(1))model.compile(optimizer='adam', loss='mse')print(model.summary())
在下面的脚本中,咱们创立了一个 LSTM 模型,该模型具备一层蕴含 50 个神经元和 relu
激活性能的 LSTM 层。您能够看到输出形态为(1,1),因为咱们的数据具备一个性能的工夫步长。
Layer (type) Output Shape Param #=================================================================lstm_16 (LSTM) (None, 50) 10400_________________________________________________________________dense_15 (Dense) (None, 1) 51=================================================================Total params: 10,451Trainable params: 10,451Non-trainable params: 0
当初让咱们训练模型:
model.fit(X, Y, epochs=2000, validation_split=0.2, batch_size=5)
咱们为 2000 个期间训练模型,批量大小为 5。您能够抉择任何数字。训练模型后,咱们能够对新实例进行预测。
假如咱们要预测输出为 30 的输入。理论输入应为 30 x 15 =450。首先,咱们须要依照 LSTM 的要求将测试数据转换为正确的形态,即 3D 形态。以下 预测数字 30 的输入:
...print(test_output)
我失去的输入值 437.86
略小于 450。
通过重叠 LSTM 解决方案
当初让咱们创立一个重叠的 LSTM,看看是否能够取得更好的后果。数据集将放弃不变,模型将被更改。看上面的脚本:
...print(model.summary())
在下面的模型中,咱们有两个 LSTM 层。留神,第一个 LSTM 层的参数 return_sequences
设置为 True
。当返回序列设置True
为时,每个神经元暗藏状态的输入将用作下一个 LSTM 层的输出。以上模型的摘要如下:
_________________________________________________________________Layer (type) Output Shape Param #=================================================================lstm_33 (LSTM) (None, 1, 50) 10400_________________________________________________________________lstm_34 (LSTM) (None, 50) 20200_________________________________________________________________dense_24 (Dense) (None, 1) 51=================================================================Total params: 30,651Trainable params: 30,651Non-trainable params: 0________________________
接下来,咱们须要训练咱们的模型,如以下脚本所示:
...
print(test_output)
我失去的输入为 459.85,好于咱们通过单个 LSTM 层取得的数字 437。
具备多个特色的一对一序列问题
在最初一节中,每个输出样本都有一个工夫步,其中每个工夫步都有一个特色。在本节中,咱们将看到如何解决输出工夫步长具备多个特色的一对一序列问题。
创立数据集
首先创立数据集。看上面的脚本:
nums = 25X1 = list()X2 = list()X = list()Y = list()...print(X1)print(X2)print(Y)
在下面的脚本中,咱们创立三个列表:X1
,X2
,和 Y
。每个列表蕴含 25 个元素,这意味着总样本大小为 25。最初,Y
蕴含输入。X1
,X2
以及 Y
列表已打印在上面:
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50][3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42, 45, 48, 51, 54, 57, 60, 63, 66, 69, 72, 75][6, 24, 54, 96, 150, 216, 294, 384, 486, 600, 726, 864, 1014, 1176, 1350, 1536, 1734, 1944, 2166, 2400, 2646, 2904, 3174, 3456, 3750]
输入列表中的每个元素基本上都是 X1
and X2
列表中相应元素的乘积。例如,输入列表中的第二个元素是 24,这是列表中的第二个元素(X1
即 4)和列表中的第二个元素(X2
即 6)的乘积。
输出将由 X1
和X2
列表的组合组成,其中每个列表将示意为一列。以下脚本创立最终输出:
X = np.column_stack((X1, X2))print(X)
这是输入:
[[2 3] [4 6] [6 9] [8 12] [10 15] [12 18] [14 21] [16 24] [18 27] [20 30] [22 33] [24 36] [26 39] [28 42] [30 45] [32 48] [34 51] [36 54] [38 57] [40 60] [42 63] [44 66] [46 69] [48 72] [50 75]]
能够看到它蕴含两列,即每个输出两个性能。如前所述,咱们须要将输出转换为 3 维形态。咱们的输出有 25 个样本,其中每个样本蕴含 1 个工夫步,每个工夫步蕴含 2 个特色。以下脚本可重塑输出。
X = array(X).reshape(25, 1, 2)
通过简略 LSTM 解决方案
咱们当初筹备训练咱们的 LSTM 模型。让咱们首先像上一节中那样开发一个 LSTM 层模型:
model = Sequential()model.add(LSTM(80, activation='relu', input_shape=(1, 2)))...print(model.summary())
在这里,咱们的 LSTM 层蕴含 80 个神经元。咱们有两个神经层,其中第一层蕴含 10 个神经元,第二个密集层(也作为输入层)蕴含 1 个神经元。该模型的摘要如下:
Layer (type) Output Shape Param #=================================================================lstm_38 (LSTM) (None, 80) 26560_________________________________________________________________dense_29 (Dense) (None, 10) 810_________________________________________________________________dense_30 (Dense) (None, 1) 11=================================================================Total params: 27,381Trainable params: 27,381Non-trainable params: 0_________________________________________________________________None
以下脚本训练模型:
model.fit(X, Y, epochs=2000, validation_split=0.2, batch_size=5)
让咱们在一个新的数据点上测试咱们训练有素的模型。咱们的数据点将具备两个特色,即(55,80)理论输入应为 55 x 80 =4400。让咱们看看咱们的算法预测了什么。执行以下脚本:
...print(test_output)
我的输入为 3263.44,与理论输入相差甚远。
通过重叠 LSTM 解决方案
当初,让咱们创立一个具备多个 LSTM 和密集层的更简单的 LSTM,看看是否能够改善咱们的答案:
model = Sequential()...print(model.summary())
模型摘要如下:
_________________________________________________________________Layer (type) Output Shape Param #=================================================================lstm_53 (LSTM) (None, 1, 200) 162400_________________________________________________________________lstm_54 (LSTM) (None, 1, 100) 120400_________________________________________________________________lstm_55 (LSTM) (None, 1, 50) 30200_________________________________________________________________lstm_56 (LSTM) (None, 25) 7600_________________________________________________________________dense_43 (Dense) (None, 20) 520_________________________________________________________________dense_44 (Dense) (None, 10) 210_________________________________________________________________dense_45 (Dense) (None, 1) 11=================================================================Total params: 321,341Trainable params: 321,341Non-trainable params: 0
下一步是训练咱们的模型,并在测试数据点(即(55,80))上对其进行测试。
为了进步准确性,咱们将减小批量大小,并且因为咱们的模型更加简单,当初咱们还能够缩小期间数。以下脚本训练 LSTM 模型并在测试数据点上进行预测。
...print(test_output)
在输入中,我失去的值 3705.33 仍小于 4400,但比以前应用单个 LSTM 层取得的 3263.44 的值好得多。您能够将 LSTM 层,密集层,批处理大小和期间数进行不同的组合,以查看是否取得更好的后果。
多对一序列问题
在后面的局部中,咱们看到了如何应用 LSTM 解决一对一的序列问题。在一对一序列问题中,每个样本都蕴含一个或多个特色的单个工夫步。具备单个工夫步长的数据实际上不能视为序列数据。事实证明,密集连贯的神经网络在单个工夫步长数据下体现更好。
理论序列数据蕴含多个工夫步长,例如过来 7 天的股票市场价格,蕴含多个单词的句子等等。
在本节中,咱们将看到如何解决多对一序列问题。在多对一序列问题中,每个输出样本具备多个工夫步长,然而输入由单个元素组成。输出中的每个工夫步都能够具备一个或多个性能。咱们将从具备一个特色的多对一序列问题开始,而后咱们将理解如何解决输出工夫步长具备多个特色的多对一问题。
具备单个性能的多对一序列问题
首先创立数据集。咱们的数据集将蕴含 15 个样本。每个样本将具备 3 个工夫步长,其中每个工夫步长将蕴含一个繁多性能,即一个数字。每个样本的输入将是三个工夫步长中每个步长的数字之和。例如,如果咱们的样本蕴含序列 4,5,6,则输入将为 4 + 5 + 6 = 10。
创立数据集
首先创立一个从 1 到 45 的整数列表。因为咱们要在数据集中取得 15 个样本,因而咱们将对蕴含前 45 个整数的整数列表进行整形。
X = np.array([x+1 for x in range(45)])print(X)
在输入中,您应该看到前 45 个整数:
[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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45]
咱们能够应用以下函数将其重塑为样本数,工夫步长和特色:
X = X.reshape(15,3,1)print(X)
下面的脚本将列表 X
转换为带有 15 个样本,3 个工夫步长和 1 个特色的 3 维形态。下面的脚本还打印了调整后的数据。
[[[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]] [[31] [32] [33]] [[34] [35] [36]] [[37] [38] [39]] [[40] [41] [42]] [[43] [44] [45]]]
咱们曾经将输出数据转换为正确的格局,当初让咱们创立输入向量。正如我之前所说,输入中的每个元素将等于相应输出样本中工夫步长中的值之和。以下脚本创立输入向量:
Y = list()for x in X:...print(Y)
输入数组 Y
如下所示:
[6 15 24 33 42 51 60 69 78 87 96 105 114 123 132]
通过简略 LSTM 解决方案
当初让咱们用一个 LSTM 层创立模型。
model = Sequential()...model.compile(optimizer='adam', loss='mse')
以下脚本训练了咱们的模型:
history = model.fit(...)
训练完模型后,咱们就能够应用它对测试数据点进行预测。让咱们预测数字序列 50、51、52 的输入。理论输入应为 50 + 51 + 52 =153。以下脚本将咱们的测试点转换为 3 维形态,而后预测输入:
....print(test_output)
我的输入为 145.96,比理论输入值 153 少 7 点。
通过重叠 LSTM 解决方案
当初,让咱们创立一个具备多层的简单 LSTM 模型,看看是否能够取得更好的后果。执行以下脚本来创立和训练具备多个 LSTM 和密集层的简单模型:
model = Sequential()....model.compile(optimizer='adam', loss='mse')history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
当初让咱们在测试序列(即 50、51、52)上测试模型:
....print(test_output)
我在这里失去的答案是 155.37,比咱们之前失去的 145.96 更好。在这种状况下,咱们与 153 的理论差值只有 2 分。
通过双向 LSTM 解决方案
双向 LSTM 是一种 LSTM,能够从正向和反向两个方向的输出序列中学习。最终的序列解释是向前和向后学习遍历的串联。让咱们看看应用双向 LSTM 是否能够取得更好的后果。
以下脚本创立了一个双向 LSTM 模型,该模型具备一个双向层和一个作为模型输入的密集层。
from keras.layers import Bidirectional...model.compile(optimizer='adam', loss='mse')
以下脚本训练模型并依据测试序列 50、51 和 52 进行预测。
...print(test_output)
我失去的后果是 152.26,仅比理论后果少一小部分。因而,咱们能够得出结论,对于咱们的数据集,具备单层的双向 LSTM 的性能优于单层和重叠的单向 LSTM。
具备多个特色的多对一序列问题
在多对一序列问题中,咱们有一个输出,其中每个工夫步均蕴含多个特色。输入能够是一个值或多个值,在输出工夫步长中每个性能一个。咱们将在本节中介绍这两种状况。
创立数据集
咱们的数据集将蕴含 15 个样本。每个样本将蕴含 3 个工夫步。每个工夫步都有两个性能。
让咱们创立两个列表。一个将蕴含 3 的倍数,直到 135,即总共 45 个元素。第二个列表将蕴含 5 的倍数,从 1 到 225。第二个列表也将总共蕴含 45 个元素。以下脚本创立这两个列表:
X1 = np.array([x+3 for x in range(0, 135, 3)])...print(X2)
您能够在以下输入中看到列表的内容:
[3 6 9 12 15 18 21 24 27 30 33 36 39 42 45 48 51 54 57 60 63 66 69 72 75 78 81 84 87 90 93 96 99 102 105 108 111 114 117 120 123 126 129 132 135][5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 105 110 115 120 125 130 135 140 145 150 155 160 165 170 175 180 185 190 195 200 205 210 215 220 225]
下面的每个列表代表工夫样本中的一个性能。能够通过合并两个列表来创立聚合数据集,如下所示:
X = np.column_stack((X1, X2))print(X)
输入显示汇总的数据集:
[6 10] [9 15] [12 20] [15 25] [18 30] [21 35] [24 40] [27 45] [30 50] [33 55] [36 60] [39 65] [42 70] [45 75] [48 80] [51 85] [54 90] [57 95] [60 100] [63 105] [66 110] [69 115] [72 120] [75 125] [78 130] [81 135] [84 140] [87 145] [90 150] [93 155] [96 160] [99 165] [102 170] [105 175] [108 180] [111 185] [114 190] [117 195] [120 200] [123 205] [126 210] [129 215] [132 220] [135 225]]
咱们须要将数据重塑为三个维度,以便 LSTM 能够应用它。咱们的数据集 有 45 行,两列。咱们将数据集重塑为 15 个样本,3 个工夫步长和两个特色。
X = array(X).reshape(15, 3, 2)print(X)
您能够在以下输入中看到 15 个样本:
[[[3 5] [6 10] [9 15]] [[12 20] [15 25] [18 30]] [[21 35] [24 40] [27 45]] [[30 50] [33 55] [36 60]] [[39 65] [42 70] [45 75]] [[48 80] [51 85] [54 90]] [[57 95] [60 100] [63 105]] [[66 110] [69 115] [72 120]] [[75 125] [78 130] [81 135]] [[84 140] [87 145] [90 150]] [[93 155] [96 160] [99 165]] [[102 170] [105 175] [108 180]] [[111 185] [114 190] [117 195]] [[120 200] [123 205] [126 210]] [[129 215] [132 220] [135 225]]]
输入还将具备对应于 15 个输出样本的 15 个值。输入中的每个值将是每个输出样本的第三工夫步中两个特征值的总和。例如,第一个样本的第三工夫步长具有特征 9 和 15,因而输入将为 24。相似地,第二个样本的第三工夫步长中的两个特征值别离为 18 和 30;第二个工夫步长中的两个特征值别离为 18 和 30。相应的输入将是 48,依此类推。
以下脚本创立并显示输入向量:
[24 48 72 96 120 144 168 192 216 240 264 288 312 336 360]
当初让咱们通过简略的,重叠的和双向的 LSTM 解决多对一序列问题。
通过简略 LSTM 解决方案
model = Sequential()...history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
模型经过训练。咱们将创立一个测试数据点,而后将应用咱们的模型对测试点进行预测。
...print(test_output)
输出的第三工夫步长的两个特色的总和为 14 + 61 =75。咱们的带有一个 LSTM 层的模型预测为 73.41,这十分靠近。
通过重叠 LSTM 解决方案
以下脚本训练重叠的 LSTM 并在测试点上进行预测:
model = Sequential()model.add(LSTM(200, activation='relu', return_sequences=True, input_shape=(3, 2)))...print(test_output)
我收到的输入为 71.56,比简略的 LSTM 差。仿佛咱们重叠的 LSTM 适度拟合。
通过双向 LSTM 解决方案
这是简略双向 LSTM 的训练脚本,以及用于对测试数据点进行预测的代码:
from keras.layers import Bidirectionalmodel = Sequential()...print(test_output)
输入为 76.82,十分靠近 75。同样,双向 LSTM 仿佛胜过其余算法。
到目前为止,咱们曾经基于来自不同工夫步长的多个因素值预测了单个值。在多对一序列的另一种状况下,您心愿在工夫步长中为每个性能预测一个值。例如,咱们在本节中应用的数据集具备三个工夫步,每个工夫步具备两个特色。咱们可能心愿预测每个性能系列的独自价值。上面的示例很分明,假如咱们有以下输出:
[[[3 5] [6 10] [9 15]]
在输入中,咱们须要一个具备两个性能的工夫步,如下所示:
[12, 20]
您能够看到输入中的第一个值是第一个系列的连续,第二个值是第二个系列的连续。咱们能够通过简略地将输入密集层中神经元的数量更改为咱们想要的输入中的特征值的数量来解决此类问题。然而,首先咱们须要更新输入向量Y
。输出向量将放弃不变:
Y = list()for x in X:...print(Y)
下面的脚本创立一个更新的输入向量并将其打印在管制台上,输入如下所示:
[[12 20] [21 35] [30 50] [39 65] [48 80] [57 95] [66 110] [75 125] [84 140] [93 155] [102 170] [111 185] [120 200] [129 215] [138 230]]
当初,让咱们在数据集上训练咱们的简略,重叠和双向 LSTM 网络。以下脚本训练了一个简略的 LSTM:
model = Sequential()...history = model.fit(X, Y, epochs=1000, validation_split=0.2, verbose=1)
下一步是在测试数据点上测试咱们的模型。以下脚本创立一个测试数据点:
test_input = array([[20,34], [23,39], [26,44]])...print(test_output)
理论输入为[29,45]。咱们的模型预测[29.089157,48.469097],这十分靠近。
当初让咱们训练一个重叠的 LSTM 并预测测试数据点的输入:
model = Sequential()model.add(LSTM(100, activation='relu', return_sequences=True, input_shape=(3, 2)))...print(test_output)
输入为[29.170143,48.688267],再次十分靠近理论输入。
最初,咱们能够训练双向 LSTM 并在测试点上进行预测:
from keras.layers import Bidirectionalmodel = Sequential()...print(test_output)
输入为[29.2071,48.737988]。
您能够再次看到双向 LSTM 做出最精确的预测。
论断
简略的神经网络不适用于解决序列问题,因为在序列问题中,除了以后输出之外,咱们还须要跟踪先前的输出。具备某种记忆的神经网络更适宜解决序列问题。LSTM 就是这样一种网络。