如何在深度学习框架中实现LSTM?

提供的答案:

长短期记忆(LSTM)是目前循环神经网络最普遍使用的类型,在处理时间序列数据时使用最为频繁。关于 LSTM 的更加深刻的洞察可以看看这篇优秀的博客:http://colah.github.io/posts/2015-08-Understanding-LSTMs/。

目的

本文的主要目的是使读者熟悉在 TensorFlow 上实现基础 LSTM 神经网络的详细过程。我们将选用 MNIST 作为数据集。

MNIST 数据集

手机买彩下载MNIST 数据集包括手写数字的图像和对应的标签。我们可以根据以下内置功能从 TensorFlow 上下载并读取数据。

手机买彩下载from tensorflow.examples.tutorials.mnist import input_data

手机买彩下载mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

数据被分成 3 个部分:

手机买彩下载1. 训练数据(mnist.train):55000 张图像

2. 测试数据(mnist.test):10000 张图像

3. 验证数据(mnist.validation):5000 张图像

数据的形态

讨论一下 MNIST 数据集中的训练数据的形态。数据集的这三个部分的形态都是一样的。

训练数据集包括 55000 张 28x28 像素的图像,这些 784(28x28)像素值被展开成一个维度为 784 的单一向量,所有 55000 个像素向量(每个图像一个)被储存为形态为 (55000,784) 的 numpy 数组,并命名为 mnist.train.images。

所有这 55000 张图像都关联了一个类别标签(表示其所属类别),一共有 10 个类别(0,1,2...9),类别标签使用独热编码的形式表示。因此标签将作为形态为 (55000,10) 的数组保存,并命名为 mnist.train.labels。

为什么要选择 MNIST?

LSTM 通常用来解决复杂的序列处理问题,比如包含了 NLP 概念(词嵌入、编码器等)的语言建模问题。这些问题本身需要大量理解,那么将问题简化并集中于在 TensorFlow 上实现 LSTM 的细节(比如输入格式化、LSTM 单元格以及网络结构设计),会是个不错的选择。

MNIST 就正好提供了这样的机会。其中的输入数据是一个像素值的集合。我们可以轻易地将其格式化,将注意力集中在 LSTM 实现细节上。

实现

手机买彩下载在动手写代码之前,先规划一下实现的蓝图,可以使写代码的过程更加直观。

手机买彩下载VANILLA RNN

循环神经网络按时间轴展开的时候,如下图所示:

图中,

手机买彩下载1.x_t 代表时间步 t 的输入;

手机买彩下载2.s_t 代表时间步 t 的隐藏状态,可看作该网络的「记忆」;

3.o_t 作为时间步 t 时刻的输出;

4.U、V、W 是所有时间步共享的参数,共享的重要性在于我们的模型在每一时间步以不同的输入执行相同的任务。

手机买彩下载当把 RNN 展开的时候,网络可被看作每一个时间步都受上一时间步输出影响(时间步之间存在连接)的前馈网络。

两个注意事项

手机买彩下载为了更顺利的进行实现,需要清楚两个概念的含义:

1.TensorFlow 中 LSTM 单元格的解释;

2. 数据输入 TensorFlow RNN 之前先格式化。

手机买彩下载TensorFlow 中 LSTM 单元格的解释

手机买彩下载在 TensorFlow 中,基础的 LSTM 单元格声明为:

手机买彩下载tf.contrib.rnn.BasicLSTMCell(num_units)

手机买彩下载这里,num_units 指一个 LSTM 单元格中的单元数。num_units 可以比作前馈神经网络中的隐藏层,前馈神经网络的隐藏层的节点数量等于每一个时间步中一个 LSTM 单元格内 LSTM 单元的 num_units 数量。下图可以帮助直观理解:

手机买彩下载每一个 num_units LSTM 单元都可以看作一个标准的 LSTM 单元:

手机买彩下载以上图表来自博客(地址:http://colah.github.io/posts/2015-08-Understanding-LSTMs/),该博客有效介绍了 LSTM 的概念。

手机买彩下载数据输入 TensorFlow RNN 之前先格式化

手机买彩下载在 TensorFlow 中最简单的 RNN 形式是 static_rnn,在 TensorFlow 中定义如下:

tf.static_rnn(cell,inputs)

手机买彩下载虽然还有其它的注意事项,但在这里我们仅关注这两个。

inputs 引数接受形态为 [batch_size,input_size] 的张量列表。列表的长度为将网络展开后的时间步数,即列表中每一个元素都分别对应网络展开的时间步。比如在 MNIST 数据集中,我们有 28x28 像素的图像,每一张都可以看成拥有 28 行 28 个像素的图像。我们将网络按 28 个时间步展开,以使在每一个时间步中,可以输入一行 28 个像素(input_size),从而经过 28 个时间步输入整张图像。给定图像的 batch_size 值,则每一个时间步将分别收到 batch_size 个图像。详见下图说明:

由 static_rnn 生成的输出是一个形态为 [batch_size,n_hidden] 的张量列表。列表的长度为将网络展开后的时间步数,即每一个时间步输出一个张量。在这个实现中我们只需关心最后一个时间步的输出,因为一张图像的所有行都输入到 RNN,预测即将在最后一个时间步生成。

手机买彩下载现在,所有的困难部分都已经完成,可以开始写代码了。只要理清了概念,写代码过程是很直观的。

代码

手机买彩下载在开始的时候,先导入一些必要的依赖关系、数据集,并声明一些常量。设定 batch_size=128 、 num_units=128。

import tensorflow as tffrom tensorflow.contrib import rnn

#import mnist datasetfrom tensorflow.examples.tutorials.mnist import input_data

mnist=input_data.read_data_sets("/tmp/data/",one_hot=True)#define constants#unrolled through 28 time steps

手机买彩下载time_steps=28#hidden LSTM units

num_units=128#rows of 28 pixels

n_input=28#learning rate for adam

手机买彩下载learning_rate=0.001#mnist is meant to be classified in 10 classes(0-9).

手机买彩下载n_classes=10#size of batch

batch_size=128

手机买彩下载现在设置占位、权重以及偏置变量(用于将输出的形态从 [batch_size,num_units] 转换为 [batch_size,n_classes]),从而可以预测正确的类别。

#weights and biases of appropriate shap