keras上手系列之:序列到序列预测问题

来源:互联网 发布:unity3d弯折 编辑:程序博客网 时间:2024/06/17 04:43

LSTM序列到序列模型种类

LSTM 序列到序列(seq to seq)问题建模, 根据问题和数据本身的特点,可以分为几种不同:
- 一对一(one to one)
- 多对一(many to one)
- 一对多(one to many)
- 多对多(many to many)

一个时间步预测

(1) 一对一(one to one)
这种模型是根据过去的一个时间点上的数据,预测下一个时间点的数据. 典型的问题结构是:
y(t+1) = f(x(t))
对应的LSTM网络结构是:
这里写图片描述
按照timestep展开后, 网络结构如下:
这里写图片描述
一对一模型用keras建模实现如下:

model = Sequential()model.add(LSTM(..., input_shape=(1, features)))model.add(Dense(1))

值得注意的是, 数据本身可以是一个向量, 也就是说, 在一个时间点上, 对应的数据本身是多维的.
整个网络的输入是1个长度为features的向量, 输出是标量。
(2) 多对一(many to one)
此时,网络输入的时间步是大于1的, 但是输出的预测时间步只是1.
y(t+1) = f(x(t-n), x(t-n+1), …, x(t))
此时的网络结构为:
这里写图片描述

model = Sequential()features = 10vectors = 3model.add(LSTM(8, input_shape=(vectors, features)))model.add(Dense(1))print(model.summary())

可以得到:

_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================lstm_27 (LSTM)               (None, 8)                 608       _________________________________________________________________dense_22 (Dense)             (None, 1)                 9         =================================================================Total params: 617Trainable params: 617Non-trainable params: 0_________________________________________________________________None

多个时间步预测

TimeDistributed()包装器

要输出对未来多个时间步上的预测, 就必须使用TimeDistributed()包装器, 将输出上一层网络的输出在时间轴上展开. 关于TimeDistributed()包装器, F. Chollet(Keras的作者)解释说:
TimeDistributedDense将同样的密集(全连接)操作应用到3D张量的每一个时间间隔上。
TimeDistributedDense applies a same Dense (fully-connected) operation to every timestep of a 3D tensor.

这一点可以用一个简单的例子说明. 例如如下的单层LSTM网络:

model = Sequential()model.add(LSTM(1, input_shape=(10,1)))print(model.summary())

得到:

_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================lstm_15 (LSTM)               (None, 1)                 12        =================================================================Total params: 12Trainable params: 12Non-trainable params: 0_________________________________________________________________None

另外一个单层LSTM网络外面还增加了TimeDistributed()包装器.

model = Sequential()model.add(TimeDistributed(LSTM(1, input_shape=(None, 10, 1))))print(model.summary())

得到:

_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================time_distributed_14 (TimeDis (None, None, 1)           12        =================================================================Total params: 12Trainable params: 12Non-trainable params: 0_________________________________________________________________None

得到的网络参数都是12. 可见, TimeDistributed()包装器没有引入新的参数, 而是将同样的网络分别在batch中的每个样本上都应用了.正如这个包装器的命名,是将训练数据的batch视为在时间轴上的展开. 这一点上可以从Output Shape中看出来。 对于第一个单层LSTM网络,输出的数据维度就是[batch, 1], 第二个LSTM网络的输出是[batch, batch, 1].
有了对TimeDistributed()包装器的基本认识,我们就可以理解下面的多时间步预测问题。

多时间步上的预测

(3) 一对多(one to many)

这种问题的典型结构是:
y(t+1), y(t+2) = f(x(t))
这里写图片描述
也就是说, 根据过去一步的数据, 预测未来两步的数据. 用keras建模应该是:

model = Sequential()features = 8model.add(LSTM(out_dim, input_shape(1, features), return_sequences=True))model.add(TimeDistributed(Dense(1)))

这里TimeDistributed() 包装器将第一层LSTM的输出序列按照时间顺序排列好. 例如上面LSTM网络的输入数据是[batch, 1, features], 那么输出是: [batch, 1, 20]
在Dense层,增加了TimeDistributed()包装器,可以得到输出的维数是:[batch, 1, 1]
这个模型的结构和输出数据的维数是:

_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================lstm_18 (LSTM)               (None, 1, 20)             2320      _________________________________________________________________time_distributed_17 (TimeDis (None, 1, 1)              21        =================================================================Total params: 2,341Trainable params: 2,341Non-trainable params: 0_________________________________________________________________Noneoutput_shape is : (None, 1, 1)

网络的输入是1个长度是8维的向量,输出是标量。

(4) 多对多(many to many)

多对多问题的典型结构是:
y(t+1), y(t+2), …, y(t+n) = f(y(t-n), y(t-n+1), …, y(t))
这里写图片描述

用keras建模:

from keras.models import Sequentialfrom keras.layers import LSTM, Dense, TimeDistributedmodel = Sequential()in_features = 8n_in = 10out_dim = 6out_features = 12model.add(LSTM(out_dim, input_shape=(n_in, in_features), return_sequences=True))model.add(TimeDistributed(Dense(out_features)))print(model.summary())

得到:

Using TensorFlow backend._________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================lstm_1 (LSTM)                (None, 10, 6)             360       _________________________________________________________________time_distributed_1 (TimeDist (None, 10, 12)            84        =================================================================Total params: 444Trainable params: 444Non-trainable params: 0_________________________________________________________________None

网络的输入是10个长度为8的向量,输出是长度是12的向量。

如果输入序列的长度与输出序列不一致, 那么需要在网络中增加RepeatVector()层.

from keras.layers import RepeatVectormodel = Sequential()n_in = 120n_out = 60model.add(LSTM(60, input_shape=(n_in, 1)))model.add(RepeatVector(n_out))model.add(LSTM(20, return_sequences=True))model.add(TimeDistributed(Dense(1)))model.compile(loss='mse',  optimizer='adam')print(model.summary()) 

得到:

_________________________________________________________________Layer (type)                 Output Shape              Param #   =================================================================lstm_4 (LSTM)                (None, 60)                14880     _________________________________________________________________repeat_vector_1 (RepeatVecto (None, 60, 60)            0         _________________________________________________________________lstm_5 (LSTM)                (None, 60, 20)            6480      _________________________________________________________________time_distributed_2 (TimeDist (None, 60, 1)             21        =================================================================Total params: 21,381Trainable params: 21,381Non-trainable params: 0_________________________________________________________________None