Keras 中的时间分布层使用教程



作者:沂水寒城,CSDN博客专家,个人研究方向:机器学习、深度学习、NLP、CV

Blog: http://yishuihancheng.blog.csdn.net

TimeDistributed官方文档如下:

https://keras.io/layers/wrappers/#timedistributed

长短期网络(LSTM)是一种流行且功能强大的递归神经网络(RNN)。即使使用像Python的Keras深度学习库中提供的那样定义明确且“易于使用”的接口,它们也很难配置并应用于任意序列预测问题。Keras中出现此困难的原因之一是使用了TimeDistributed包装器层,并且需要一些LSTM层返回序列而不是单个值。

在本教程中,您将发现配置LSTM网络进行序列预测的不同方法,TimeDistributed层扮演的角色以及确切的使用方法。完成本教程后,您将知道:

  • 如何设计一对一的LSTM进行序列预测

  • 如何设计没有时间分布层的多对一LSTM序列预测。

  • 如何设计多对多LSTM以便使用TimeDistributed Layer进行序列预测。

教程概述

本教程分为5个部分。 他们是:

1、时间分布层
2、序列学习问题
3、一对一的LSTM用于序列预测
4、用于序列预测的多对一LSTM(无时间分布)
5、用于序列预测的多对多LSTM(具有TimeDistributed)

序列学习问题

我们将使用一个简单的序列学习问题来演示TimeDistributed层。

在此问题中,序列[0.0、0.2、0.4、0.6、0.8]将一次作为输入项提供,并且必须依次返回一次作为输出项作为输出。将其视为学习简单的回声程序。我们给定0.0作为输入,我们希望看到0.0作为输出,并对序列中的每个项目重复进行。

我们可以直接生成此序列,如下所示:

from numpy import array
length = 5
seq = array([i/float(length) for i in range(length)])
print(seq)

运行此示例将打印生成的序列:

[ 0.   0.2  0.4  0.6  0.8]

该示例是可配置的,如果您愿意,以后可以自己播放更长/更短的序列。在评论中让我知道您的结果。输入输出对如下:

X,     y
0.0,    0.0
0.2,    0.2
0.4,    0.4
0.6,    0.6
0.8,    0.8

LSTM的输入必须是三维的。我们可以将2D序列整形为具有5个样本,1个时间步长和1个特征的3D序列。我们将输出定义为具有1个功能的5个样本。

X = seq.reshape(5, 1, 1)
y = seq.reshape(5, 1)

我们将网络模型定义为具有1个输入和1个时间步长。第一个隐藏层将是具有5个单位的LSTM。输出层是具有1个输出的完全连接层。

该模型将使用有效的ADAM优化算法和均方误差损失函数进行拟合。

批大小设置为时期中的样本数,以避免必须使LSTM有状态并手动管理状态重置,尽管这样做很容易,以便在将每个样本显示到网络后更新权重。下面提供了完整的代码清单:

