LSTM 应该是这段时间应用非常广泛也非常火的一个算法了。关于其理论基础, 已经有非常好的文章了。 在这里, 笔者记录一下自己从一些实际例子来学习LSTM的路程。 不太监的话, 应该会有好几篇文章。 这是第一篇, 主要目的:
- 从一个简单的例子来看看LSTM是如何预测下一个输出的。
-
从这个简单的例子, 体会一下什么是Seg2Seg。
-
大概看看, 如何使用Keras来训练一个LSTM的模型。
主要参考文章:
- 在keras 上实践,通过keras例子来理解lstm循环神经网络
- Understanding Stateful LSTM Recurrent Neural Networks in Python with Keras
问题描述:学习字母表
我们经常听说LSTM可以用来训练机器人进行说话, 或者使用LSTM之类的Seg2Seg算法进行翻译。 这个命题就是一个简化版本的预测输出的命题。
假设我们有一个数据集 ABCDEFGHIJKLMNOPQRSTUVWXYZ
。 给定一个输入序列, 预测下一个字母是什么。
举个例子:
1 2 3 4 5 |
A -> B B -> C C -> D # ... |
上面的例子之中, 我们只使用了1个输入字符,预测1个输出字符。也就是我们的输入输出序列长度都是1.
注意: 我们学过字母表及其顺序, 现在是让算法学会这个顺序。 就像交小孩子学习字母表及其顺序那样。后面我们也会尝试修改->
左边的数值。
数据集准备
- 首先, 我们还是要引入相应的类库, 并设定一个随机值
123456789import numpyfrom keras.models import Sequentialfrom keras.layers import Densefrom keras.layers import LSTMfrom keras.utils import np_utils# fix random seed for reproducibilitynumpy.random.seed(7)
-
然后, 将字符映射成数字:
采用大写是为了后面好看, 小写字母就忽略不计了。
123456# define the raw datasetalphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"# create mapping of characters to integers (0-25) and the reversechar_to_int = dict((c, i) for i, c in enumerate(alphabet))int_to_char = dict((i, c) for i, c in enumerate(alphabet)) - 第三步:尝试构建出上面1:1映射的数据集
1234567891011121314151617# prepare the dataset of input to output pairs encoded as integersseq_length = 1 # 注意这里, seq_length = 1dataX = []dataY = []for i in range(0, len(alphabet) - seq_length, 1):seq_in = alphabet[i:i + seq_length]seq_out = alphabet[i + seq_length]dataX.append([char_to_int[char] for char in seq_in])dataY.append(char_to_int[seq_out])print seq_in, '->', seq_out# 上面的程序运行的结果就是:X -> Y"""A -> BB -> C..."""
-
【重要】Reshape
12345678910111213# reshape X to be [samples , time steps, features]X = numpy.reshape(dataX, (len(dataX), seq_length, 1))print(X.shape) # (25, 1, 1)print(X)"""array([[[ 0]],[[ 1]],[[ 2]],..."""一些我的理解:
samples 或者 len(dataX)
: 数据有多少行-
time_steps 或者 seq_length
: 步长, 即每一次观察,有几个观测点。 我喜欢叫他window_size
-
features 或者 1
: 特征。
举另外一个例子可能更好懂一些。
我们使用股市或者比特币价格作为输入。 每一个时刻,可能是分、时、日、周等等,会有好几种价格(成交量等其他feature暂略):
- 开盘价
- 收盘价
- 最高价
- 最低价
如果我们只使用最高价, 那么
features == 1
, 如果我们使用多种价格或者把这一时刻的成交量也加进来, 那么features == 4
从官网文档来看, 这几个参数分别为:(batch_size, timesteps, input_dim)
关于为什么要reshape成这个样子, 更详细的可以参考:
How to Reshape Input Data for Long Short-Term Memory Networks in Keras
-
正则化数据(normalize)
123# normalizeX = X / float(len(alphabet))注意: 如果是其他的数据集,也需要进行类似的操作。 比如
MinMaxScaler
-
因为字符是有限的, 相当于预测是26类之中的哪一个。 因此进行下面的处理方式:
123456789101112131415# one hot encode the output variabley = np_utils.to_categorical(dataY)"""array([[ 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.],[ 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., 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.],...."""y.shape # (25, 26)注意: LSTM算法的输入输出需要转换成数值类型。 因此在其他命题之中, 如果原始输出不是数值, 也需要进行类似的转换。
LSTM 初体验: seq_length =1, features = 1
原文小标题: Naive LSTM for Learning One-Char to One-Char Mapping
这种是最简单朴素的方式。 feature & seq_length 都是1
训练模型
1 2 3 4 5 6 7 8 |
# create and fit the model model = Sequential() # 32: cell state size, input_shape: 期望1+ samples model.add(LSTM(32, input_shape=(X.shape[1], X.shape[2]))) model.add(Dense(y.shape[1], activation='softmax')) # 输出多个类 model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(X, y, epochs=500, batch_size=1, verbose=2) |
实测一下结果:
1 2 3 4 5 6 |
# summarize performance of the model scores = model.evaluate(X, y, verbose=0) print("Model Accuracy: %.2f%%" % (scores[1]*100)) # Output: Model Accuracy: 76.00% |
原文将这个LSTM模型称为 Navie LSTM
. 我们看看后面应该如何提高成绩。
修改: seq_length = 3, feature = 1
两处修改:
1 2 3 4 5 |
seq_length = 3 # reshape X to be [samples , time steps, features] X = numpy.reshape(dataX, (len(dataX), 3, 1)) |
此时生成的数据集:
1 2 3 4 5 6 7 8 |
ABC -> D BCD -> E CDE -> F DEF -> G EFG -> H FGH -> I GHI -> J |
这种方式把输入序列当成3个特征, 个人认为只是一种测试方式。
结果: 100%
比如ABC -> D
实际上, 因为有了context信息, 所以对后面的数据 BCD->E
也是有帮助的。
修改:batch_size
Keras在每一个mini_batch之中会保存状态, 但是这一个batch结束之后, 就会reset。
基于最开始的seq_length = 1, features=1
, 我们修改batch_size=len(dataX)
结果: 100%
也可以通过参数强制让Keras不重置状态。
修改: 变长字符
假设Sample长下面这样, 即数据集是变长的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# prepare the dataset of input to output pairs encoded as integers num_inputs = 1000 max_len = 5 dataX = [] dataY = [] for i in range(num_inputs): start = numpy.random.randint(len(alphabet)-2) end = numpy.random.randint(start, min(start+max_len,len(alphabet)-1)) sequence_in = alphabet[start:end+1] sequence_out = alphabet[end + 1] dataX.append([char_to_int[char] for char in sequence_in]) dataY.append(char_to_int[sequence_out]) print sequence_in, '->', sequence_out |
生成的Sample:
1 2 3 4 5 6 7 8 9 10 |
PQRST -> U W -> X O -> P OPQ -> R IJKLM -> N QRSTU -> V ABCD -> E X -> Y GHIJ -> K |
此时的处理方式:
1 2 |
X = pad_sequences(dataX, maxlen=max_len, dtype='float32') |
主要是使用pad_sequences
。 长度不足的地方会用0
填充。
其他一些值得看看的文章:
Tensorflow实例:利用LSTM预测股票每日最高价(一)
Tensorflow实例:利用LSTM预测股票每日最高价(二)
LSTM Neural Network for Time Series Prediction
Multidimensional LSTM Networks to Predict Bitcoin Price

文章评论