LSTM循环神经网络实例:教你处理LSTM神经网络序列预测问题

应用LSTM神经网络来学习如何在序列预测问题上应用它们是非常重要的,因此,你需要一组定义良好的问题,使你能够专注于不同的问题类型和框架。这是至关重要的,你可以了解序列预测问题是如何不同的,以及像LSTM神经网络这样的复杂模型是如何解决这些问题的。

在本教程中,你将发现5个序列预测问题,你可以使用它们来应用和学习LSTM循环的神经网络。

完成此次教程后,你将了解:

  • 简单的记忆任务来测试LSTM神经网络学习记忆能力。
  • 简单的echo任务来测试LSTM神经网络的学习时间依从能力。
  • 简单的算术任务来测试LSTM神经网络的解译能力。

让我们开始学习吧!

LSTM循环神经网络实例:教你处理LSTM神经网络序列预测问题

教程概述

本教程分为5部分,分别是:

  1. 序列学习问题
  2. 值记忆
  3. Echo 随机整数
  4. Echo随机序列
  5. 序列的分类

问题的性质

序列问题的设计中有几个属性:

  • 狭窄:关注序列预测的一个方面,如内存或函数近似。
  • 可伸缩:在选择的狭窄焦点上或多或少的困难。
  • 再构造:提出了两个或更多的问题,以支持对不同算法学习能力的探索。

1.序列学习问题

在这个问题中,会生成0.0到1.0之间的连续的实值序列。给出一个或多个过去值的时间步长,模型必须预测序列中的下一个项目。我们可以直接生成这个序列,如下所列:

from numpy import array

# generate a sequence of real values between 0 and 1.
def generate_sequence(length=10):
	return array([i/float(length) for i in range(length)])

print(generate_sequence())

运行这个示例打印生成的序列:

[ 0. 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9]

这可以被认为是一种记忆挑战,在之前的时间步长的观察中,模型必须预测下一个值:

X (samples),	y
0.0,			0.1
0.1,			0.2
0.2,			0.3
...

网络可以记忆输入/输出对组,虽然这很无趣,但可以演示网络的函数逼近能力。

这个问题可以被认为随机选择的连续子序列作为输入时间步长,并且序列中的下一个值作为输出。

X (timesteps),		y
0.4, 0.5, 0.6,		0.7
0.0, 0.2, 0.3,		0.4
0.3, 0.4, 0.5,		0.6
...

这将要求网络去学习如何将一个固定的值添加到最后看到的观察中,或者记住生成的问题的所有可能的子序列。这个问题的框架将被建模为一个多对一的序列预测问题。

这是一个简单的问题,它测试了序列学习的原始特征。这个问题可以通过多层感知机网络解决

2.值记忆

问题是要记住序列中的第一个值,并在序列的末尾重复它。这是基于1997年的论文 Long Short Term Memory中“实验2”来证明LSTM而产生的问题。它可以被认为是一个单步预测问题。 给定序列中的一个值,模型必须预测序列中的下一个值。例如,给定一个值为“0”作为输入,模型必须预测“1”的值。

考虑以下5个整数的两个序列:

3, 0, 1, 2, 3
4, 0, 1, 2, 4

Python代码将生成任意长度的两个序列。如果你愿意,你可以进一步概括它。

def generate_sequence(length=5):
	return [i for i in range(length)]

# sequence 1
seq1 = generate_sequence()
seq1[0] = seq1[-1] = seq1[-2]
print(seq1)
# sequence 2
seq1 = generate_sequence()
seq1[0] = seq1[-1]
print(seq1)

运行该示例生成并打印上述两个序列。

[3, 1, 2, 3, 3]
[4, 1, 2, 3, 4]

这些整数可以被标准化,或者说更适合独热编码。

该模式引入了一个问题,即两个序列之间存在相互冲突的信息,并且模型必须知道每个步骤预测的上下环境(例如当前预测的序列),以便正确地预测每个序列。

我们可以看到序列的第一个值被重复作为序列的最后一个值。这是向模型提供上下环境信息的指示器,以便来说明它正在进行的是哪个序列。

遇到的冲突是每一个序列中从第二个到最后一个条目的转换。在序列1中,给出一个“2”作为输入,并且“3”必须被预测,而在序列2中,“2”被输入,并且“4”必须被预测。

Sequence 1:

X (samples),	y
...
1,				2
2,				3

Sequence 2:

X (samples),	y
...
1,				2
2,				4

这个问题是很重要的,它防止模型在每个序列中记住每个单步输入-输出对组的值,因为这个序列不知道模型可能倾向于这样做。

这个框架将被建模为一个一对一的序列预测问题。是一个多层感知机和其他非周期性神经网络无法学习的问题。序列中的第一个值必须在多个样本中被记住。所以这个问题可以被认为提供了除了最后一个作为输入时间步长的值的整个序列,并且预测了终值。

X (timesteps),		y
3, 0, 1, 2, 		3
4, 0, 1, 2, 		4

