赞
踩
本文代码运行环境:
LSTM 01:理解LSTM网络及训练方法
LSTM 02:如何为LSTM准备数据
LSTM 03:如何使用Keras编写LSTM
LSTM 04:4种序列预测模型及Keras实现
LSTM 05:Keras实现多层LSTM进行序列预测
LSTM 06:Keras实现CNN-LSTM模型
LSTM 07:Keras实现Encoder-Decoder LSTM
LSTM 08:超详细LSTM调参指南
第一步是定义网络。在Keras中,神经网络被定义为一系列的层(Layer)。这些层的容器是 Sequential
类。第一步是创建 Sequential
类的实例。然后,按照顺序添加所需要的层。LSTM递归层称为 LSTM()
。通常紧跟在 LSTM
层之后并用于输出预测的全连接层称为 Dense()
。
例如,定义一个包含2个记忆单元的LSTM层,然后定义一个包含1个神经元的全连接输出层:
model = Sequential()
model.add(LSTM(2))
model.add(Dense(1))
也可以通过创建一个层数组并将其传递给 Sequential
构造器:
layers = [LSTM(2), Dense(1)]
model = Sequential(layers)
网络中的第一个隐藏层必须定义预期的输入数量,例如输入层的形状。输入必须是三维的,其shape为 [样本数量, 时间步, 特征]
。
假设数据是作为NumPy数组加载的,那么可以使用NumPy中的 reshape
函数将1D或2D数据集转换为3D数据集。假设在一个NumPy数组中有两列输入数据(X)。我们可以将这两个列视为两个时间步,并重塑形状:
data = data.reshape((data.shape[0], data.shape[1], 1))
如果要使二维数据中的列成为一个时间步长的形状,可以按以下方式对其进行重塑:
data = data.reshape((data.shape[0], 1, data.shape[1]))
可以指定输入形状参数,该参数需要一个包含时间步数和特征数的元组。例如,如果一个单变量序列有两个时间步和一个特征,每行有两个滞后观测值,则可以指定如下:
model = Sequential()
model.add(LSTM(5, input_shape=(2,1)))
model.add(Dense(1))
LSTM层的 input_shape
参数无需指定样本数,因为默认推断为batchsize的大小。
把一个序列模型想象成一条管道,一端输入原始数据,另一端输出预测。这是Keras中一个有用的容器,因为传统上与层相关联的关注点也可以作为单独的层拆分和添加,清楚地显示了它们在数据从输入到预测的转换中的作用。例如,可以提取转换来自层中每个神经元的总和信号的激活函数,并将其作为一个类似层的对象添加到序列中,称为 Activation。
model = Sequential()
model.add(LSTM(5, input_shape=(2,1)))
model.add(Dense(1))
model.add(Activation( sigmoid ))
激活函数的选择对于输出层是最重要的,因为它将定义预测将采用的格式。例如,下面是一些常见的预测建模问题类型以及可以在输出层中使用的结构和标准激活函数:
**1. Regression: Linear activation function, or linear, and the number of neurons matching the number of outputs. This is the default activation function used for neurons in the Dense layer.
编译为网络的预计算步骤,定义模型后必须进行编译。编译是一个高效的步骤。它将我们定义的简单层序列转换为高效的矩阵转换序列,其格式将在GPU或CPU上执行,具体取决于Keras的配置方式。
编译需要指定训练参数。具体来说,用优化算法来训练网络,用损失函数来评估被优化算法最小化的网络。例如,下面是为回归型问题编译定义的模型并指定随机梯度下降(sgd)优化算法和均方误差(mse)损失函数的情况。
model.compile(optimizer= 'sgd' , loss= 'mse' )
或者,优化器可以在作为编译步骤的参数提供之前创建和配置。
algorithm = SGD(lr=0.1, momentum=0.3)
model.compile(optimizer=algorithm, loss= mse )
预测建模问题的类型对可使用的损失函数的类型施加约束。例如,以下是不同预测模型类型的一些标准损失函数:
**1. Regression: Mean Squared Error or mean squared error, mse for short.
最常见的优化算法是经典的随机梯度下降,但Keras也支持这一经典优化算法的一系列其他扩展,这些扩展在很少或没有配置的情况下都能很好地工作。也许最常用的优化算法,因为它们通常有更好的性能:
最后,除了loss函数之外,还可以指定在拟合模型时要收集的度量指标。通常,要收集的最有用的附加度量是分类问题的准确性(例如,“准确率”或简称“acc”)。要收集的度量是在度量或损失函数名数组中按名称指定的。例如:
model.compile(optimizer= sgd , loss= mean_squared_error , metrics=[ accuracy ])
编译完成之后,需要进行拟合,即训练,这意味着调整训练数据集上的权重。拟合网络需要指定训练数据,包括输入模式矩阵X和匹配输出模式数组y。使用时间反向传播算法对网络进行训练,并根据编译模型时指定的优化算法和损失函数进行优化。
反向传播算法要求对网络进行训练,以适应训练数据集中指定数量的时间段或暴露于所有序列的情况。每个epoch可以被划分成一组称为批的输入输出模式对。这定义了在一个epoch内更新权重之前网络暴露的样本数。这也是一种效率优化,确保一次不会有太多的输入样本加载到内存中。
Epoch: One pass through all samples in the training dataset and updating the network weights. LSTMs may be trained for tens, hundreds, or thousands of epochs.
Batch: A pass through a subset of samples in the training dataset after which the network weights are updated. One epoch is comprised of one or more batches.
Below are some common configurations for the batch size:
Mini-batch gradient descent with a batch size of 32 is a common configuration for LSTMs. An example of fitting a network is as follows:
model.fit(X, y, batch_size=32, epochs=100)
模型训练完成后,会返回一个history对象,该对象提供模型在训练期间的性能摘要。这包括损失和编译模型时指定的任何其他度量,记录每个epoch。可以记录、绘制和分析这些度量,以深入了解网络是过拟合还是欠拟合训练数据。
根据网络规模和训练数据的大小,训练可能需要很长的时间。默认情况下,命令行上会显示每个epoch的进度条。将verbose参数设置为2,可以只显示每个epoch的损失。将verbose设置为0,可以关闭所有输出。例如:
history = model.fit(X, y, batch_size=10, epochs=100, verbose=0)
一旦网络经过训练,就可以对其进行评估。可以根据训练数据对网络进行评估,但这并不能作为预测模型提供网络性能的有用指示,因为它已经看到了所有这些数据。我们可以在单独的数据集上评估网络的性能。这将提供对网络在预测未来未知数据方面的性能的估计。
模型评估所有测试模式的损失,以及编译模型时指定的任何其他度量,如分类精度。返回一个评估指标列表。例如,对于使用精度度量编译的模型,我们可以在新的数据集上对其进行评估:
loss, accuracy = model.evaluate(X, y)
可以将verbose参数设置为0,来屏蔽评估过程中的控制台输出信息。
loss, accuracy = model.evaluate(X, y, verbose=0)
使用模型对新数据进行预测,可以调用的 predict
函数:
predictions = model.predict(X)
预测将以网络输出层提供的格式返回。在回归问题的情况下,这些预测可以由线性激活函数直接以问题的形式提供。对于二分类问题,预测可以是第一类的概率数组,通过判别函数可以转换为1或0。对于多类分类问题,结果可以是概率数组的形式(假设一个热编码输出变量),可能需要使用 argmax
函数将其转换为单个类输出预测。或者,对于分类问题,我们可以使用 predict_classes
函数,该函数自动将预测转换为清晰的整数类值。
predictions = model.predict_classes(X)
可以将verbose参数设置为0,来屏蔽评估过程中的控制台输出信息。
predictions = model.predict(X, verbose=0)
每个LSTM存储单元都保持累积的内部状态。这种内部状态可能需要在网络训练期间和进行预测时仔细管理序列预测问题。默认情况下,网络中所有LSTM内存单元的内部状态在每次批处理后(例如,更新网络权重时)重置。这意味着批量大小的配置在以下三个方面之间施加了张力:
Keras通过将LSTM层定义为有状态层,提供了将内部状态的重置与网络权重的更新分离的灵活性。这可以通过将LSTM层上的 stateful
参数(如果为true,则批量索引I处的每个样本的最后状态将用作以下批次中索引I的样本的初始状态。)设置为True来完成。使用状态LSTM层时,还必须通过设置批输入形状参数将批大小定义为网络定义中输入形状的一部分,并且批大小必须是训练数据集中样本数的一个因子。batch_input_shape
参数需要定义为批大小、时间步长和特征的三元组。keras LSTM layer API docs
例如,我们可以定义一个有状态的LSTM,它将在一个训练数据集上进行训练,该数据集有100个样本,批处理大小为10,对于一个特征有5个时间步,如下所示:
model.add(LSTM(2, stateful=True, batch_input_shape=(10, 5, 1)))
有状态的LSTM不会在每个批处理结束时重置内部状态。可以通过调用 reset_states
函数对何时重置内部状态进行细粒度控制。例如,我们可能希望在每个纪元结束时重置内部状态,我们可以执行以下操作:
for i in range(1000):
model.fit(X, y, epochs=1, batch_input_shape=(10, 5, 1))
model.reset_states()
在进行预测时,还必须使用有状态LSTM定义中使用的相同批处理大小。
predictions = model.predict(X, batch_size=10)
在评估网络和进行预测时,LSTM层的内部状态也会累积。因此,如果使用的是有状态的LSTM,则必须在验证数据集上评估网络或进行预测后重置状态。
默认情况下,一个epoch内的样本被shuffle。当使用多层感知器神经网络时,这是一个很好的实践。如果尝试跨样本保留状态,则训练数据集中样本的顺序可能很重要,必须保留。这可以通过将 fit
函数中的 shuffle
参数设置为 False
来完成:
for i in range(1000):
model.fit(X, y, epochs=1, shuffle=False, batch_input_shape=(10, 5, 1))
model.reset_states()
为了更具体地说明这一点,下面是管理状态的三个常见示例:
很难理解如何准备序列数据以输入LSTM模型。对于如何定义LSTM模型的输入层,经常会出现混淆。对于如何将序列数据(可能是1D或2D数字矩阵)转换为LSTM输入层所需的3D格式,也存在一些混淆。在本节将介绍重塑序列数据和定义LSTM模型的输入层的两个示例。
Consider the case where you have one sequence of multiple time steps and one feature. For example, this could be a sequence of 10 values:
0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0
We can define this sequence of numbers as a NumPy array.
from numpy import array
data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
We can then use the reshape() function on the NumPy array to reshape this one-dimensional array into a three-dimensional array with 1 sample, 10 time steps and 1 feature at each time step. The reshape() function when called on an array takes one argument which is a tuple defining the new shape of the array. We cannot pass in any tuple of numbers, the reshape must evenly reorganize the data in the array.
from numpy import array
data = array([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0])
data = data.reshape((1, 10, 1))
print(data.shape)
(1, 10, 1)
This data is now ready to be used as input (X) to the LSTM with an input shape of (10,1).
model = Sequential()
model.add(LSTM(32, input_shape=(10, 1)))
...
Consider the case where you have multiple parallel series as input for your model. For example, this could be two parallel series of 10 values:
series 1: 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0
series 2: 1.0, 0.9, 0.8, 0.7, 0.6, 0.5, 0.4, 0.3, 0.2, 0.1
We can define these data as a matrix of 2 columns with 10 rows:
from numpy import array
data = array([
[0.1, 1.0],
[0.2, 0.9],
[0.3, 0.8],
[0.4, 0.7],
[0.5, 0.6],
[0.6, 0.5],
[0.7, 0.4],
[0.8, 0.3],
[0.9, 0.2],
[1.0, 0.1]])
data = data.reshape(1, 10, 2)
print(data.shape)
Running the example prints the new 3D shape of the single sample.
(1, 10, 2)
This data is now ready to be used as input (X) to the LSTM with an input shape of (10,2).
model = Sequential()
model.add(LSTM(32, input_shape=(10, 2)))
...
This section provides some resources for further reading.
参考:Jason Brownlee《 long-short-term-memory-networks-with-python》chapter 4
本文为个人学习记录,如有不易理解的地方还望读者谅解,谢谢!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。