《安娜卡列尼娜》文本生成——利用TensorFlow构建LSTM模型
前言最近看完了LSTM的一些外文资料,主要参考了 Colah的blog以及 Andrej Karpathy blog的一些关于RNN和LSTM的材料,准备动手去实现一个LSTM模型。代码的基础框架来自于Udacity上深度学习纳米学位的课程(付费课程)的一个demo,我刚开始看代码的时候真的是一头雾水,很多东西没有理解,后来反复查阅资料,并我重新对代码进行了学习和修改,对步骤进行了进一步的剖析,下面将一步步用TensorFlow来构建LSTM模型进行文本学习并试图去生成新的文本。本篇文章比较适合新手去操作,LSTM层采用的是BasicLSTMCell。 关于RNN与LSTM模型本文不做介绍,详情去查阅资料过着去看上面的blog链接,讲的很清楚啦。这篇文章主要是偏向实战,来自己动手构建LSTM模型。 数据集来自于外文版《安娜卡列妮娜》书籍的文本文档(本文后面会提供整个project的git链接)。 工具介绍- 语言:Python 3
- 包:TensorFlow及其它数据处理包(见代码中)
- 编辑器:jupyter notebook
- 线上GPU:floyd
---------------------------------------------------------------------------------------------------------- 正文部分正文部分主要包括以下四个部分: - 数据预处理:加载数据、转换数据、分割数据mini-batch - 模型构建:输入层,LSTM层,输出层,训练误差,loss,optimizer - 模型训练:设置模型参数对模型进行训练 - 生成新文本:训练新的文本
主题:整个文本将基于《安娜卡列妮娜》这本书的英文文本作为LSTM模型的训练数据,输入为单个字符,通过学习整个英文文档的字符(包括字母和标点符号等)来进行文本生成。在开始建模之前,我们首先要明确我们的输入和输出。即输入是字符,输出是预测出的新字符。 一. 数据预处理在开始模型之前,我们首先要导入需要的包: import timeimport numpy as npimport tensorflow as tf
这一部分主要包括了数据的转换与mini-batch的分割步骤。 首先我们来进行数据的加载与编码转换。由于我们是基于字符(字母和标点符号等单个字符串,以下统称为字符)进行模型构建,也就是说我们的输入和输出都是字符。举个栗子,假如我们有一个单词“hello”,我们想要基于这个单词构建LSTM,那么希望的到的结果是,输入“h”,预测下一个字母为“e”;输入“e”时,预测下一个字母为“l”,等等。 因此我们的输入便是一个个字母,下面我们将文章进行转换。
上面的代码主要完成了下面三个任务: - 得到了文章中所有的字符集合 vocab - 得到一个字符-数字的映射 vocab_to_int - 得到一个数字-字符的映射 int_to_vocab - 对原文进行转码后的列表 encoded 完成了前面的数据预处理操作,接下来就是要划分我们的数据集,在这里我们使用mini-batch来进行模型训练,那么我们要如何划分数据集呢?在进行mini-batch划分之前,我们先来了解几个概念。
假如我们目前手里有一个序列1-12,我们接下来以这个序列为例来说明划分mini-batch中的几个概念。首先我们回顾一下,在DNN和CNN中,我们都会将数据分batch输入给神经网络,加入我们有100个样本,如果设置我们的batch_size=10,那么意味着每次我们都会向神经网络输入10个样本进行训练调整参数。同样的,在LSTM中,batch_size意味着每次向网络输入多少个样本,在上图中,当我们设置batch_size=2时,我们会将整个序列划分为6个batch,每个batch中有两个数字。
然而由于RNN中存在着“记忆”,也就是循环。事实上一个循环神经网络能够被看做是多个相同神经网络的叠加,在这个系统中,每一个网络都会传递信息给下一个。上面的图中,我们可以看到整个RNN网络由三个相同的神经网络单元叠加起来的序列。那么在这里就有了第二个概念sequence_length(也叫steps),中文叫序列长度。上图中序列长度是3,可以看到将三个字符作为了一个序列。 有了上面两个概念,我们来规范一下后面的定义。我们定义一个batch中的序列个数为N(即batch_size),定义单个序列长度为M(也就是我们的num_steps)。那么实际上我们每个batch是一个 的数组,相当于我们的每个batch中有 个字符。在上图中,当我们设置N=2, M=3时,我们可以得到每个batch的大小为2 x 3 = 6个字符,整个序列可以被分割成12 / 6 = 2个batch。 基于上面的分析,我们下面来进行mini-batch的分割:
上面的代码定义了一个generator,调用函数会返回一个generator对象,我们可以获取一个batch。 经过上面的步骤,我们已经完成了对数据集的预处理。下一步我们开始构建模型。
更多地址:
https://zhuanlan.zhihu.com/p/27087310
|