本文介绍了LSTM网络中的TimeDistributed包装层,代码演示了具有TimeDistributed层的LSTM网络配置方法。

演示了一对一,多对一,多对多,三种不同的预测方法如何配置。

在对多对一预测中用了不配置TimeDistributed的方法,在多对多预测中使用了TimeDistributed层。

对代码的解析在代码注释中

源码地址:

https://github.com/yangwohenmai/LSTM/tree/master/%E9%95%BF%E7%9F%AD%E6%9C%9F%E8%AE%B0%E5%BF%86(LSTM)/LSTM%E7%9A%84%E7%89%B9%E6%80%A7/%E8%BE%93%E5%85%A5%E8%BE%93%E5%87%BA%E5%AF%B9%E5%92%8CTimeDistributed

正文:

长期短期网络或LSTM是一种流行且功能强大的递归神经网络或RNN。

它们可能很难配置并应用于任意序列预测问题,即使使用定义良好且“易于使用”的接口,如Python中的Keras深度学习库中提供的那些接口也是如此。

在Keras中遇到这种困难的一个原因是使用了TimeDistributed包装层,并且需要一些LSTM层来返回序列而不是单个值。

在本教程中,您将发现为序列预测配置LSTM网络的不同方法,TimeDistributed层所扮演的角色以及如何使用它。

TimeDistributed 包装层

LSTM功能强大,但难以使用且难以配置。

你应该如何以及何时使用LSTM的这个包装器?

本教程旨在消除使用带有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]

该示例是可配置的,如果您愿意,您可以稍后自己玩更长/更短的序列。请在评论中告诉我您的结果。

用于序列预测的一对一LSTM

在我们深入研究之前,重要的是要表明这种序列学习问题可以分段学习。

也就是说,我们可以将问题重新构造为序列中每个项目的输入 - 输出对的数据集。给定0,网络应输出0,给定0.2,网络必须输出0.2,依此类推。

这是问题的最简单的表述,并且要求将序列分成输入 - 输出对,并且序列一次一步地预测并聚集在网络外部。

