本文介绍了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. LabVIEW(十三):同一个控件的输入和输出转换

    1.实现功能:读取某些文件的数据并将这些数据显示在一个界面上,对界面上的数据进行修改后,将修改后的数据保存到源文件中. 2.显示功能: 程序框图右键>文件I/O>读取分隔符电子表格> ...

  2. iOS开发笔记-一种任意字体、颜色混排UILabel的实现

    最近开发新App,射妓狮给的图上出现一种不同大小字体混排的Label,就像下面这种: 想了想,最简单的方法是使用多个UILabel排列显示,但是这样不仅麻烦而且效果也不好,索性自定义UILabel来尽 ...

  3. PyTorch(一)Basics

    PyTorch Basics import torch import torchvision import torch.nn as nn import numpy as np import torch ...

  4. C语言函数部分

    一.变量的作用域 1.概念:变量起作用的范围. 2.局部变量与全局变量: ①局部变量: 概念:在函数内部或某个控制块的内部定义的变量(理解“局部”) 作用域:函数内部 作用:增强了函数模块的独立性 ② ...

  5. 如何用python爬取两个span之间的内容

    Python用做数据处理还是相当不错的,如果你想要做爬虫,Python是很好的选择,它有很多已经写好的类包,只要调用,即可完成很多复杂的功能,此文中所有的功能都是基于BeautifulSoup这个包. ...

  6. 全网最详细的IDEA、Eclipse和MyEclipse之间于Java web项目发布到Tomcat上运行成功的对比事宜【博主强烈推荐】【适合普通的还是Maven方式创建的】(图文详解)

    不多说,直接上干货! IDEA [适合公司业务]全网最详细的IDEA里如何正确新建[普通或者Maven]的Java web项目并发布到Tomcat上运行成功[博主强烈推荐](类似eclipse里同一个 ...

  7. 从零开始学 Web 之 CSS3(七)多列布局,伸缩布局

    大家好,这里是「 从零开始学 Web 系列教程 」,并在下列地址同步更新...... github:https://github.com/Daotin/Web 微信公众号:Web前端之巅 博客园:ht ...

  8. Docker两种方式进入后台运行的容器

    1.在启动容器的时候,有时候我们加了参数-d,这时容器自动进入后台运行.如果我们要进入容器,该怎么办?通常使用docker attach命令和nsenter工具. 2.docker attach是Do ...

  9. SpringMVC redirect中文乱码问题

    在使用"redirect:xxx.do?param=中文"时会出现乱码问题,解决方案如下: 使用model.addAttribute来替代直接拼接参数.如下: @RequestMa ...

  10. leetcode — generate-parentheses

    import java.util.ArrayList; import java.util.Arrays; import java.util.List; /** * Source : https://o ...