每个时间步长仍然在网络上显示一次,但是网络必须记住第一个时间步长的值。不同的是,网络可以更好地通过时间的反向传播(back propagation)来更好地了解序列之间的区别。这个问题的框架将被建模为一个多对一的序列预测问题。

再提一次,这个问题不能通过多层感知器来学习。

3.Echo随机整数

在这个问题中,会生成整数的随机序列。

模型必须在特定的滞后时间内记住一个整数,并在序列结束时对其进行Echo。

例如,一个10个整数的随机序列可能是:

5, 3, 2, 1, 9, 9, 2, 7, 1, 6

这个问题可能被框定为在第5个时间步长中重复的值,在本例中是9。

下面的代码将生成随机的整数序列。

from random import randint

# generate a sequence of random numbers in [0, 99]
def generate_sequence(length=10):
	return [randint(0, 99) for _ in range(length)]

print(generate_sequence())

运行该示例将生成并打印一个随机序列,例如:

[47, 69, 76, 9, 71, 87, 8, 16, 32, 81]

这些整数可以被规范化,但是最好使用独热编码来处理。这个问题的一个简单框架就是echo当前的输入值。

yhat(t) = f(X(t))

例如:

X (timesteps),		y
5, 3, 2, 1, 9,		9

这个简单的问题可以很容易地被多层感知器解决,并且可以用来校准或诊断一个测试装置。一个更具挑战性的问题框架是在之前的时间步长中echo这个值。

yhat(t) = f(X(t-1))

例如:

X (timesteps),		y
5, 3, 2, 1, 9,		1

这是一个不能用多层感知器解决的问题。echo的索引可以在时间上进一步向后推,从而在LSTMs内存上增加了更多的需求。

不同于上面的“值记忆”问题,每个训练阶段都会产生一个新的序列。这将要求模型学习一个泛化echo解决方案,而不是记住一个特定的序列或随机数字序列。

在这两种情况下,问题都将被建模为一个多对一的序列预测问题。

4.Echo随机序列

这个问题也涉及到生成整数的随机序列方面。与之前的问题不同,这个问题需要模型来记住并输出输入序列的部分子序列。

最简单的框架应该是上一节的echo问题。相反,我们将关注一个序列输出,其中最简单的框架被模型所记住,并且输出整个输入序列。

例如:

X (timesteps),		y
5, 3, 2, 4, 1,		5, 3, 2, 4, 1

这可以被建模为一个多对一序列预测问题,其中输出序列在输入序列的最后一个值的末尾直接输出。

同时也可以建模为为每一个输入时间步长的网络输出一个值,例如一个一对一的模型。

一个更具挑战性的框架是输出一个输入序列的部分连续子序列。

例如:

X (timesteps),		y
5, 3, 2, 4, 1,		5, 3, 2

这更具有挑战性,因为输入的数量与输出的数量不匹配。这个问题的多对多模型需要一个更高级的体系结构,比如编码-解码器LSTM。

同样,尽管问题可以被建模为规范化的整数值,但是仍然需要独热编码来解决。

5.序列的分类

这个问题被定义为0到1之间的随机值序列。序列被当作问题的输入,每个数字提供一个时间步长。

一个二进制标签(0或1)与每个输入相关。输出值都是0。一旦序列中输入值的累积总和超过一个阈值,那么输出值就会从0变为1。

一个1/4的阈值被使用。

例如,下面是一个10个输入时间步长(X)的序列:

0.63144003 0.29414551 0.91587952 0.95189228 0.32195638 0.60742236 0.83895793 0.18023048 0.84762691 0.29165514

对应的分类输出(y)是:

0 0 0 1 1 1 1 1 1 1

我们可以用Python实现它。

from random import random
from numpy import array
from numpy import cumsum

# create a sequence classification instance
def get_sequence(n_timesteps):
	# create a sequence of random numbers in [0,1]
	X = array([random() for _ in range(n_timesteps)])
	# calculate cut-off value to change class values
	limit = n_timesteps/4.0
	# determine the class outcome for each item in cumulative sequence
	y = array([0 if x < limit else 1 for x in cumsum(X)])
	return X, y

X, y = get_sequence(10)
print(X)
print(y)

运行这个示例会生成一个随机的输入序列,并计算相应的二进制值的输出序列。

[ 0.31102339  0.66591885  0.7211718   0.78159441  0.50496384  0.56941485
  0.60775583  0.36833139  0.180908    0.80614878]
[0 0 0 0 1 1 1 1 1 1]

这是一个可以被建模为一对一的序列分类问题。状态被要求解释过去的时间步长,从而可以正确地预测输出序列从0到1的时间。

 

本文为ATYUN编译作品,未经允许,任何人不得私自转载。ATYUN专注人工智能

本文为ATYUN(www.atyun.com)编译作品,ATYUN专注人工智能
请扫码或微信搜索ATYUN订阅号及时获取最新内容

发表评论