输入输出对如下:

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)])
# 定义输入为:5个样本,一个步长,一个特征值
"""
[[[0. ]]
[[0.2]]
[[0.4]]
[[0.6]]
[[0.8]]]
"""
X = seq.reshape(5, 1, 1)
print(X)
# 定义输出为:5个样本,每个样本1个特征值
"""
[[0. ]
[0.2]
[0.4]
[0.6]
[0.8]]
"""
y = seq.reshape(5, 1)
print(y)
# define LSTM configuration
n_neurons = 5
n_batch = 5
# create LSTM
model = Sequential()
# 输入类型为1个步长和1个特征值
model.add(LSTM(5, 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=1000, 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(没有TimeDistributed)

在本节中,我们开发了一个LSTM来同时输出序列,尽管没有TimeDistributed包装层。

LSTM的输入必须是三维的。我们可以将2D序列重塑为具有1个样本,5个时间步长和1个特征的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
# 输入为1个样本,5个步长,1个特征值
length = 5
seq = array([i/float(length) for i in range(length)])
"""
[[[0. ]
[0.2]
[0.4]
[0.6]
[0.8]]]
"""
X = seq.reshape(1, 5, 1)
print(X)
# 输出为五个特征值的一个样本
"""
[[0. 0.2 0.4 0.6 0.8]]
"""
y = seq.reshape(1, 5)
print(y)
# define LSTM configuration
n_neurons = length
n_batch = 1
# create LSTM
model = Sequential()
# 输入类型为5个步长,1个特征值
model.add(LSTM(5, input_shape=(5, 1)))
model.add(Dense(5))
model.compile(loss='mean_squared_error', optimizer='adam')
print(model.summary())
# train LSTM
model.fit(X, y, epochs=500, 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
_________________________________________________________________

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

序列被正确再现,但是作为单个部分而不是逐步通过输入数据。我们可能使用Dense层作为第一个隐藏层而不是LSTM,因为LSTM的这种使用并没有充分利用它们完整的序列学习和处理能力。

0.0
0.2
0.4
0.6
0.8

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

在本节中,我们将使用TimeDistributed层来处理LSTM隐藏层的输出。

使用TimeDistributed包装层时需要记住两个关键点:

  • 输入必须(至少)为3D。这通常意味着您需要在TimeDistributed wrapped Dense层之前配置最后一个LSTM层以返回序列(例如,将“return_sequences”参数设置为“True”)。
  • 输出将是3D。这意味着如果TimeDistributed wrapped 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个时间步。

TimeDistributed通过一次一个步骤将相同的Dense层(相同的权重)应用于LSTM输出来实现此技巧。这样,输出层只需要一个连接到每个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)])
# 输入为1个样本,5个步长,1个特征值
X = seq.reshape(1, 5, 1)
# 输出为1个样本,5个步长,1个特征值
y = seq.reshape(1, 5, 1)
# define LSTM configuration
n_batch = 1
# create LSTM
model = Sequential()
# 输入类型为5个步长和1个特征值,return_sequences=True返回整个序列
model.add(LSTM(5, input_shape=(5, 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=1000, 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层视为在第一个示例中实现一对一网络的更紧凑方式。它甚至可能在更大规模上更有效(空间或时间)。

参考:

https://blog.csdn.net/yangwohenmai1/article/details/84981645

https://machinelearningmastery.com/timedistributed-layer-for-long-short-term-memory-networks-in-python/

RNN,LSTM中如何使用TimeDistributed包装层,代码示例的更多相关文章

  1. 简:Spring中Bean的生命周期及代码示例

    (重要:spring bean的生命周期. spring的bean周期,装配.看过spring 源码吗?(把容器启动过程说了一遍,xml解析,bean装载,bean缓存等)) 完整的生命周期概述(牢记 ...

  2. 浅谈 PHP 中的多种加密技术及代码示例

    信息加密技术的分类 单项散列加密技术(不可逆的加密) 属于摘要算法,不是一种加密算法,作用是把任意长的输入字符串变化成固定长的输出串的一种函数 MD5 string md5 ( string $str ...

  3. c/c++中define用法详解及代码示例

    https://blog.csdn.net/u012611878/article/details/52534622   版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog. ...

  4. python---Numpy模块中创建数组的常用方式代码示例

    要机器学习,这方面内容不可少. import numpy as np import time # 对比标准python实现和numpy实现的性能差异 def sum_trad(): start = t ...

  5. C#中构建多线程应用程序[转] ----代码示例

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  6. ECMAScript 6 中的快捷语法汇总及代码示例

    对于每个 JavaScript 开发人员,快捷语法都是必备技能之一,下面就集中介绍这些快捷语法. 三元运算符 传统写法 const x = 20; let answer; if (x > 10) ...

  7. go中的方法以及自定义类型代码示例

    package main import "fmt" type user struct { name string age int sex string } type admin s ...

  8. 深度学习中的序列模型演变及学习笔记(含RNN/LSTM/GRU/Seq2Seq/Attention机制)

    [说在前面]本人博客新手一枚,象牙塔的老白,职业场的小白.以下内容仅为个人见解,欢迎批评指正,不喜勿喷![认真看图][认真看图] [补充说明]深度学习中的序列模型已经广泛应用于自然语言处理(例如机器翻 ...

  9. tensorflow学习之(十一)RNN+LSTM神经网络的构造

    #RNN 循环神经网络 import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data tf.se ...

随机推荐

  1. Burpsuite常用模块详解以及渗透测试上的运用

    0x00前言 哪有什么前言,大家好,我是浅安.QQ:320229344... 0x01 JDK的安装,以及Burpsuite的成功开启. burpsuite基于JAVA环境才能正常运行的.所以要先安装 ...

  2. Android 上传文件到 FTP 服务器

    实现背景 近期接触到一个需求,就是将文件从Android系统上传到FTP服务器,虽然之前接触过FTP服务器,了解基本的使用流程,但是将此流程从使用习惯转化为代码实现还是有一定难度的.但是基本的流程还是 ...

  3. 第31节:Java基础-类与对象

    前言 Java基础-类与对象,方法的重载,构造方法的重载,static关键字,main()方法,this关键字,包,访问权限,类的继承,继承性,方法的重写,super变量. 方法的重载:成员方法的重载 ...

  4. python中使用双端队列解决回文问题

    双端队列:英文名字:deque (全名double-ended queue)是一种具有队列和栈性质的抽象数据类型. 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行. 双端队列可以在 ...

  5. redis pipeline 独占链接

    pipeline期间将“独占”链接,此期间将不能进行非“管道”类型的其他操作,直到pipeline关闭:如果你的pipeline的指令集很庞大,为了不干扰链接中的其他操作,你可以为pipeline操作 ...

  6. Hadoop项目实战-用户行为分析之编码实践

    1.概述 本课程的视频教程地址:<用户行为分析之编码实践> 本课程以用户行为分析案例为基础,带着大家去完成对各个KPI的编码工作,以及应用调度工作,让大家通过本课程掌握Hadoop项目的编 ...

  7. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(十二):解决跨域问题

    什么是跨域? 同源策略是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 如果一个请求地址里面的协议.域名和端口号都相同,就属于同源. ...

  8. 通过反编译深入理解Java String及intern

    一.字符串问题 字符串在我们平时的编码工作中其实用的非常多,并且用起来也比较简单,所以很少有人对其做特别深入的研究.倒是面试或者笔试的时候,往往会涉及比较深入和难度大一点的问题.我在招聘的时候也偶尔会 ...

  9. java 访问剪切板(读取与设置)

    设置文本到剪切板 public void setIntoClipboard(String data) { Clipboard clipboard = Toolkit.getDefaultToolkit ...

  10. [深度学习] 最全优化方法总结比较--SGD,Adagrad,Adadelta,Adam,Adamax,Nadam

    SGD 此处的SGD指mini-batch gradient descent,关于batch gradient descent, stochastic gradient descent, 以及 min ...