from numpy import array
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# prepare sequence
length = 5
seq = array([i/float(length) for i in range(length)])
X = seq.reshape(len(seq), 1, 1)
y = seq.reshape(len(seq), 1)
# define LSTM configuration
n_neurons = length
n_batch = length
n_epoch = 1000
# create LSTM
model = Sequential()
model.add(LSTM(n_neurons, input_shape=(1, 1)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
print(model.summary())
# train LSTM
model.fit(X, y, epochs=n_epoch, batch_size=n_batch, verbose=2)
# evaluate
result = model.predict(X, batch_size=n_batch, verbose=0)
for value in result:
    print('%.1f' % value)

首先运行示例将打印配置的网络的结构。

我们可以看到LSTM层有140个参数。这是根据输入数(1)和输出数(对于隐藏层中的5个单位为5)计算的,如下所示:

n = 4 * ((inputs + 1) * outputs + outputs^2)
n = 4 * ((1 + 1) * 5 + 5^2)
n = 4 * 35
n = 140

我们还可以看到,完全连接的层仅具有6个参数,分别用于输入数量(上一层中的5个输入为5个),输出数量(该层中的1个神经元为1个)和偏差。

n = inputs * outputs + outputs
n = 5 * 1 + 1
n = 6
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_1 (LSTM)                (None, 1, 5)              140
_________________________________________________________________
dense_1 (Dense)              (None, 1, 1)              6
=================================================================
Total params: 146.0
Trainable params: 146
Non-trainable params: 0.0
_________________________________________________________________
0.0
0.2
0.4
0.6
0.8

用于序列预测的多对一LSTM(无时间分布)。在本节中,我们将开发LSTM以一次全部输出序列,尽管没有TimeDistributed包装器层。

LSTM的输入必须是三维的。我们可以使用1个样本,5个时间步长和1个特征将2D序列重塑为3D序列。我们将输出定义为具有5个功能的1个样本。

X = seq.reshape(1, 5, 1)
y = seq.reshape(1, 5)

立刻,您可以看到问题定义必须稍加调整,以支持没有TimeDistributed包装器的网络进行序列预测。具体来说,输出一个向量,而不是一次建立一个输出序列。两者之间的差异可能听起来有些微,但了解TimeDistributed包装器的作用很重要。

我们将模型定义为具有5个时间步长的一个输入。第一个隐藏层将是具有5个单位的LSTM。输出层是具有5个神经元的完全连接层。

# create LSTM
model = Sequential()
model.add(LSTM(5, input_shape=(5, 1)))
model.add(Dense(length))
model.compile(loss='mean_squared_error', optimizer='adam')
print(model.summary())

接下来,我们仅对训练数据集中的单个样本拟合模型500个神经元,批量大小为1。

# train LSTM
model.fit(X, y, epochs=500, batch_size=1, verbose=2)

综上所述,下面提供了完整的代码清单。

from numpy import array
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
# prepare sequence
length = 5
seq = array([i/float(length) for i in range(length)])
X = seq.reshape(1, length, 1)
y = seq.reshape(1, length)
# define LSTM configuration
n_neurons = length
n_batch = 1
n_epoch = 500
# create LSTM
model = Sequential()
model.add(LSTM(n_neurons, input_shape=(length, 1)))
model.add(Dense(length))
model.compile(loss='mean_squared_error', optimizer='adam')
print(model.summary())
# train LSTM
model.fit(X, y, epochs=n_epoch, batch_size=n_batch, verbose=2)
# evaluate
result = model.predict(X, batch_size=n_batch, verbose=0)
for value in result[0,:]:
    print('%.1f' % value)

首先运行示例将打印配置的网络摘要。我们可以看到LSTM层具有上一节中的140个参数。LSTM单元已被削弱,每个单元将输出一个值,从而提供5个值的向量作为全连接层的输入。时间维度或序列信息已被丢弃,并折叠为5个值的向量。

我们可以看到,完全连接的输出层有5个输入,预计将输出5个值。我们可以说明要学习的30种权重,如下所示:

n = inputs * outputs + outputs
n = 5 * 5 + 5
n = 30

该网络的摘要报告如下:

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_1 (LSTM)                (None, 5)                 140
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 30
=================================================================
Total params: 170.0
Trainable params: 170
Non-trainable params: 0.0
_________________________________________________________________

该模型是合适的,在最终确定并打印预测序列之前先打印损失信息。

序列可以正确地再现,但可以单段显示,而不是逐步输入数据。我们可能已将密集层用作第一隐藏层而不是LSTM,因为这种使用LSTM并没有充分利用其完整的序列学习和处理能力。

0.0
0.2
0.4
0.6
0.8

用于序列预测的多对多LSTM(具有TimeDistributed)

在本节中,我们将使用TimeDistributed层来处理LSTM隐藏层的输出。使用TimeDistributed包装器层时,要记住两个要点:

输入必须是(至少)3D。这通常意味着您需要在TimeDistributed包装的密集层之前配置最后一个LSTM层以返回序列(例如,将“ return_sequences”参数设置为“ True”)。

输出将是3D。这意味着,如果您的TimeDistributed包装的Dense层是您的输出层,并且您正在预测序列,则需要将y数组的大小调整为3D向量。

我们可以将输出的形状定义为具有1个样本,5个时间步长和1个特征,就像输入序列一样,如下所示:

y = seq.reshape(1, length, 1)

通过将“ return_sequences”参数设置为true,我们可以定义LSTM隐藏层以返回序列而不是单个值。

model.add(LSTM(n_neurons, input_shape=(length, 1), return_sequences=True))

这样的效果是,每个LSTM单元都返回5个输出的序列,在输入数据中的每个时间步长返回一个输出,而不是如先前示例中的单个输出值。

我们还可以在输出层上使用TimeDistributed来包装具有单个输出的完全连接的Dense层。

model.add(TimeDistributed(Dense(1)))

输出层中的单个输出值是关键。它强调了我们打算在输入中为每个时间步从序列中输出一个时间步。碰巧我们一次将处理输入序列的5个时间步。

通过将相同的密集层(相同的权重)应用于LSTM输出一次一次,TimeDistributed实现了这一技巧。这样,输出层只需要与每个LSTM单元建立一个连接(加上一个偏置)。

因此,需要增加训练时期的数量以解决较小的网络容量。我将其从500倍增加到1000,以匹配第一个一对一的示例。

from numpy import array
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import TimeDistributed
from keras.layers import LSTM
# prepare sequence
length = 5
seq = array([i/float(length) for i in range(length)])
X = seq.reshape(1, length, 1)
y = seq.reshape(1, length, 1)
# define LSTM configuration
n_neurons = length
n_batch = 1
n_epoch = 1000
# create LSTM
model = Sequential()
model.add(LSTM(n_neurons, input_shape=(length, 1), return_sequences=True))
model.add(TimeDistributed(Dense(1)))
model.compile(loss='mean_squared_error', optimizer='adam')
print(model.summary())
# train LSTM
model.fit(X, y, epochs=n_epoch, batch_size=n_batch, verbose=2)
# evaluate
result = model.predict(X, batch_size=n_batch, verbose=0)
for value in result[0,:,0]:
    print('%.1f' % value)

运行示例,我们可以看到已配置网络的结构。我们可以看到,与前面的示例一样,LSTM隐藏层中有140个参数。

完全连接的输出层是一个完全不同的故事。实际上,它与一对一示例完全匹配。对于上一层中的每个LSTM单元,一个神经元具有一个权重,而对于偏置输入,则具有一个权重。

这有两件重要的事情:

允许按照定义的方式对问题进行框架化和学习,即从一个输入到一个输出,将每个时间步的内部过程都分开。通过少得多的权重来简化网络,从而一次只处理一个时间步。

按照从上一层提供的顺序,将一个更简单的完全连接层应用于每个时间步骤,以构建输出顺序。

_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
lstm_1 (LSTM)                (None, 5, 5)              140
_________________________________________________________________
time_distributed_1 (TimeDist (None, 5, 1)              6
=================================================================
Total params: 146.0
Trainable params: 146
Non-trainable params: 0.0
_________________________________________________________________

再次,网络学习序列

0.0
0.2
0.4
0.6
0.8

在第一个示例中,我们可以认为使用时间步长和TimeDistributed层对问题进行框架化是实现一对一网络的更紧凑方式。在更大范围内,它甚至可能更有效(时空或时空)

很高兴有时间可以亲自翻译和实践一下大神Jason这篇基于LSTM的多种类型网络的数据建模分析教程,欢迎感兴趣的同学一起交流学习共同进步。

赞 赏 作 者

Python中文社区作为一个去中心化的全球技术社区,以成为全球20万Python中文开发者的精神部落为愿景,目前覆盖各大主流媒体和协作平台,与阿里、腾讯、百度、微软、亚马逊、开源中国、CSDN等业界知名公司和技术社区建立了广泛的联系,拥有来自十多个国家和地区数万名登记会员,会员来自以工信部、清华大学、北京大学、北京邮电大学、中国人民银行、中科院、中金、华为、BAT、谷歌、微软等为代表的政府机关、科研单位、金融机构以及海内外知名公司,全平台近20万开发者关注。

▼点击成为社区注册会员      喜欢文章,点个在看

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值