Machine Learning Mastery LSTM 教程(四)
如何使用长短期记忆循环神经网络来打印随机整数
长短期记忆(LSTM)循环神经网络能够学习长序列数据中的顺序依赖性。
它们是用于一系列最先进结果的基本技术,例如图像字幕和机器翻译。
它们也很难理解,特别是如何构建问题以充分利用这种类型的网络。
在本教程中,您将了解如何开发一个简单的 LSTM 循环神经网络,以学习如何在随机整数的特殊序列中打印数字。虽然这是一个微不足道的问题,但开发这个网络将提供将 LSTM 应用于一系列序列预测问题所需的技能。
完成本教程后,您将了解:
- 如何为打印任何给定输入的简单问题开发 LSTM。
- 如何在应用 LSTM 来排序问题时避免初学者的错误,例如打印整数。
- 如何开发一个强大的 LSTM 来回应随机整数的特殊序列的最后一次观察。
让我们开始吧。
如何学习使用长短期记忆循环神经网络回应随机整数 照片由 Franck Michel ,保留一些权利。
概观
本教程分为 4 个部分;他们是:
- 生成和编码随机序列
- 打印电流观察
- 没有语境的打印滞后观察(初学者错误)
- 打印滞后观察
环境
本教程假定您已安装 Python SciPy 环境。您可以在此示例中使用 Python 2 或 3。
本教程假设您安装了 TensorFlow 或 Theano 后端的 Keras v2.0 或更高版本。本教程不需要 GPU,所有代码都可以在 CPU 中轻松运行。
本教程还假设您安装了 scikit-learn,Pandas,NumPy 和 Matplotlib。
如果您在设置 Python 环境时需要帮助,请参阅以下帖子:
生成和编码随机序列
第一步是编写一些代码来生成随机的整数序列,并为网络编码。
生成随机序列
我们可以使用 randint()函数在 Python 中生成随机整数,该函数接受两个参数,指示从中绘制值的整数范围。
在本教程中,我们将问题定义为具有 0 到 99 之间的整数值以及 100 个唯一值。
randint(0, 99)
我们可以将它放在一个名为 generate_sequence()的函数中,该函数将生成所需长度的随机整数序列,默认长度设置为 25 个元素。
此功能如下所列。
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
单热编码随机序列
一旦我们生成了随机整数序列,我们需要将它们转换为适合训练 LSTM 网络的格式。
一种选择是将整数重新缩放到范围[0,1]。这可行,并要求将问题表述为回归。
我有兴趣预测正确的数字,而不是接近预期值的数字。这意味着我更倾向于将问题框架化为分类而不是回归,其中预期输出是一个类,并且有 100 个可能的类值。
在这种情况下,我们可以使用整数值的单热编码,其中每个值由 100 个元素的二进制向量表示,除了整数的索引(标记为 1)之外,该二进制向量都是“0”值。
下面的函数 one_hot_encode()定义了如何迭代整数序列并为每个整数创建二进制向量表示,并将结果作为二维数组返回。
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
我们还需要解码编码值,以便我们可以使用预测,在这种情况下,只需查看它们。
通过使用 argmax()NumPy 函数可以反转单热编码,该函数返回具有最大值的向量中的值的索引。
下面的函数名为 one_hot_decode(),将对编码序列进行解码,并可用于稍后解码来自我们网络的预测。
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
完整的例子
我们可以将所有这些结合在一起。
下面是生成 25 个随机整数序列并将每个整数编码为二进制向量的完整代码清单。
from random import randint
from numpy import array
from numpy import argmax
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate random sequence
sequence = generate_sequence()
print(sequence)
# one hot encode
encoded = one_hot_encode(sequence)
print(encoded)
# one hot decode
decoded = one_hot_decode(encoded)
print(decoded)
运行该示例首先打印 25 个随机整数的列表,然后是序列中所有整数的二进制表示的截断视图,每行一个向量,然后再次解码序列。
您可能会得到不同的结果,因为每次运行代码时都会生成不同的随机整数。
[37, 99, 40, 98, 44, 27, 99, 18, 52, 97, 46, 39, 60, 13, 66, 29, 26, 4, 65, 85, 29, 88, 8, 23, 61]
[[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 1]
[0 0 0 ..., 0 0 0]
...,
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]
[0 0 0 ..., 0 0 0]]
[37, 99, 40, 98, 44, 27, 99, 18, 52, 97, 46, 39, 60, 13, 66, 29, 26, 4, 65, 85, 29, 88, 8, 23, 61]
现在我们知道如何准备和表示整数的随机序列,我们可以看一下使用 LSTM 来学习它们。
打印电流观察
让我们从一个更简单的打印问题开始。
在本节中,我们将开发一个 LSTM 来回应当前的观察结果。给出一个随机整数作为输入,返回与输出相同的整数。
或者稍微更正式地说:
yhat(t) = f(X(t))
也就是说,该模型是将当前时间的值(yhat(t))预测为当前时间(X(t))的观测值的函数(f())。
这是一个简单的问题,因为不需要内存,只是将输入映射到相同输出的函数。
这是一个微不足道的问题,并将展示一些有用的东西:
- 如何使用上面的问题表示机制。
- 如何在 Keras 中使用 LSTM。
- LSTM 的能力需要学习这样一个微不足道的问题。
这将为接下来的滞后观察的打印奠定基础。
首先,我们将开发一个函数来准备随机序列,以便训练或评估 LSTM。此函数必须首先生成随机的整数序列,使用单热编码,然后将输入数据转换为三维数组。
LSTM 需要包含尺寸[样本,时间步长,特征]的 3D 输入。我们的问题将包括每个序列 25 个示例,1 个时间步长和 100 个用于单热编码的特征。
下面列出了此函数,名为 generate_data()。
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# convert to 3d for input
X = encoded.reshape(encoded.shape[0], 1, encoded.shape[1])
return X, encoded
接下来,我们可以定义我们的 LSTM 模型。
模型必须指定输入数据的预期维度。在这种情况下,就时间步长(1)和特征(100)而言。我们将使用具有 15 个内存单元的单个隐藏层 LSTM。
输出层是一个完全连接的层(密集),有 100 个神经元,可以输出 100 个可能的整数。在输出层上使用 softmax 激活功能,以允许网络在可能的输出值上学习和输出分布。
网络将在训练时使用对数丢失函数,适用于多分类问题,以及高效的 ADAM 优化算法。每个训练时期都会报告准确度量,以便了解除损失之外的模型技能。
# define model
model = Sequential()
model.add(LSTM(15, input_shape=(1, 100)))
model.add(Dense(100, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
我们将通过手动运行每个迭代与新生成的序列手动拟合模型。该模型将适合 500 个时期,或以另一种方式说明,训练 500 个随机生成的序列。
这将鼓励网络学习重现实际输入而不是记忆固定的训练数据集。
# fit model
for i in range(500):
X, y = generate_data()
model.fit(X, y, epochs=1, batch_size=1, verbose=2)
一旦模型拟合,我们将对新序列做出预测,并将预测输出与预期输出进行比较。
# evaluate model on new data
X, y = generate_data()
yhat = model.predict(X)
print('Expected: %s' % one_hot_decode(y))
print('Predicted: %s' % one_hot_decode(yhat))
下面列出了完整的示例。
from random import randint
from numpy import array
from numpy import argmax
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# convert to 3d for input
X = encoded.reshape(encoded.shape[0], 1, encoded.shape[1])
return X, encoded
# define model
model = Sequential()
model.add(LSTM(15, input_shape=(1, 100)))
model.add(Dense(100, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
# fit model
for i in range(500):
X, y = generate_data()
model.fit(X, y, epochs=1, batch_size=1, verbose=2)
# evaluate model on new data
X, y = generate_data()
yhat = model.predict(X)
print('Expected: %s' % one_hot_decode(y))
print('Predicted: %s' % one_hot_decode(yhat))
运行该示例会在每个时期打印日志丢失和准确率。
网络有点过度规划,拥有比这个简单问题所需的更多的内存单元和训练时期,你可以通过网络快速达到 100%的准确率来看到这一点。
在运行结束时,将预测的序列与随机生成的序列进行比较,并且两者看起来相同。
您的具体结果可能会有所不同,但您的网络应该达到 100%的准确率,因为网络规模较大,训练时间长于问题所需的时间。
...
0s - loss: 0.0895 - acc: 1.0000
Epoch 1/1
0s - loss: 0.0785 - acc: 1.0000
Epoch 1/1
0s - loss: 0.0789 - acc: 1.0000
Epoch 1/1
0s - loss: 0.0832 - acc: 1.0000
Epoch 1/1
0s - loss: 0.0927 - acc: 1.0000
Expected: [18, 41, 49, 56, 86, 25, 96, 3, 75, 24, 57, 95, 81, 44, 2, 22, 76, 34, 41, 4, 69, 47, 1, 97, 57]
Predicted: [18, 41, 49, 56, 86, 25, 96, 3, 75, 24, 57, 95, 81, 44, 2, 22, 76, 34, 41, 4, 69, 47, 1, 97, 57]
现在我们知道如何使用工具来创建和表示随机序列并使 LSTM 适合学习回应当前序列,让我们看看如何使用 LSTM 来学习如何回应过去的观察。
无背景的打印滞后观察
(_ 初学者错误 _)
预测滞后观察的问题可以更正式地定义如下:
yhat(t) = f(X(t-n))
其中当前时间步长 yhat(t)的预期输出被定义为特定先前观察(X(t-n))的函数(f())。
LSTM 的承诺表明,您可以一次向网络显示一个示例,并且网络将使用内部状态来学习并充分记住先前的观察以解决此问题。
我们来试试吧。
首先,我们必须更新 generate_data()函数并重新定义问题。
我们将使用编码序列的移位版本作为输入,并使用截断版本的编码序列作为输出,而不是使用相同的序列进行输入和输出。
需要进行这些更改才能获取一系列数字,例如[1,2,3,4],并将它们转换为带有输入(X)和输出(y)组件的监督学习问题,例如:
X y
1, NaN
2, 1
3, 2
4, 3
NaN, 4
在此示例中,您可以看到第一行和最后一行不包含足够的数据供网络学习。这可以被标记为“无数据”值并被屏蔽,但更简单的解决方案是简单地从数据集中删除它。
更新的 generate_data()函数如下所示:
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# drop first value from X
X = encoded[1:, :]
# convert to 3d for input
X = X.reshape(X.shape[0], 1, X.shape[1])
# drop last value from y
y = encoded[:-1, :]
return X, y
我们必须测试这个更新的数据表示,以确认它符合我们的预期。为此,我们可以生成序列并查看序列上的解码 X 和 y 值。
X, y = generate_data()
for i in range(len(X)):
a, b = argmax(X[i,0]), argmax(y[i])
print(a, b)
下面提供了此完整性检查的完整代码清单。
from random import randint
from numpy import array
from numpy import argmax
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# drop first value from X
X = encoded[1:, :]
# convert to 3d for input
X = X.reshape(X.shape[0], 1, X.shape[1])
# drop last value from y
y = encoded[:-1, :]
return X, y
# test data generator
X, y = generate_data()
for i in range(len(X)):
a, b = argmax(X[i,0]), argmax(y[i])
print(a, b)
运行该示例将打印问题框架的 X 和 y 组件。
我们可以看到,在冷启动的情况下,网络学习的第一个模式很难(不可能)。我们可以通过数据看到 yhat(t)== X(t-1)的预期模式。
78 65
7 78
16 7
11 16
23 11
99 23
39 99
53 39
82 53
6 82
18 6
17 18
49 17
4 49
34 4
77 34
46 77
22 46
40 22
76 40
85 76
87 85
17 87
75 17
网络设计类似,但只有一个小的变化。
一次一个地向网络显示观察并且执行重量更新。因为我们期望观察之间的状态携带学习先前观察所需的信息,所以我们需要确保在每批之后不重置该状态(在这种情况下,一批是一次训练观察)。我们可以通过使 LSTM 层有状态并在状态重置时手动管理来实现。
这涉及在 LSTM 层上将有状态参数设置为 True,并使用包含尺寸[batchsize,timesteps,features]的 batch_input_shape 参数定义输入形状。
对于给定的随机序列,存在 24 个 X,y 对,因此使用 6 的批量大小(4 批 6 个样品= 24 个样品)。请记住,序列被分解为样本,并且在执行网络权重更新之前,样本可以批量显示给网络。使用 50 个内存单元的大型网络,再次过度规定问题所需的容量。
model.add(LSTM(50, batch_input_shape=(6, 1, 100), stateful=True))
接下来,在每个时期(随机生成的序列的一次迭代)之后,可以手动重置网络的内部状态。该模型适用于 2,000 个训练时期,并且注意不要使序列内的样本混洗。
# fit model
for i in range(2000):
X, y = generate_data()
model.fit(X, y, epochs=1, batch_size=6, verbose=2, shuffle=False)
model.reset_states()
综合这些,下面列出了完整的例子。
from random import randint
from numpy import array
from numpy import argmax
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# drop first value from X
X = encoded[1:, :]
# convert to 3d for input
X = X.reshape(X.shape[0], 1, X.shape[1])
# drop last value from y
y = encoded[:-1, :]
return X, y
# define model
model = Sequential()
model.add(LSTM(50, batch_input_shape=(6, 1, 100), stateful=True))
model.add(Dense(100, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
# fit model
for i in range(2000):
X, y = generate_data()
model.fit(X, y, epochs=1, batch_size=6, verbose=2, shuffle=False)
model.reset_states()
# evaluate model on new data
X, y = generate_data()
yhat = model.predict(X, batch_size=6)
print('Expected: %s' % one_hot_decode(y))
print('Predicted: %s' % one_hot_decode(yhat))
运行该示例会产生令人惊讶的结果。
无法学习问题,训练以 0%精确度回归序列中最后一次观察的模型结束。
...
Epoch 1/1
0s - loss: 4.6042 - acc: 0.0417
Epoch 1/1
0s - loss: 4.6215 - acc: 0.0000e+00
Epoch 1/1
0s - loss: 4.5802 - acc: 0.0000e+00
Epoch 1/1
0s - loss: 4.6023 - acc: 0.0000e+00
Epoch 1/1
0s - loss: 4.6071 - acc: 0.0000e+00
Expected: [71, 44, 6, 11, 91, 23, 55, 37, 53, 4, 42, 15, 81, 6, 57, 97, 49, 69, 56, 86, 70, 12, 61, 48]
Predicted: [49, 49, 49, 87, 49, 96, 96, 96, 96, 96, 85, 96, 96, 96, 96, 96, 96, 96, 49, 49, 87, 96, 49, 49]
怎么会这样?
初学者的错误
这是初学者常犯的错误,如果您使用 RNN 或 LSTM 进行了阻塞,那么您可能会发现上述错误。
具体而言,LSTM 的力量确实来自所保持的学习内部状态,但是如果它被训练为过去观察的函数,则该状态仅是强大的。
换句话说,您必须为网络提供预测的上下文(例如,可能包含时间依赖性的观察)作为输入上的时间步长。
上述公式训练网络将输出学习为仅当前输入值的函数,如第一个示例所示:
yhat(t) = f(X(t))
根据我们的要求,不是最后 n 个观测值的函数,甚至不是之前的观测值:
yhat(t) = f(X(t-1))
LSTM 一次只需要一个输入来学习这种未知的时间依赖性,但它必须对序列进行反向传播才能学习这种依赖性。您必须提供序列的过去观察结果作为上下文。
您没有定义窗口(如多层感知机的情况,其中每个过去的观察是加权输入);相反,您正在定义历史观测的范围,LSTM 将尝试从中学习时间依赖性(f(X(t-1),... X(t-n)))。
需要明确的是,这是在 Keras 中使用 LSTM 时的初学者的错误,而不一定是一般的。
打印滞后观察
现在我们已经为初学者找到了常见的陷阱,我们可以开发一个 LSTM 来回应之前的观察。
第一步是再次重新定义问题的定义。
我们知道网络只需要最后一次观察作为输入,以便做出正确的预测。但是我们希望网络能够了解哪些过去的观察结果是为了正确解决这个问题。因此,我们将提供最后 5 个观察的子序列作为上下文。
具体来说,如果我们的序列包含:[1,2,3,4,5,6,7,8,9,10],则 X,y 对看起来如下:
X, y
NaN, NaN, NaN, NaN, NaN, NaN
NaN, NaN, NaN, NaN, 1, NaN
NaN, NaN, NaN, 1, 2, 1
NaN, NaN, 1, 2, 3, 2
NaN, 1, 2, 3, 4, 3
1, 2, 3, 4, 5, 4
2, 3, 4, 5, 6, 5
3, 4, 5, 6, 7, 6
4, 5, 6, 7, 8, 7
5, 6, 7, 8, 9, 8
6, 7, 8, 9, 10, 9
7, 8, 9, 10, NaN, 10
在这种情况下,您可以看到前 5 行和后 1 行不包含足够的数据,因此在这种情况下,我们将删除它们。
我们将使用 Pandas shift()函数创建序列的移位版本,并使用 Pandas concat()函数将移位序列重新组合在一起。然后,我们将手动排除不可行的行。
下面列出了更新的 generate_data()函数。
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# create lag inputs
df = DataFrame(encoded)
df = concat([df.shift(4), df.shift(3), df.shift(2), df.shift(1), df], axis=1)
# remove non-viable rows
values = df.values
values = values[5:,:]
# convert to 3d for input
X = values.reshape(len(values), 5, 100)
# drop last value from y
y = encoded[4:-1,:]
print(X.shape, y.shape)
return X, y
同样,我们可以通过生成序列并比较解码的 X,y 对来理智地检查这个更新的函数。下面列出了完整的示例。
from random import randint
from numpy import array
from numpy import argmax
from pandas import concat
from pandas import DataFrame
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# create lag inputs
df = DataFrame(encoded)
df = concat([df.shift(4), df.shift(3), df.shift(2), df.shift(1), df], axis=1)
# remove non-viable rows
values = df.values
values = values[5:,:]
# convert to 3d for input
X = values.reshape(len(values), 5, 100)
# drop last value from y
y = encoded[4:-1,:]
return X, y
# test data generator
X, y = generate_data()
for i in range(len(X)):
a, b, c, d, e, f = argmax(X[i,0]), argmax(X[i,1]), argmax(X[i,2]), argmax(X[i,3]), argmax(X[i,4]), argmax(y[i])
print(a, b, c, d, e, f)
运行该示例将最后 5 个值的上下文显示为输入,将最后一个先前观察(X(t-1))显示为输出。
57 96 99 77 44 77
96 99 77 44 45 44
99 77 44 45 28 45
77 44 45 28 70 28
44 45 28 70 73 70
45 28 70 73 74 73
28 70 73 74 73 74
70 73 74 73 64 73
73 74 73 64 29 64
74 73 64 29 15 29
73 64 29 15 94 15
64 29 15 94 98 94
29 15 94 98 89 98
15 94 98 89 52 89
94 98 89 52 96 52
98 89 52 96 46 96
89 52 96 46 46 46
52 96 46 46 85 46
96 46 46 85 49 85
46 46 85 49 59 49
我们现在可以开发 LSTM 来学习这个问题。
给定序列有 20 个 X,y 对;因此,选择批量大小为 5(4 批 5 个实例= 20 个样品)。
使用相同的结构,LSTM 隐藏层中有 50 个内存单元,输出层中有 100 个神经元。该网络适合 2000 个时期,每个时期后内部状态重置。
完整的代码清单如下。
from random import randint
from numpy import array
from numpy import argmax
from pandas import concat
from pandas import DataFrame
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=25):
return [randint(0, 99) for _ in range(length)]
# one hot encode sequence
def one_hot_encode(sequence, n_unique=100):
encoding = list()
for value in sequence:
vector = [0 for _ in range(n_unique)]
vector[value] = 1
encoding.append(vector)
return array(encoding)
# decode a one hot encoded string
def one_hot_decode(encoded_seq):
return [argmax(vector) for vector in encoded_seq]
# generate data for the lstm
def generate_data():
# generate sequence
sequence = generate_sequence()
# one hot encode
encoded = one_hot_encode(sequence)
# create lag inputs
df = DataFrame(encoded)
df = concat([df.shift(4), df.shift(3), df.shift(2), df.shift(1), df], axis=1)
# remove non-viable rows
values = df.values
values = values[5:,:]
# convert to 3d for input
X = values.reshape(len(values), 5, 100)
# drop last value from y
y = encoded[4:-1,:]
return X, y
# define model
model = Sequential()
model.add(LSTM(50, batch_input_shape=(5, 5, 100), stateful=True))
model.add(Dense(100, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['acc'])
# fit model
for i in range(2000):
X, y = generate_data()
model.fit(X, y, epochs=1, batch_size=5, verbose=2, shuffle=False)
model.reset_states()
# evaluate model on new data
X, y = generate_data()
yhat = model.predict(X, batch_size=5)
print('Expected: %s' % one_hot_decode(y))
print('Predicted: %s' % one_hot_decode(yhat))
运行该示例表明网络可以适应问题并且正确地学习在先前 5 次观察的上下文中将 X(t-1)观测作为预测返回。
示例输出如下;根据不同的随机序列,您的具体输出可能不同
...
Epoch 1/1
0s - loss: 0.1763 - acc: 1.0000
Epoch 1/1
0s - loss: 0.2393 - acc: 0.9500
Epoch 1/1
0s - loss: 0.1674 - acc: 1.0000
Epoch 1/1
0s - loss: 0.1256 - acc: 1.0000
Epoch 1/1
0s - loss: 0.1539 - acc: 1.0000
Expected: [24, 49, 86, 73, 51, 6, 6, 52, 34, 32, 0, 14, 83, 16, 37, 75, 41, 40, 80, 33]
Predicted: [24, 49, 86, 73, 51, 6, 6, 52, 34, 32, 0, 14, 83, 16, 37, 75, 41, 40, 80, 33]
扩展
本节列出了本教程中实验的一些扩展。
- 忽略内部状态。注意通过在时期结束时手动重置状态来保持序列内样本的 LSTM 的内部状态。我们知道网络已经具有通过时间步长在每个样本中所需的所有上下文和状态。探索额外的跨样本状态是否为模型的技能带来任何好处。
- 掩码丢失数据。在数据准备期间,删除了缺少数据的行。探索使用特殊值(例如-1)标记缺失值并查看 LSTM 是否可以从这些示例中学习。还要探索使用蒙版层作为输入并探索掩盖缺失值。
- 整个序列为时间步。仅提供了最后 5 个观测值的背景作为学习打印的上下文。探索使用整个随机序列作为每个样本的上下文,随着序列的展开而构建。这可能需要填充甚至屏蔽缺失值以满足对 LSTM 的固定大小输入的期望。
- 打印不同滞后值。在回波示例中使用特定滞后值(t-1)。探索在打印中使用不同的滞后值以及它如何影响属性,例如模型技能,训练时间和 LSTM 层大小。我希望每个滞后都可以使用相同的模型结构来学习。
- 回波延迟序列。训练该网络以回应特定的滞后观察。探索打印滞后序列的变体。这可能需要在网络输出上使用 TimeDistributed 层来实现序列到序列预测。
你有没有探索过这些扩展? 在下面的评论中分享您的发现。
摘要
在本教程中,您了解了如何开发 LSTM 以解决从随机整数序列打印滞后观察的问题。
具体来说,你学到了:
- 如何为问题生成和编码测试数据。
- 在尝试解决 LSTM 的这个问题和类似问题时,如何避免初学者的错误。
- 如何开发一个强大的 LSTM 来回应随机整数的特殊序列中的整数。
你有任何问题吗? 在评论中提出您的问题,我会尽力回答。
Keras 长短期记忆循环神经网络的迷你课程
原文:
machinelearningmastery.com/long-short-term-memory-recurrent-neural-networks-mini-course/
长期短期记忆(LSTM)复现神经网络是目前最有趣的深度学习类型之一。
它们被用于展示复杂问题领域的世界级结果,例如语言翻译,自动图像字幕和文本生成。
LSTM 与多层感知机和卷积神经网络的不同之处在于它们专门用于序列预测问题。
在这个迷你课程中,您将了解如何快速将 LSTM 模型用于您自己的序列预测问题。
完成这个迷你课程后,您将知道:
- LSTM 是什么,如何训练,以及如何准备训练 LSTM 模型的数据。
- 如何开发一套 LSTM 模型,包括堆叠,双向和编解码器模型。
- 如何通过超参数优化,更新和最终模型来充分利用模型。
让我们开始吧。
注:这是一个很大的指南;你可能想要为它添加书签。
具有 Keras 的长期短期记忆循环神经网络的迷你课程 照片由 Nicholas A. Tonelli ,保留一些权利。
这个迷你课程是谁?
在我们开始之前,让我们确保您在正确的位置。
本课程适用于了解一些应用机器学习并且需要快速掌握 LSTM 的开发人员。
也许您想要或需要在项目中开始使用 LSTM。本指南旨在帮助您快速有效地完成此任务。
- 你了解 Python 的方法。
- 你知道你在 SciPy 周围的方式。
- 您知道如何在工作站上安装软件。
- 你知道如何纠缠自己的数据。
- 您知道如何使用机器学习来解决预测性建模问题。
- 你可能知道一点点深度学习。
- 你可能知道一点 Keras。
您知道如何设置工作站以使用 Keras 和 scikit-learn;如果没有,你可以在这里学习如何:
本指南采用自上而下和结果优先的机器学习风格,您已经习惯了。它将教你如何获得结果,但它不是灵丹妙药。
您将通过本指南开发有用的技能。
完成本课程后,您将:
- 了解 LSTM 的工作原理。
- 知道如何为 LSTM 准备数据。
- 知道如何应用一系列类型的 LSTM。
- 知道如何将 LSTM 调整为问题。
- 知道如何保存 LSTM 模型并使用它来做出预测。
接下来,让我们回顾一下课程。
迷你课程概述
这个迷你课程分为 14 节课。
您可以每天完成一节课(推荐)或在一天内完成所有课程(硬核!)。
这取决于你有空的时间和你的热情程度。
以下是 14 个课程,可以帮助您开始使用 Python 中的 LSTM 并提高工作效率。课程分为三个主题:基础,模型和高级。
LSTM 迷你课程概述
基金会
这些课程的重点是在使用 LSTM 之前需要了解的事项。
- 第 01 课:什么是 LSTM?
- 第 02 课:如何训练 LSTM
- 第 03 课:如何为 LSTM 准备数据
- 第 04 课:如何在 Keras 开发 LSTM
楷模
- 第 05 课:如何开发香草 LSTMs
- 第 06 课:如何开发栈式 LSTM
- 第 07 课:如何开发 CNN LSTM
- 第 08 课:如何开发编解码器 LSTM
- 第 09 课:如何开发双向 LSTM
- 第 10 课:如何开发注意力的 LSTM
- 第 11 课:如何开发生成 LSTM
高级
- 第 12 课:如何调整 LSTM 超参数
- 第 13 课:如何更新 LSTM 模型
- 第 14 课:如何使用 LSTM 做出预测
每节课可能需要 60 秒或 60 分钟。花点时间,按照自己的进度完成课程。提出问题,甚至在下面的评论中发布结果。
课程期望你去学习如何做事。我会给你提示,但每节课的部分内容是强迫你去哪里寻求帮助(提示,我在这个博客上有所有的答案;使用搜索)。
我确实在早期课程中提供了更多帮助,因为我希望你建立一些自信和惯性。
挂在那里;不要放弃!
基金会
本节中的课程旨在让您了解 LSTM 的工作原理以及如何使用 Keras 库实现 LSTM 模型。
第 1 课:什么是 LSTM?
目标
本课程的目标是充分理解高级 LSTM,以便您可以向同事或经理解释它们是什么以及它们如何工作。
问题
- 什么是序列预测?一些例子是什么?
- 传统神经网络对序列预测有哪些局限性?
- RNN 对序列预测的承诺是什么?
- 什么是 LSTM 及其组成部分是什么?
- LSTM 有哪些突出的应用?
进一步阅读
- 深度学习的循环神经网络速成课
- 循环神经网络序列预测模型的简要介绍
- 循环神经网络对时间序列预测的承诺
- 关于长短期记忆网络对时间序列预测的适用性
- 专家对长短期记忆网络的简要介绍
- 8 深度学习的鼓舞人心的应用
第 2 课:如何训练 LSTM
目标
本课程的目的是了解如何在示例序列上训练 LSTM 模型。
Questions
- 传统 RNN 的训练有哪些常见问题?
- LSTM 如何克服这些问题?
- 什么算法用于训练 LSTM?
- Backpropagation Through Time 如何运作?
- 什么是截断的 BPTT,它提供了什么好处?
- 如何在 Keras 中实现和配置 BPTT?
Further Reading
第 3 课:如何为 LSTM 准备数据
Goal
本课程的目标是了解如何准备用于 LSTM 模型的序列预测数据。
Questions
- 如何准备用于 LSTM 的数字数据?
- 如何准备用于 LSTM 的分类数据?
- 使用 LSTM 时如何处理序列中的缺失值?
- 如何将序列构建为监督学习问题?
- 在使用 LSTM 时,如何处理长序列?
- 你如何处理不同长度的输入序列?
- 如何重塑 Keras 中 LSTM 的输入数据?
实验
演示如何将数字输入序列转换为适合训练 LSTM 的形式。
Further Reading
- 如何在 Python 中扩展长短期记忆网络的数据
- 如何使用 Python 编写单热编码序列数据
- 如何使用 Python 处理序列预测问题中的缺失时间步长
- 如何将时间序列转换为 Python 中的监督学习问题
- 如何处理具有长短期记忆循环神经网络的超长序列
- 如何准备 Keras 中截断反向传播的序列预测
- 可变长度输入序列的数据准备
第 4 课:如何在 Keras 开发 LSTM
Goal
本课程的目标是了解如何使用 Python 中的 Keras 深度学习库定义,拟合和评估 LSTM 模型。
Questions
- 你如何定义 LSTM 模型?
- 你如何编译 LSTM 模型?
- 你如何适应 LSTM 模型?
- 您如何评估 LSTM 模型?
- 如何使用 LSTM 模型做出预测?
- 如何将 LSTM 应用于不同类型的序列预测问题?
Experiment
准备一个示例,演示 LSTM 模型在序列预测问题上的生命周期。
Further Reading
楷模
本节中的课程旨在教您如何使用 LSTM 模型获得序列预测问题的结果。
第 5 课:如何开发香草 LSTM
Goal
本课程的目标是学习如何开发和评估香草 LSTM 模型。
- 什么是香草 LSTM 架构?
- 什么是香草 LSTM 应用的例子?
Experiment
设计并执行一个实验,演示序列预测问题的香草 LSTM。
Further Reading
- 用 Keras 在 Python 中用 LSTM 循环神经网络进行序列分类
- 用 Keras 用 Python 中的 LSTM 循环神经网络进行时间序列预测
- Python 中长期短期记忆网络的时间序列预测
第 6 课:如何开发栈式 LSTM
Goal
本课程的目标是学习如何开发和评估堆叠的 LSTM 模型。
Questions
- 在层次结构的序列问题上使用香草 LSTM 有什么困难?
- 堆叠的 LSTM 是什么?
- 什么是栈式 LSTM 应用于何处的示例?
- 栈式 LSTM 提供哪些好处?
- 如何在 Keras 中实现栈式 LSTM?
Experiment
设计并执行一个实验,演示具有分层输入结构的序列预测问题的栈式 LSTM。
Further Reading
第 7 课:如何开发 CNN LSTM
Goal
本课程的目标是学习如何开发在前端使用卷积神经网络的 LSTM 模型。
Questions
- 使用具有空间输入数据的香草 LSTM 有什么困难?
- 什么是 CNN LSTM 架构?
- 有哪些 CNN LSTM 的例子?
- CNN LSTM 提供哪些好处?
- 如何在 Keras 中实现 CNN LSTM 架构?
Experiment
设计并执行一个实验,演示有空间输入的序列预测问题的 CNN LSTM。
Further Reading
- 用 Keras 在 Python 中用 LSTM 循环神经网络进行序列分类
第 8 课:如何开发编解码器 LSTM
Goal
本课程的目标是学习如何开发编解码器 LSTM 模型。
Questions
- 什么是序列到序列(seq2seq)预测问题?
- 在 seq2seq 问题上使用香草 LSTM 有什么困难?
- 什么是编解码器 LSTM 架构?
- 编解码器 LSTM 有哪些例子?
- 编解码器 LSTM 有什么好处?
- 如何在 Keras 中实现编解码器 LSTM?
Experiment
设计并执行一个实验,演示序列到序列预测问题的编解码器 LSTM。
Further Reading
- 如何在 Python 中为长期短期记忆网络使用时间分布层
- 如何学习使用 seq2seq 循环神经网络相加数字
- 如何将编解码器 LSTM 用于随机整数的回波序列
第 9 课:如何开发双向 LSTM
Goal
本课程的目标是学习如何开发双向 LSTM 模型。
Questions
- 什么是双向 LSTM?
- 有哪些使用双向 LSTM 的例子?
- 双向 LSTM 比香草 LSTM 有什么好处?
- 双向架构引发了关于时间步长的问题?
- 如何在 Keras 中实现双向 LSTM?
Experiment
设计并执行一个实验,在序列预测问题上比较前向,后向和双向 LSTM 模型。
Further Reading
第 10 课:如何开发注意力的 LSTM
Goal
本课的目的是学习如何开发 LSTM 模型。
Questions
- 具有中性信息的长序列对 LSTM 有何影响?
- LSTM 型号的注意事项是什么?
- 在 LSTM 中使用注意力的一些例子是什么?
- 注意为序列预测提供了什么好处?
- 如何在 Keras 中实现注意力架构?
Experiment
设计并执行一项实验,该实验将注意力集中在具有长序列中性信息的序列预测问题上。
Further Reading
- 长期短期记忆循环神经网络的注意事项
第 11 课:如何开发生成 LSTM
Goal
本课程的目标是学习如何开发用于生成模型的 LSTM。
- 什么是生成模型?
- 如何将 LSTM 用作生成模型?
- LSTM 作为生成模型的一些例子是什么?
- LSTM 作为生成模型有哪些好处?
Experiment
设计并执行实验以学习文本语料库并生成具有相同语法,语法和样式的新文本样本。
Further Reading
- 使用 Keras 在 Python 中使用 LSTM 循环神经网络生成文本
高级
本节中的课程旨在教您如何根据自己的序列预测问题从 LSTM 模型中获得最大收益。
第 12 课:如何调整 LSTM 超参数
Goal
本课程的目标是学习如何调整 LSTM 超参数。
Questions
- 我们如何诊断 LSTM 模型的过度学习或学习不足?
- 调整模型超参数的两种方案是什么?
- 鉴于 LSTM 是随机算法,如何可靠地估计模型技能?
- 列出可以调整的 LSTM 超参数,并提供可以评估的值的示例:
- 模型初始化和行为。
- 模型架构和结构。
- 学习行为。
Experiment
设计并执行实验以调整 LSTM 的一个超参数并选择最佳配置。
Further Reading
第 13 课:如何更新 LSTM 模型
Goal
本课程的目标是学习如何在新数据可用后更新 LSTM 模型。
Questions
- 更新 LSTM 模型以响应新数据有什么好处?
- 使用新数据更新 LSTM 模型有哪些方案?
Experiment
设计并执行实验以使 LSTM 模型适应序列预测问题,该问题与不同模型更新方案的模型技能的影响形成对比。
Further Reading
第 14 课:如何使用 LSTM 做出预测
Goal
本课程的目标是学习如何最终确定 LSTM 模型并使用它来预测新数据。
Questions
- 你如何在 Keras 中保存模型结构和重量?
- 你如何适应最终的 LSTM 模型?
- 如何使用最终模型做出预测?
Experiment
设计并执行实验以适应最终的 LSTM 模型,将其保存到文件,然后加载它并对保留的验证数据集做出预测。
Further Reading
结束!
(_ 看你有多远 _)
你做到了。做得好!
花点时间回顾一下你到底有多远。以下是您学到的知识:
- LSTM 是什么以及为什么它们是序列预测的首选深度学习技术。
- LSTM 使用 BPTT 算法进行训练,该算法也强加了一种思考序列预测问题的方法。
- 用于序列预测的数据准备可以涉及掩蔽缺失值以及分割,填充和截断输入序列。
- Keras 为 LSTM 模型提供了 5 步生命周期,包括定义,编译,拟合,评估和预测。
- 香草 LSTM 由输入层,隐藏的 LSTM 层和密集输出层组成。
- 隐藏的 LSTM 层可以堆叠,但必须从一层到另一层暴露整个序列的输出。
- 在处理图像和视频数据时,CNN 可用作 LSTM 的输入层。
- 在预测可变长度输出序列时可以使用编解码器架构。
- 在双向 LSTM 中向前和向后提供输入序列可以提高某些问题的技能。
- 该注意力可以为包含中性信息的长输入序列提供优化。
- LSTM 可以学习输入数据的结构化关系,进而可以用来生成新的例子。
- LSTM 的 LSTM 超参数可以像任何其他随机模型一样进行调整。
- 当新数据可用时,可以更新适合的 LSTM 模型。
- 最终的 LSTM 模型可以保存到文件中,然后加载以便对新数据做出预测。
不要轻视这一点;你在很短的时间内走了很长的路。
这只是您与 Keras 的 LSTM 之旅的开始。继续练习和发展你的技能。
摘要
你如何使用迷你课程? 你喜欢这个迷你课吗?
你有什么问题吗?有没有任何问题? 让我知道。在下面发表评论。
LSTM 自编码器的温和介绍
LSTM 自编码器是使用编解码器 LSTM 架构的用于序列数据的自编码器的实现。
一旦拟合,模型的编码器部分可用于编码或压缩序列数据,而序列数据又可用于数据可视化或作为监督学习模型的特征向量输入。
在这篇文章中,您将发现 LSTM Autoencoder 模型以及如何使用 Keras 在 Python 中实现它。
阅读这篇文章后,你会知道:
- 自编码器是一种自我监督的学习模型,可以学习输入数据的压缩表示。
- LSTM 自编码器可以学习序列数据的压缩表示,并且已经用于视频,文本,音频和时间序列序列数据。
- 如何使用 Keras 深度学习库在 Python 中开发 LSTM Autoencoder 模型。
让我们开始吧。
LSTM 自编码器 的温和介绍 Ken Lund 的照片,保留一些权利。
概观
这篇文章分为六个部分;他们是:
- 什么是自编码器?
- 序列问题
- 编解码器 LSTM 模型
- 什么是 LSTM 自编码器?
- LSTM 自编码器的早期应用
- 如何在 Keras 中创建 LSTM 自编码器
什么是自编码器?
自编码器是一种神经网络模型,旨在学习输入的压缩表示。
它们是一种无监督的学习方法,尽管从技术上讲,它们是使用有监督的学习方法训练的,称为自我监督。它们通常作为试图重新创建输入的更广泛模型的一部分进行训练。
例如:
X = model.predict(X)
自编码器模型的设计有目的地通过将架构限制在模型的中点处的瓶颈来实现这种挑战,从中执行输入数据的重建。
有许多类型的自编码器,它们的使用各不相同,但更常见的用途可能是学习或自动特征提取模型。
在这种情况下,一旦模型拟合,就可以丢弃模型的重建方面,并且可以使用直到瓶颈点的模型。瓶颈处的模型输出是固定长度向量,其提供输入数据的压缩表示。
然后可以将来自域的输入数据提供给模型,并且瓶颈处的模型的输出可以用作监督学习模型中的特征向量,用于可视化,或者更一般地用于降低维度。
序列问题
序列预测问题具有挑战性,尤其是因为输入序列的长度可以变化。
这具有挑战性,因为机器学习算法,特别是神经网络,设计用于固定长度输入。
序列数据的另一个挑战是观察的时间顺序可能使得提取适合用作监督学习模型的输入的特征具有挑战性,通常需要在领域或信号处理领域的深入专业知识。
最后,涉及序列的许多预测性建模问题需要预测其本身也是序列。这些被称为序列到序列或 seq2seq 预测问题。
您可以在此处详细了解序列预测问题:
编解码器 LSTM 模型
诸如长短期存储器或 LSTM 网络的循环神经网络专门设计用于支持输入数据序列。
它们能够学习输入序列的时间排序中的复杂动态,以及使用内部存储器来记忆或使用长输入序列中的信息。
LSTM 网络可以组织成称为编解码器 LSTM 的架构,该架构允许该模型用于支持可变长度输入序列并预测或输出可变长度输出序列。
该架构是复杂序列预测问题(如语音识别和文本转换)中许多进步的基础。
在该架构中,编码器 LSTM 模型逐步读取输入序列。在读入整个输入序列之后,该模型的隐藏状态或输出将整个输入序列的内部学习表示表示为固定长度向量。然后将该向量作为输入提供给解码器模型,该解码器模型在生成输出序列中的每个步骤时对其进行解释。
您可以在此处了解有关编解码器架构的更多信息
什么是 LSTM 自编码器?
LSTM 自编码器是使用编解码器 LSTM 架构的用于序列数据的自编码器的实现。
对于给定的序列数据集,编解码器 LSTM 被配置为读取输入序列,对其进行编码,对其进行解码并重新创建它。基于模型重新创建输入序列的能力来评估模型的表现。
一旦模型达到重建序列的所需表现水平,就可以移除模型的解码器部分,仅留下编码器模型。然后,该模型可用于将输入序列编码为固定长度的向量。
然后,所得到的向量可以用于各种应用中,尤其是作为序列的压缩表示,作为另一个监督学习模型的输入。
LSTM 自编码器的早期应用
LSTM Autoencoder 的早期和广泛引用的应用之一是在 2015 年的论文“使用 LSTM 的视频表示的无监督学习”。
LSTM 自编码器模型 取自“使用 LSTM 的无监督学习视频表示”
在论文中,Nitish Srivastava 等人。将 LSTM Autoencoder 描述为编解码器 LSTM 的扩展或应用。
他们使用具有视频输入数据的模型来重建视频帧的序列以及预测视频帧,这两者都被描述为无监督学习任务。
模型的输入是一系列向量(图像块或特征)。编码器 LSTM 以此顺序读取。在读取了最后一个输入之后,解码器 LSTM 接管并输出对目标序列的预测。
- 使用 LSTM 的视频表示的无监督学习,2015。
作者不仅仅是直接使用模型,而是探索一些有趣的架构选择,这些选择可能有助于为模型的未来应用提供信息。
他们设计模型的方式是以相反的顺序重新创建视频帧的目标序列,声称它使得模型解决的优化问题更容易处理。
目标序列与输入序列相同,但顺序相反。反转目标序列使得优化更容易,因为模型可以通过查看低范围相关性来实现。
- 使用 LSTM 的视频表示的无监督学习,2015。
他们还探讨了训练解码器模型的两种方法,特别是在解码器生成的先前输出中调节的版本,以及没有任何这种调节的另一种方法。
解码器可以是两种 - 有条件的或无条件的。条件解码器接收最后生成的输出帧作为输入[...]。无条件解码器不接收该输入。
- 使用 LSTM 的视频表示的无监督学习,2015。
还研究了更精细的自编码器模型,其中两个解码器模型用于一个编码器:一个用于预测序列中的下一帧,一个用于重建序列中的帧,称为复合模型。
...重建输入和预测未来可以组合起来创建一个复合[...]。在这里,编码器 LSTM 被要求提出一种状态,我们既可以预测接下来的几帧,也可以重建输入。
- 使用 LSTM 的视频表示的无监督学习,2015。
具有两个解码器的 LSTM 自编码器模型 取自“使用 LSTM 的视频表示的无监督学习”
模型以多种方式进行评估,包括使用编码器来播种分类器。看来,不是使用编码器的输出作为分类输入,而是选择直接使用编码器模型的权重为独立的 LSTM 分类器播种。鉴于实现的复杂性,这是令人惊讶的。
我们使用编码器 LSTM 从该模型中学习的权重初始化 LSTM 分类器。
- 使用 LSTM 的视频表示的无监督学习,2015。
发现在解码器上没有调节的复合模型在他们的实验中表现最佳。
表现最佳的模型是组合自编码器和未来预测器的复合模型。条件变量在微调后的分类准确度方面没有给出任何显着的改进,但是它们确实给出了略低的预测误差。
- 使用 LSTM 的视频表示的无监督学习,2015。
已经演示了 LSTM 自编码器的许多其他应用,尤其是文本序列,音频数据和时间序列。
如何在 Keras 中创建 LSTM 自编码器
在 Keras 中创建 LSTM 自编码器可以通过实现编解码器 LSTM 架构并配置模型来重新创建输入序列来实现。
让我们看几个例子来说明这一点。
重建 LSTM 自编码器
最简单的 LSTM 自编码器是学习重建每个输入序列的自编码器。
对于这些演示,我们将使用九个时间步骤和一个特征的一个样本的数据集:
[0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
我们可以通过定义序列并将其重新整形为[_ 样本,时间步长,特征 _]的首选形状来开始。
# define input sequence
sequence = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
# reshape input into [samples, timesteps, features]
n_in = len(sequence)
sequence = sequence.reshape((1, n_in, 1))
接下来,我们可以定义编解码器 LSTM 架构,该架构期望输入序列具有九个时间步长和一个特征,并输出具有九个时间步长和一个特征的序列。
# define model
model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
model.add(RepeatVector(n_in))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(optimizer='adam', loss='mse')
接下来,我们可以将模型拟合到我们设计的数据集上。
# fit model
model.fit(sequence, sequence, epochs=300, verbose=0)
下面列出了完整的示例。
模型的配置,例如单元数和训练时期,完全是任意的。
# lstm autoencoder recreate sequence
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.utils import plot_model
# define input sequence
sequence = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
# reshape input into [samples, timesteps, features]
n_in = len(sequence)
sequence = sequence.reshape((1, n_in, 1))
# define model
model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
model.add(RepeatVector(n_in))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(sequence, sequence, epochs=300, verbose=0)
plot_model(model, show_shapes=True, to_file='reconstruct_lstm_autoencoder.png')
# demonstrate recreation
yhat = model.predict(sequence, verbose=0)
print(yhat[0,:,0])
运行该示例适合自编码器并打印重建的输入序列。
结果足够接近,非常小的舍入误差。
[0.10398503 0.20047213 0.29905337 0.3989646 0.4994707 0.60005534
0.70039135 0.80031013 0.8997728 ]
创建架构图以供参考。
用于序列重建的 LSTM 自编码器
预测 LSTM 自编码器
我们可以修改重建 LSTM Autoencoder 来预测序列中的下一步。
在我们的小设计问题的情况下,我们期望输出是序列:
[0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]
这意味着模型将期望每个输入序列具有九个时间步长,并且输出序列具有八个时间步长。
# reshape input into [samples, timesteps, features]
n_in = len(seq_in)
seq_in = seq_in.reshape((1, n_in, 1))
# prepare output sequence
seq_out = seq_in[:, 1:, :]
n_out = n_in - 1
下面列出了完整的示例。
# lstm autoencoder predict sequence
from numpy import array
from keras.models import Sequential
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.utils import plot_model
# define input sequence
seq_in = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
# reshape input into [samples, timesteps, features]
n_in = len(seq_in)
seq_in = seq_in.reshape((1, n_in, 1))
# prepare output sequence
seq_out = seq_in[:, 1:, :]
n_out = n_in - 1
# define model
model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
model.add(RepeatVector(n_out))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(optimizer='adam', loss='mse')
plot_model(model, show_shapes=True, to_file='predict_lstm_autoencoder.png')
# fit model
model.fit(seq_in, seq_out, epochs=300, verbose=0)
# demonstrate prediction
yhat = model.predict(seq_in, verbose=0)
print(yhat[0,:,0])
运行该示例将打印输出序列,该序列预测每个输入时间步的下一个时间步。
我们可以看到模型是准确的,除了一些小的舍入误差。
[0.1657285 0.28903174 0.40304852 0.5096578 0.6104322 0.70671254
0.7997272 0.8904342 ]
创建架构图以供参考。
用于序列预测的 LSTM 自编码器
复合 LSTM 自编码器
最后,我们可以创建一个复合 LSTM 自编码器,它具有一个编码器和两个解码器,一个用于重建,另一个用于预测。
我们可以使用功能 API 在 Keras 中实现这个多输出模型。您可以在此帖子中了解有关功能 API 的更多信息:
首先,定义编码器。
# define encoder
visible = Input(shape=(n_in,1))
encoder = LSTM(100, activation='relu')(visible)
然后是第一个用于重建的解码器。
# define reconstruct decoder
decoder1 = RepeatVector(n_in)(encoder)
decoder1 = LSTM(100, activation='relu', return_sequences=True)(decoder1)
decoder1 = TimeDistributed(Dense(1))(decoder1)
然后是用于预测的第二个解码器。
# define predict decoder
decoder2 = RepeatVector(n_out)(encoder)
decoder2 = LSTM(100, activation='relu', return_sequences=True)(decoder2)
decoder2 = TimeDistributed(Dense(1))(decoder2)
然后我们将整个模型联系在一起。
# tie it together
model = Model(inputs=visible, outputs=[decoder1, decoder2])
下面列出了完整的示例。
# lstm autoencoder reconstruct and predict sequence
from numpy import array
from keras.models import Model
from keras.layers import Input
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.utils import plot_model
# define input sequence
seq_in = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
# reshape input into [samples, timesteps, features]
n_in = len(seq_in)
seq_in = seq_in.reshape((1, n_in, 1))
# prepare output sequence
seq_out = seq_in[:, 1:, :]
n_out = n_in - 1
# define encoder
visible = Input(shape=(n_in,1))
encoder = LSTM(100, activation='relu')(visible)
# define reconstruct decoder
decoder1 = RepeatVector(n_in)(encoder)
decoder1 = LSTM(100, activation='relu', return_sequences=True)(decoder1)
decoder1 = TimeDistributed(Dense(1))(decoder1)
# define predict decoder
decoder2 = RepeatVector(n_out)(encoder)
decoder2 = LSTM(100, activation='relu', return_sequences=True)(decoder2)
decoder2 = TimeDistributed(Dense(1))(decoder2)
# tie it together
model = Model(inputs=visible, outputs=[decoder1, decoder2])
model.compile(optimizer='adam', loss='mse')
plot_model(model, show_shapes=True, to_file='composite_lstm_autoencoder.png')
# fit model
model.fit(seq_in, [seq_in,seq_out], epochs=300, verbose=0)
# demonstrate prediction
yhat = model.predict(seq_in, verbose=0)
print(yhat)
运行该示例,使用两个解码器重建并预测输出序列。
[array([[[0.10736275],
[0.20335874],
[0.30020815],
[0.3983948 ],
[0.4985725 ],
[0.5998295 ],
[0.700336 ,
[0.8001949 ],
[0.89984304]]], dtype=float32),
array([[[0.16298929],
[0.28785267],
[0.4030449 ],
[0.5104638 ],
[0.61162543],
[0.70776784],
[0.79992455],
[0.8889787 ]]], dtype=float32)]
创建架构图以供参考。
用于序列重建和预测的复合 LSTM 自编码器
保留独立 LSTM 编码器
无论选择哪种方法(重建,预测或复合),一旦自适应编码器已经适合,就可以移除解码器并且可以将编码器保持为独立模型。
然后,编码器可用于将输入序列变换为固定长度的编码向量。
我们可以通过创建一个与原始模型具有相同输入的新模型,并在RepeatVector层之前直接从编码器模型的末尾输出。
# connect the encoder LSTM as the output layer
model = Model(inputs=model.inputs, outputs=model.layers[0].output)
下面列出了使用重建 LSTM 自编码器执行此操作的完整示例。
# lstm autoencoder recreate sequence
from numpy import array
from keras.models import Sequential
from keras.models import Model
from keras.layers import LSTM
from keras.layers import Dense
from keras.layers import RepeatVector
from keras.layers import TimeDistributed
from keras.utils import plot_model
# define input sequence
sequence = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9])
# reshape input into [samples, timesteps, features]
n_in = len(sequence)
sequence = sequence.reshape((1, n_in, 1))
# define model
model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_in,1)))
model.add(RepeatVector(n_in))
model.add(LSTM(100, activation='relu', return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(optimizer='adam', loss='mse')
# fit model
model.fit(sequence, sequence, epochs=300, verbose=0)
# connect the encoder LSTM as the output layer
model = Model(inputs=model.inputs, outputs=model.layers[0].output)
plot_model(model, show_shapes=True, to_file='lstm_encoder.png')
# get the feature vector for the input sequence
yhat = model.predict(sequence)
print(yhat.shape)
print(yhat)
运行该示例将创建一个独立的编码器模型,可以使用或保存以供以后使用。
我们通过预测序列并返回编码器的 100 个元素输出来演示编码器。
显然,这对于我们微小的九步输入序列来说太过分了。
[[0.03625513 0.04107533 0.10737951 0.02468692 0.06771207 0.
0.0696108 0\. 0\. 0.0688471 0\. 0.
0\. 0\. 0\. 0\. 0\. 0.03871286
0\. 0\. 0.05252134 0\. 0.07473809 0.02688836
0\. 0\. 0\. 0\. 0\. 0.0460703
0\. 0\. 0.05190025 0\. 0\. 0.11807001
0\. 0\. 0\. 0\. 0\. 0.
0\. 0.14514188 0\. 0\. 0\. 0.
0.02029926 0.02952124 0\. 0\. 0\. 0.
0\. 0.08357017 0.08418129 0\. 0\. 0.
0\. 0\. 0.09802645 0.07694854 0\. 0.03605933
0\. 0.06378153 0\. 0.05267526 0.02744672 0.
0.06623861 0\. 0\. 0\. 0.08133873 0.09208347
0.03379713 0\. 0\. 0\. 0.07517676 0.08870222
0\. 0\. 0\. 0\. 0.03976351 0.09128518
0.08123557 0\. 0.08983088 0.0886112 0\. 0.03840019
0.00616016 0.0620428 0\. 0\. ]
创建架构图以供参考。
独立编码器 LSTM 模型
进一步阅读
如果您希望深入了解,本节将提供有关该主题的更多资源。
- 用序列做出预测
- 编解码器长短期记忆网络
- 自编码器,维基百科
- 使用 LSTM 进行视频表示的无监督学习,ArXiv 2015。
- 使用 LSTM 进行视频表示的无监督学习,PMLR,PDF,2015。
- 使用 LSTM ,GitHub 存储库进行视频表示的无监督学习。
- 在 Keras 建立自编码器,2016 年。
- 如何使用 Keras 功能 API 进行深度学习
摘要
在这篇文章中,您发现了 LSTM Autoencoder 模型以及如何使用 Keras 在 Python 中实现它。
具体来说,你学到了:
- 自编码器是一种自我监督的学习模型,可以学习输入数据的压缩表示。
- LSTM 自编码器可以学习序列数据的压缩表示,并且已经用于视频,文本,音频和时间序列序列数据。
- 如何使用 Keras 深度学习库在 Python 中开发 LSTM Autoencoder 模型。
你有任何问题吗? 在下面的评论中提出您的问题,我会尽力回答。
如何在 Keras 中用长短期记忆模型做出预测
原文:
machinelearningmastery.com/make-predictions-long-short-term-memory-models-keras/
开发 LSTM 模型的目标是可以用于序列预测问题的最终模型。
在这篇文章中,您将了解如何最终确定模型并使用它来预测新数据。
完成这篇文章后,你会知道:
- 如何训练最终的 LSTM 模型。
- 如何保存最终的 LSTM 模型,然后再次加载它。
- 如何预测新数据。
让我们开始吧。
如何使用 Keras 用长期短期记忆模型做出预测 Damon jah ,保留一些权利。
步骤 1.训练最终模型
什么是最终的 LSTM 模型?
最终的 LSTM 模型是用于对新数据做出预测的模型。
也就是说,给定输入数据的新示例,您希望使用该模型来预测预期输出。这可以是分类(分配标签)或回归(实际值)。
序列预测项目的目标是获得最佳的最终模型,其中“最佳”定义为:
- 数据:您提供的历史数据。
- 时间:你必须在项目上花费的时间。
- 程序:数据准备步骤,算法或算法,以及所选的算法配置。
在项目中,您可以收集数据,花费时间,发现数据准备过程,要使用的算法以及如何配置它。
最终的模型是这个过程的顶峰,你寻求的目的是为了开始实际做出预测。
没有完美的模型这样的东西。只有你能发现的最好的模型。
如何敲定 LSTM 模型?
您可以通过在所有数据上应用所选的 LSTM 架构和配置来最终确定模型。
没有训练和测试拆分,也没有交叉验证折叠。将所有数据重新组合到一个大型训练数据集中,以适合您的模型。
而已。
使用最终模型,您可以:
- 保存模型以供以后或操作使用。
- 加载模型并对新数据做出预测。
有关训练最终模型的更多信息,请参阅帖子:
第 2 步。保存最终模型
Keras 提供了一个 API,允许您将模型保存到文件中。
该模型以 HDF5 文件格式保存,可有效地在磁盘上存储大量数字。您需要确认已安装 h5py Python 库。它可以安装如下:
sudo pip install h5py
您可以使用模型上的 save()函数将适合的 Keras 模型保存到文件中。
例如:
# define model
model = Sequential()
model.add(LSTM(...))
# compile model
model.compile(...)
# fit model
model.fit(...)
# save model to single file
model.save('lstm_model.h5')
此单个文件将包含模型架构和权重。它还包括所选损失和优化算法的规范,以便您可以恢复训练。
可以使用 load_model()函数再次加载模型(来自不同 Python 会话中的不同脚本)。
from keras.models import load_model
# load model from single file
model = load_model('lstm_model.h5')
# make predictions
yhat = model.predict(X, verbose=0)
print(yhat)
下面是一个完整的 LSTM 模型拟合示例,将其保存到单个文件中,然后再次加载。尽管模型的加载位于同一脚本中,但此部分可以从另一个 Python 会话中的另一个脚本运行。运行该示例将模型保存到文件 lstm_model.h5。
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from numpy import array
from keras.models import load_model
# return training data
def get_train():
seq = [[0.0, 0.1], [0.1, 0.2], [0.2, 0.3], [0.3, 0.4], [0.4, 0.5]]
seq = array(seq)
X, y = seq[:, 0], seq[:, 1]
X = X.reshape((len(X), 1, 1))
return X, y
# define model
model = Sequential()
model.add(LSTM(10, input_shape=(1,1)))
model.add(Dense(1, activation='linear'))
# compile model
model.compile(loss='mse', optimizer='adam')
# fit model
X,y = get_train()
model.fit(X, y, epochs=300, shuffle=False, verbose=0)
# save model to single file
model.save('lstm_model.h5')
# snip...
# later, perhaps run from another script
# load model from single file
model = load_model('lstm_model.h5')
# make predictions
yhat = model.predict(X, verbose=0)
print(yhat)
有关保存和加载 Keras 模型的更多信息,请参阅帖子:
第 3 步。对新数据做出预测
在完成模型并将其保存到文件后,您可以加载它并使用它来做出预测。
For example:
- 在序列回归问题上,这可能是下一时间步的实际值的预测。
- 在序列分类问题上,这可能是给定输入序列的类结果。
或者它可能是基于序列预测问题细节的任何其他变化。您希望给出输入序列(X)的模型(yhat)的结果,其中序列(y)的真实结果当前是未知的。
您可能有兴趣在生产环境中做出预测,作为接口的后端或手动做出预测。这实际上取决于项目的目标。
在拟合最终模型之前对训练数据执行的任何数据准备也必须在做出预测之前应用于任何新数据。
预测是容易的部分。
它涉及获取准备好的输入数据(X)并在加载的模型上调用 Keras 预测方法之一。
请记住,做出预测(X)的输入仅包括做出预测所需的输入序列数据,而不是所有先前的训练数据。在预测一个序列中的下一个值的情况下,输入序列将是 1 个样本,具有固定数量的时间步长和在定义和拟合模型时使用的特征。
例如,可以通过调用模型上的 predict()函数来对输出层的激活函数的形状和比例进行原始预测:
X = ...
model = ...
yhat = model.predict(X)
可以通过调用模型上的 predict_classes()函数来预测类索引。
X = ...
model = ...
yhat = model.predict_classes(X)
可以通过调用模型上的 predict_proba()函数来预测概率。
X = ...
model = ...
yhat = model.predict_proba(X)
有关 Keras 模型生命周期的更多信息,请参阅帖子:
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
帖子
API
摘要
在这篇文章中,您了解了如何最终确定模型并使用它来预测新数据。
具体来说,你学到了:
- 如何训练最终的 LSTM 模型。
- 如何保存最终的 LSTM 模型,然后再次加载它。
- 如何预测新数据。
你有任何问题吗? 在下面的评论中提出您的问题,我会尽力回答。
在 Python 中使用长短期记忆网络演示记忆
原文:
machinelearningmastery.com/memory-in-a-long-short-term-memory-network/
长短期记忆(LSTM)网络是一种能够学习长序列的循环神经网络。
这使它们与没有记忆的常规多层神经网络区分开来,并且只能学习输入和输出模式之间的映射。
重要的是要理解像 LSTM 这样的复杂神经网络在小型设计问题上的能力,因为这种理解将帮助您将网络扩展到大型甚至是非常大的问题。
在本教程中,您将发现 LSTM 记忆和回忆的功能。
完成本教程后,您将了解:
- 如何定义一个小序列预测问题,只有像 LSTM 这样的 RNN 可以使用记忆来解决。
- 如何转换问题表示,使其适合 LSTM 学习。
- 如何设计 LSTM 来正确解决问题。
让我们开始吧。
在长期短期记忆网络中的记忆演示 照片由 crazlei ,保留一些权利。
环境
本教程假设您使用带有 TensorFlow 或 Theano 后端的 SciPy,Keras 2.0 或更高版本的 Python 2 或 3 环境。
有关设置 Python 环境的帮助,请参阅帖子:
序列问题描述
问题是一次预测一个序列的值。
给定序列中的一个值,模型必须预测序列中的下一个值。例如,给定值“0”作为输入,模型必须预测值“1”。
模型必须学习和正确预测有两种不同的序列。
皱纹是两个序列之间存在冲突的信息,并且模型必须知道每个一步预测的上下文(例如,它当前正在预测的序列),以便正确地预测每个完整序列。
这种皱纹对于防止模型记忆每个序列中的每个单步输入 - 输出值对非常重要,因为序列未知模型可能倾向于这样做。
要学习的两个序列如下:
- 3,0,1,2,3
- 4,0,1,2,4
我们可以看到序列的第一个值重复作为序列的最后一个值。这是指示器为模型提供关于它正在处理的序列的上下文。
冲突是从每个序列中的第二个项目到最后一个项目的过渡。在序列 1 中,给出“2”作为输入并且必须预测“3”,而在序列 2 中,给出“2”作为输入并且必须预测“4”。
这是多层感知机和其他非循环神经网络无法学习的问题。
这是“_ 实验 2_ ”的简化版本,用于证明 Hochreiter 和 Schmidhuber 1997 年论文长期短期记忆( PDF )中的 LSTM 长期记忆能力。
问题表征
本节分为 3 部分;他们是:
- 单热编码
- 输入输出对
- 重塑数据
单热编码
我们将使用单热编码来表示 LSTM 的学习问题。
也就是说,每个输入和输出值将表示为具有 5 个元素的二进制向量,因为问题的字母表是 5 个唯一值。
例如,[0,1,2,3,4]的 5 个值表示为以下 5 个二进制向量:
0: [1, 0, 0, 0, 0]
1: [0, 1, 0, 0, 0]
2: [0, 0, 1, 0, 0]
3: [0, 0, 0, 1, 0]
4: [0, 0, 0, 0, 1]
我们可以使用一个简单的函数来执行此操作,该函数将获取序列并返回序列中每个值的二进制向量列表。下面的函数 encode() 实现了这种行为。
# binary encode an input pattern, return a list of binary vectors
def encode(pattern, n_unique):
encoded = list()
for value in pattern:
row = [0.0 for x in range(n_unique)]
row[value] = 1.0
encoded.append(row)
return encoded
我们可以在第一个序列上测试它并打印结果的二进制向量列表。下面列出了完整的示例。
# binary encode an input pattern, return a list of binary vectors
def encode(pattern, n_unique):
encoded = list()
for value in pattern:
row = [0.0 for x in range(n_unique)]
row[value] = 1.0
encoded.append(row)
return encoded
seq1 = [3, 0, 1, 2, 3]
encoded = encode(seq1, 5)
for vector in encoded:
print(vector)
运行该示例打印每个二进制向量。请注意,我们使用浮点值 0.0 和 1.0,因为它们将用作模型的输入和输出。
[0.0, 0.0, 0.0, 1.0, 0.0]
[1.0, 0.0, 0.0, 0.0, 0.0]
[0.0, 1.0, 0.0, 0.0, 0.0]
[0.0, 0.0, 1.0, 0.0, 0.0]
[0.0, 0.0, 0.0, 1.0, 0.0]
输入输出对
下一步是将一系列编码值拆分为输入 - 输出对。
这是问题的监督学习表示,使得机器学习问题可以学习如何将输入模式(X)映射到输出模式(y)。
例如,第一个序列具有以下要学习的输入 - 输出对:
X, y
3, 0
0, 1
1, 2
2, 3
我们必须从单热编码的二进制向量中创建这些映射对,而不是原始数字。
例如,3-> 0 的第一输入 - 输出对将是:
X, y
[0, 0, 0, 1, 0] [1, 0, 0, 0, 0]
下面是一个名为 to_xy_pairs() 的函数,它将在给定编码二进制向量列表的情况下创建X和y模式的列表。
# create input/output pairs of encoded vectors, returns X, y
def to_xy_pairs(encoded):
X,y = list(),list()
for i in range(1, len(encoded)):
X.append(encoded[i-1])
y.append(encoded[i])
return X, y
我们可以将它与上面的单热编码函数放在一起,并打印第一个序列的编码输入和输出对。
# binary encode an input pattern, return a list of binary vectors
def encode(pattern, n_unique):
encoded = list()
for value in pattern:
row = [0.0 for x in range(n_unique)]
row[value] = 1.0
encoded.append(row)
return encoded
# create input/output pairs of encoded vectors, returns X, y
def to_xy_pairs(encoded):
X,y = list(),list()
for i in range(1, len(encoded)):
X.append(encoded[i-1])
y.append(encoded[i])
return X, y
seq1 = [3, 0, 1, 2, 3]
encoded = encode(seq1, 5)
X, y = to_xy_pairs(encoded)
for i in range(len(X)):
print(X[i], y[i])
运行该示例将打印序列中每个步骤的输入和输出对。
[0.0, 0.0, 0.0, 1.0, 0.0] [1.0, 0.0, 0.0, 0.0, 0.0]
[1.0, 0.0, 0.0, 0.0, 0.0] [0.0, 1.0, 0.0, 0.0, 0.0]
[0.0, 1.0, 0.0, 0.0, 0.0] [0.0, 0.0, 1.0, 0.0, 0.0]
[0.0, 0.0, 1.0, 0.0, 0.0] [0.0, 0.0, 0.0, 1.0, 0.0]
重塑数据
最后一步是重新整形数据,以便 LSTM 网络可以直接使用它。
Keras LSTM 期望输入模式(X)为具有[_ 样本,时间步长,特征 _]维度的三维 NumPy 数组。
在一个输入数据序列的情况下,维度将是[4,1,5],因为我们有 4 行数据,每行有 1 个时间步长,每行有 5 列。
我们可以从 X 模式列表中创建 2D NumPy 数组,然后将其重新整形为所需的 3D 格式。例如:
df = DataFrame(X)
values = df.values
array = values.reshape(4, 1, 5)
我们还必须将输出模式列表(y)转换为 2D NumPy 数组。
下面是一个名为 to_lstm_dataset() 的函数,它将序列作为输入和序列字母表的大小,并返回准备使用的X和y数据集与 LSTM。它在重新整形数据之前执行所需的序列转换为单热编码和输入输出对。
# convert sequence to x/y pairs ready for use with an LSTM
def to_lstm_dataset(sequence, n_unique):
# one hot encode
encoded = encode(sequence, n_unique)
# convert to in/out patterns
X,y = to_xy_pairs(encoded)
# convert to LSTM friendly format
dfX, dfy = DataFrame(X), DataFrame(y)
lstmX = dfX.values
lstmX = lstmX.reshape(lstmX.shape[0], 1, lstmX.shape[1])
lstmY = dfy.values
return lstmX, lstmY
可以使用以下每个序列调用此函数:
seq1 = [3, 0, 1, 2, 3]
seq2 = [4, 0, 1, 2, 4]
n_unique = len(set(seq1 + seq2))
seq1X, seq1Y = to_lstm_dataset(seq1, n_unique)
seq2X, seq2Y = to_lstm_dataset(seq2, n_unique)
我们现在拥有为 LSTM 准备数据的所有部分。
使用 LSTM 学习序列
在本节中,我们将定义 LSTM 以学习输入序列。
本节分为 4 个部分:
- LSTM 配置
- LSTM 训练
- LSTM 评估
- LSTM 完整示例
LSTM 配置
我们希望 LSTM 进行一步预测,我们已经在数据集的格式和形状中定义了这些预测。我们还希望在每个时间步之后更新 LSTM 错误,这意味着我们需要使用批量大小的一个。
默认情况下,Keras LSTM 在批次之间不具有状态。我们可以通过将 LSTM 层上的 _ 有状态 _ 参数设置为True并手动管理训练时期来确保 LSTM 的内部状态在每个序列之后被重置,从而使它们成为有状态。
我们必须使用batch_input_shape参数定义批次的形状,其中 3 维[_ 批量大小,时间步长和特征 _]分别为 1,1 和 5。
网络拓扑将配置一个具有 20 个单元的隐藏 LSTM 层和一个具有 5 个输出的普通密集层,用于输出模式中的每个 5 列。由于二进制输出,将在输出层上使用 sigmoid(逻辑)激活函数,并且将在 LSTM 层上使用默认的 tanh(双曲正切)激活函数。
由于二进制输出,因此在拟合网络时将优化对数(交叉熵)损失函数,并且将使用有效的 ADAM 优化算法与所有默认参数。
下面列出了为此问题定义 LSTM 网络的 Keras 代码。
model = Sequential()
model.add(LSTM(20, batch_input_shape=(1, 1, 5), stateful=True))
model.add(Dense(5, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
LSTM 训练
我们必须一次手动拟合模型一个时期。
在一个时期内,我们可以在每个序列上拟合模型,确保在每个序列之后重置状态。
鉴于问题的简单性,该模型不需要长时间训练;在这种情况下,只需要 250 个迭代。
下面是一个示例,说明模型如何适应所有时期的每个序列。
# train LSTM
for i in range(250):
model.fit(seq1X, seq1Y, epochs=1, batch_size=1, verbose=1, shuffle=False)
model.reset_states()
model.fit(seq2X, seq2Y, epochs=1, batch_size=1, verbose=0, shuffle=False)
model.reset_states()
我希望在安装网络时能看到关于损失函数的一些反馈,因此从其中一个序列开启详细输出,而不是另一个序列。
LSTM 评估
接下来,我们可以通过预测学习序列的每个步骤来评估拟合模型。
我们可以通过预测每个序列的输出来做到这一点。
predict_classes() 函数可以用于直接预测类的 LSTM 模型。它通过在输出二进制向量上执行 argmax() 并返回具有最大输出的预测列的索引来完成此操作。输出索引完美地映射到序列中使用的整数(通过上面的仔细设计)。下面列出了做出预测的示例:
result = model.predict_classes(seq1X, batch_size=1, verbose=0)
我们可以做出预测,然后在输入模式的上下文和序列的每个步骤的预期输出模式中打印结果。
LSTM 完整示例
我们现在可以将整个教程结合在一起。
完整的代码清单如下。
首先,准备数据,然后拟合模型并打印两个序列的预测。
from pandas import DataFrame
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# binary encode an input pattern, return a list of binary vectors
def encode(pattern, n_unique):
encoded = list()
for value in pattern:
row = [0.0 for x in range(n_unique)]
row[value] = 1.0
encoded.append(row)
return encoded
# create input/output pairs of encoded vectors, returns X, y
def to_xy_pairs(encoded):
X,y = list(),list()
for i in range(1, len(encoded)):
X.append(encoded[i-1])
y.append(encoded[i])
return X, y
# convert sequence to x/y pairs ready for use with an LSTM
def to_lstm_dataset(sequence, n_unique):
# one hot encode
encoded = encode(sequence, n_unique)
# convert to in/out patterns
X,y = to_xy_pairs(encoded)
# convert to LSTM friendly format
dfX, dfy = DataFrame(X), DataFrame(y)
lstmX = dfX.values
lstmX = lstmX.reshape(lstmX.shape[0], 1, lstmX.shape[1])
lstmY = dfy.values
return lstmX, lstmY
# define sequences
seq1 = [3, 0, 1, 2, 3]
seq2 = [4, 0, 1, 2, 4]
# convert sequences into required data format
n_unique = len(set(seq1 + seq2))
seq1X, seq1Y = to_lstm_dataset(seq1, n_unique)
seq2X, seq2Y = to_lstm_dataset(seq2, n_unique)
# define LSTM configuration
n_neurons = 20
n_batch = 1
n_epoch = 250
n_features = n_unique
# create LSTM
model = Sequential()
model.add(LSTM(n_neurons, batch_input_shape=(n_batch, 1, n_features), stateful=True))
model.add(Dense(n_unique, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='adam')
# train LSTM
for i in range(n_epoch):
model.fit(seq1X, seq1Y, epochs=1, batch_size=n_batch, verbose=1, shuffle=False)
model.reset_states()
model.fit(seq2X, seq2Y, epochs=1, batch_size=n_batch, verbose=0, shuffle=False)
model.reset_states()
# test LSTM on sequence 1
print('Sequence 1')
result = model.predict_classes(seq1X, batch_size=n_batch, verbose=0)
model.reset_states()
for i in range(len(result)):
print('X=%.1f y=%.1f, yhat=%.1f' % (seq1[i], seq1[i+1], result[i]))
# test LSTM on sequence 2
print('Sequence 2')
result = model.predict_classes(seq2X, batch_size=n_batch, verbose=0)
model.reset_states()
for i in range(len(result)):
print('X=%.1f y=%.1f, yhat=%.1f' % (seq2[i], seq2[i+1], result[i]))
运行该示例提供关于模型在每个时期的第一序列上的损失的反馈。
在运行结束时,每个序列都在预测的上下文中打印。
...
4/4 [==============================] - 0s - loss: 0.0930
Epoch 1/1
4/4 [==============================] - 0s - loss: 0.0927
Epoch 1/1
4/4 [==============================] - 0s - loss: 0.0925
Sequence 1
X=3.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=3.0, yhat=3.0
Sequence 2
X=4.0 y=0.0, yhat=0.0
X=0.0 y=1.0, yhat=1.0
X=1.0 y=2.0, yhat=2.0
X=2.0 y=4.0, yhat=4.0
结果显示了两件重要的事情:
- LSTM 一次一步地正确学习每个序列。
- LSTM 使用每个序列的上下文来正确地解析冲突的输入对。
本质上,LSTM 能够记住 3 个时间步前序列开始处的输入模式,以正确预测序列中的最后一个值。
这种记忆和 LSTM 能够及时关联观测的能力是使 LSTM 如此强大以及它们如此广泛使用的关键能力。
虽然这个例子很简单,但 LSTM 能够在 100 秒甚至 1000 秒的时间步长中展示出同样的能力。
扩展
本节列出了本教程中示例扩展的思路。
- 调整。经过一些试验和错误后,选择了 LSTM(时期,单位等)的配置。更简单的配置可能会在此问题上获得相同的结果。需要搜索一些参数。
- 任意字母。 5 个整数的字母表是任意选择的。这可以更改为其他符号和更大的字母。
- 长序列。本例中使用的序列非常短。 LSTM 能够在更长的 100s 和 1000s 时间步长序列上展示相同的能力。
- 随机序列。本教程中使用的序列呈线性增长。可以创建新的随机值序列,允许 LSTM 设计一个通用解决方案,而不是专门用于本教程中使用的两个序列的解决方案。
- 批量学习。每个时间步后都对 LSTM 进行了更新。探索使用批量更新,看看这是否会改善学习。
- Shuffle Epoch 。序列在训练期间的每个时期以相同的顺序显示,并且在评估期间再次显示。随机化序列的顺序,使得序列 1 和 2 适合一个时期,这可以改善模型对具有相同字母表的新看不见的序列的概括。
你有没有探索过这些扩展? 在下面的评论中分享您的结果。我很想看看你想出了什么。
进一步阅读
我强烈建议阅读 Hochreiter 和 Schmidhuber 的 1997 年原始 LSTM 论文;这很棒。
摘要
在本教程中,您发现了 LSTM 能够记住多个时间步的关键功能。
具体来说,你学到了:
- 如何定义一个小序列预测问题,只有像 LSTM 这样的 RNN 可以使用记忆来解决。
- 如何转换问题表示,使其适合 LSTM 学习。
- 如何设计 LSTM 来正确解决问题。
你有任何问题吗? 在下面的评论中发表您的问题,我会尽力回答。