深度学习入门系列23:项目:用爱丽丝梦游仙境生成文本

大家好,我技术人Howzit,这是深度学习入门系列第二十三篇,欢迎大家一起交流!

深度学习入门系列1:多层感知器概述
深度学习入门系列2:用TensorFlow构建你的第一个神经网络
深度学习入门系列3:深度学习模型的性能评价方法
深度学习入门系列4:用scikit-learn找到最好的模型
深度学习入门系列5项目实战:用深度学习识别鸢尾花种类
深度学习入门系列6项目实战:声纳回声识别
深度学习入门系列7项目实战:波士顿房屋价格回归
深度学习入门系列8:用序列化保存模型便于继续训练
深度学习入门系列9:用检查点保存训练期间最好的模型
深度学习入门系列10:从绘制记录中理解训练期间的模型行为
深度学习入门系列11:用Dropout正则减少过拟合
深度学习入门系列12:使用学习规划来提升性能
深度学习入门系列13:卷积神经网络概述
深度学习入门系列14:项目实战:基于CNN的手写数字识别
深度学习入门系列15:用图像增强改善模型性能
深度学习入门系列16:项目实战:图像中目标识别
深度学习入门系列17:项目实战:从电影评论预测情感
深度学习入门系列18:循环神经网络概述
深度学习入门系列19:基于窗口(window)的多层感知器解决时序问题
深度学习入门系列20:LSTM循环神经网络解决国际航空乘客预测问题
深度学习入门系列21:项目:用LSTM+CNN对电影评论分类
深度学习入门系列22:从猜字母游戏中理解有状态的LSTM递归神经网络
深度学习入门系列23:项目:用爱丽丝梦游仙境生成文本

循环神经网络也被用于生成模型,这意味着除了能够用于预测模型(做预测),它还能学习序列问题并生成问题域的新的序列。像这样的生成模型不仅有助于研究一个模型学习一个问题的好坏,而且还能学习更多问题域本身。在这个项目中,你将学习如何使用LSTM循环神经网络为文本字符创建模型。完成之后,你将了解:

  • 在哪下载免费的文本语料库用于训练生成模型。
  • 如何把序列问题转成循环神经网络生成模型
  • 如何在给定问题的情况下开发LSTM生成合理文本序列。

让我们开始。

23.1 问题描述:文本生成

许多经典的书籍不在受到版本的保护,这意味着你可以免费的下载这些书籍文本并在实验中使用,像创建生成模型。可能下载这些书籍最好的去处且不受版本保护的是Gutenberg,在这节课中我们将使用童年最受欢迎的一本书作为数据集:Alice’s Adventures in Wonderland by Lewis Carroll

我们将了学习序列中字符间依赖和字符的条件概率,这样的话我们就能生成全新且原始的字符序列。这节课是挺好玩的,你可以用Gutenberg项目中的其他书籍来重复这个实验。当然这个实验不局限于文本,你也可以是用ASCII码做实验,比如电脑的原码,由LaTexHTML或者markdown甚至更多格式而组成。
你可以下载完整的ASCII格式(纯文本 UTF-8)的文本,并放在你的工作目录中,命名为 wonderland.txt。现在我们需要准备数据集进行建模。Gutenberg项目为每本书添加的头部和尾部,这部分不是原文的内容。在文本编辑器中打开它,并删除这些内容,头部是很明显的,以下面的文本而结束:

START OF THIS PROJECT GUTENBERG EBOOK ALICE'S ADVENTURES IN WONDERLAND 

脚部在所有文本之后,其文本为:

THE END

您应该得到一个包含大约 3,330 行的文本文件。

23.2 构建小型LSTM循环神经网络

在这个部分,我们将构建一个简单的LSTM网络从Alice in Wonderland中学习字符的时序关系。在下部分中,我们将使用这个模型来生成新的字符序列。让我们从导入用于训练模型的类和函数开始。

import numpy  
from keras.models import Sequential  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.callbacks import ModelCheckpoint  
from keras.utils import np_utils 

接下来,我们需要加载ASCII格式的书籍到内存中,并把所有的字符转成小写,目的减少网络学习的词汇量。

# load ascii text and covert to lowercase  
filename = "wonderland.txt"  
raw_text = open(filename).read()  
raw_text = raw_text.lower()

既然书已经加载了,那么我就必须为神经网络建模准备数据。我们不能直接对字符进行建模,而是将这些字符转成整型。我们可以通过这本书首次创建的字符集合来实现这一诉求,创建每个字符与唯一整型的一一对应关系。

# create mapping of unique chars to integers, and a reverse 
mapping chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for i, c in enumerate(chars))

举个例子,列出书中所有已排序小写字符如下:

['\n', '\r', ' ', '!', '"', "'", '(', ')', '*', ',', '-', '.', ':', ';', '?', '[', ']', '_', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '\xbb', '\xbf', '\xef']

其实你也能够看到,有一些字符可以移除的,这样的话就能够进一步清理数据集,减少了单词量并能够提高建模的效率。既然书本内容已经加载,而且映射关系也准备好了,那么我们对数据集进行概括。

n_chars = len(raw_text) 
n_vocab = len(chars) 
print("Total Characters: ", n_chars) 
print("Total Vocab: ", n_vocab)

运行上面代码,得到如下的结果:

Total Characters: 147674 
Total Vocab: 47

我们能够看到,书中最多有150,000字符,转成小写并过滤去重,只有47个完全不同的字符可供网络学习。要比26个字母多。我们需要为网络定义训练数据集。在如何选择分解文本以及输入到网络进行训练有很多灵活性的。在本节课中,我们将文本分解为100个字符的固定长度、任意长度。我们可以很容易地按句子拆分数据,填充较短的序列并截断较长的序列。

每个网络的训练数据格式都是100个时间步的单字符(X)组成,紧跟着单字符输出(y)。当我们创建这些字符时,我们一次在整书滑动一次窗口,允许每个字符都有机会从前100个字符中学习(期望是课程中的前100个字符)。举个例子,如果序列长度是5(为了简单),然后前两个训练格式如下:

CHAPT -> E 
HAPTE -> R

正如我们把书中数据分解的那些序列一样,我们把这些序列转成整型,用于我们之前准备的查找表。

# prepare the dataset of input to output pairs encoded as integers  
seq_length = 100  
dataX = []  
dataY = []  
for i in range(0, n_chars - seq_length, 1):  
	seq_in = raw_text[i:i + seq_length]  
	seq_out = raw_text[i + seq_length]  
	dataX.append([char_to_int[char] for char in seq_in])  
	dataY.append(char_to_int[seq_out])  
	n_patterns = len(dataX)  
	print("Total Patterns: ", n_patterns)

运行上面的代码,向我们展示了,当我们把数据集划分为训练集用于网络学习时,我们仅仅不到150,000训练格式。排除前100个字符也能够说得通,我们用一种训练格式来预测剩下的每个字符。

Total Patterns: 147574

我们已经准备好适合keras使用的训练集,首先,我们必须将输入序列转成[samples, time steps, features]格式,这种格式正是LSTM需要的格式。接下来,我们需要把参数调整在0-1之间,为了让LSTM网络更容易学习,网络默认采用激活函数sigmoid

最后,我们需要将输出格式(单字符转成整型)转成one hot编码。这样的话,我们需要配置网络来预测单词表中的47不同字符概率(一种简单的表示)而不是尝试强制准确的预测下个字符。每个y值被转成47维的稀疏向量,除了1之外全是01那列代表字符,也就是要表示格式。举个例子,当n(第31个值)是one hot 编码,长成下面那样:

[ 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 1. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

我们通过下面实现这些步骤。

# reshape X to be [samples, time steps, features]  
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))  
# normalize  
X = X / float(n_vocab)  
# one hot encode the output variable  
y = np_utils.to_categorical(dataY)

我们现在定义我们的LSTM模型。在这定义了一个256个神经元的单隐藏LSTM层。网络使用Dropout的概率为20%,输出层是Dense层,采用softmax函数用于输出47字符的预测概率,值在0-1之间。这个问题是真正的47种类别的单字符分类问题,因此使用优化的对数损失函数(交叉墒),在这使用Adam优化函数来加速。

# define the LSTM model  
model = Sequential()  
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]))) 
model.add(Dropout(0.2))  
model.add(Dense(y.shape[1], activation='softmax'))  
model.compile(loss='categorical_crossentropy', optimizer='adam')

这不是测试集,我们正在建模整个训练集来学习序列中每个字符的概率。我们对训练集中最精确模型(分类精度)不感兴趣。它是一个能够完美预测训练集中每个字符的模型。相反,我们对最小化所选损失函数的数据集的泛化感兴趣。我们寻求泛化和过拟合之间的平衡,但是缺乏记忆。

这个网络训练很慢(使用Nvidia K520 GPU每个迭代需要300s),由于慢和优化的需求,每次在epoch结束时观察到损失的改善时,我们将使用模型检查点记录所有网络权重以归档。我们将在下节使用最好的权重集合(最低的loss)来生成我们模型。

# define the checkpoint  
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5" 
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True,  
mode='min')  
callbacks_list = [checkpoint]

我们现在拟合我们的模型到数据,在这我们使用最适量的迭代周期20和大点的批处理128

model.fit(X, y, epochs=20, batch_size=128, callbacks=callbacks_list)

为了完整性下面提供来完整代码。

# Small LSTM Network to Generate Text for Alice in Wonderland  
import numpy  
from keras.callbacks import ModelCheckpoint  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.models import Sequential  
from keras.utils import np_utils  
  
# load ascii text and covert to lowercase  
filename = "wonderland.txt"  
raw_text = open(filename).read()  
raw_text = raw_text.lower()  

# create mapping of unique chars to integers  
chars = sorted(list(set(raw_text)))  
char_to_int = dict((c, i) for i, c in enumerate(chars))  

# summarize the loaded data  
n_chars = len(raw_text)  
n_vocab = len(chars)  
print("Total Characters: ", n_chars)  
print("Total Vocab: ", n_vocab)  

# prepare the dataset of input to output pairs encoded as integers  
seq_length = 100  
dataX = []  
dataY = []  
for i in range(0, n_chars - seq_length, 1):  
    seq_in = raw_text[i:i + seq_length]  
    seq_out = raw_text[i + seq_length]  
    dataX.append([char_to_int[char] for char in seq_in])  
    dataY.append(char_to_int[seq_out])  
  
n_patterns = len(dataX)  
print("Total Patterns: ", n_patterns)  

# reshape X to be [samples, time steps, features]  
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))  

# normalize  
X = X / float(n_vocab)  

# one hot encode the output variable  
y = np_utils.to_categorical(dataY)  

# define the LSTM model  
model = Sequential()  
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))  
model.add(Dropout(0.2))  
model.add(Dense(y.shape[1], activation='softmax'))  
model.compile(loss='categorical_crossentropy', optimizer='adam')  

# define the checkpoint  
filepath = "weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"  
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True, mode='min')  
callbacks_list = [checkpoint]  
# fit the model  
model.fit(X, y, epochs=20, batch_size=128, callbacks=callbacks_list)

由于模型随机性的特性,你可以看到不同的结果。因为对于LSTM模型很难设置随机种子实现100%的可复制结果。对于生成模型这不是他关注的。运行这个例子之后,你应该在本地有个权重检查点的文件,你可以删除所有除了损失最小的那个。举个例子,当我运行这个例子,下面是我们获得最小损失的检查点。

weights-improvement-19-1.9435.hdf5

网络损失几乎每次迭代都在减少,而且我们期望提高迭代次数能提高模型网络训练的性能。下面部分,我们将看看通过模型生成新文本。

23.3 网络生成文本

使用已经训练的LSTM网络生成文本是最直接的办法。首先,我们加载数据并用同样严格的方法定义模型,除了网络能够从检查点文件中加载权重之外而且网络不在需要训练。

备注:你需要使用同样的机器或者环境来生成文本,正如创建网络权重的那样(如GPU或者CPU),否则网络就是废物。

# load the network weights 
filename = "weights-improvement-19-1.9435.hdf5" 
model.load_weights(filename) 
model.compile(loss='categorical_crossentropy', optimizer='adam')

与此同时,当我们准备唯一字符和整型映射关系时,我们需要创建反映射关系,用于把整型转成对于字符,以至于我们能够理解预测结果。

int_to_char = dict((i, c) for i, c in enumerate(chars))

最后,我们需要实际做预测。使用Keras LSTM模型做预测的最简单的方法是从随机的序列作为输入开始,生成下个字符,然后更新随机序列并添加到已经生成字符的尾部并去掉第一个字符。只要我们想预测新字符就不断重复这个过程(如长度为1000的字符)。我挑选个随机输入格式作为我们种子序列,打印已生成的字符。

# pick a random seed  
start = numpy.random.randint(0, len(dataX)-1)  
pattern = dataX[start]  
print("Seed:")  
print("\"", ''.join([int_to_char[value] for value in pattern]), "\"")  
# generate characters  
for i in range(1000):  
    x = numpy.reshape(pattern, (1, len(pattern), 1))  
    x = x / float(n_vocab)  
    prediction = model.predict(x, verbose=0)  
    index = numpy.argmax(prediction)  
    result = int_to_char[index]  
    seq_in = [int_to_char[value] for value in pattern]  
    sys.stdout.write(result)  
    pattern.append(index)  
    pattern = pattern[1:len(pattern)]  
print("\nDone.")

使用已经加载的LSTM网络模型来生成文本的完整代码如下:

# Load LSTM network and generate text  
import sys  
  
import numpy  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.models import Sequential  
from keras.utils import np_utils  
  
# load ascii text and covert to lowercase  
filename = "wonderland.txt"  
raw_text = open(filename).read()  
raw_text = raw_text.lower()  
# create mapping of unique chars to integers, and a reverse mapping  
chars = sorted(list(set(raw_text)))  
char_to_int = dict((c, i) for i, c in enumerate(chars))  
int_to_char = dict((i, c) for i, c in enumerate(chars))  
# summarize the loaded data  
n_chars = len(raw_text)  
n_vocab = len(chars)  
print("Total Characters: ", n_chars)  
print("Total Vocab: ", n_vocab)  

# prepare the dataset of input to output pairs encoded as integers  
seq_length = 100  
dataX = []  
dataY = []  
for i in range(0, n_chars - seq_length, 1):  
    seq_in = raw_text[i:i + seq_length]  
    seq_out = raw_text[i + seq_length]  
    dataX.append([char_to_int[char] for char in seq_in])  
    dataY.append(char_to_int[seq_out])  
    n_patterns = len(dataX)  
print("Total Patterns: ", n_patterns)  
  
# reshape X to be [samples, time steps, features]  
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))  
# normalize  
X = X / float(n_vocab)  
# one hot encode the output variable  
y = np_utils.to_categorical(dataY)  

# define the LSTM model  
model = Sequential()  
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))  
model.add(Dropout(0.2))  
model.add(Dense(y.shape[1], activation='softmax'))  
# load the network weights  
filename = "weights-improvement-19-1.9435.hdf5"  
model.load_weights(filename)  
model.compile(loss='categorical_crossentropy', optimizer='adam')  
# pick a random seed  
start = numpy.random.randint(0, len(dataX) - 1)  
pattern = dataX[start]  
print("Seed:")  
print("\"", ''.join([int_to_char[value] for value in pattern]), "\"")  
# generate characters  
for i in range(1000):  
    x = numpy.reshape(pattern, (1, len(pattern), 1))  
    x = x / float(n_vocab)  
    prediction = model.predict(x, verbose=0)  
    index = numpy.argmax(prediction)  
    result = int_to_char[index]  
    seq_in = [int_to_char[value] for value in pattern]  
    sys.stdout.write(result)  
    pattern.append(index)  
    pattern = pattern[1:len(pattern)]  
print("\nDone.")

运行这个代码首先输出的是我们选择的随机种子,然后每个字符都是它生成的。举个例子,下面是来自文本生成器运行结果。随机种子如下:

be no mistake about it: it was neither more nor less than a pig, and she felt that it would be quit

用随机种子生成的文本如下:

be no mistake about it: it was neither more nor less than a pig, and she  
felt that it would be quit e aelin that she was a little want oe toiet  
ano a grtpersent to the tas a little war th tee the tase oa teettee  
the had been tinhgtt a little toiee at the cadl in a long tuiee aedun  
thet sheer was a little tare gereen to be a gentle of the tabdit soenee  
the gad ouw ie the tay a tirt of toiet at the was a little  
anonersen, and thiu had been woite io a lott of tueh a tiie and taede  
bot her aeain she cere thth the bene tith the tere bane to tee  
toaete to tee the harter was a little tire the same oare cade an anl ano  
the garee and the was so seat the was a little gareen and the sabdit,  
and the white rabbit wese tilel an the caoe and the sabbit se teeteer,  
and the white rabbit wese tilel an the cade in a lonk tfne the sabdi  
ano aroing to tea the was sf teet whitg the was a little tane oo thete  
the sabeit she was a little tartig to the tar tf tee the tame of the  
cagd, and the white rabbit was a little toiee to be anle tite thete ofs  
and the tabdit was the wiite rabbit, and

我们对已生成的文本进行了观察。

  • 一般来说,符合少于80字符的原始文本的行格式需要换行。
  • 很多字符被分成组了而且大部分组是实际的单词(如the,litte和was),但是有些不是(如lott,tiie和taede)。
  • 有些单词是有意义的(如and the white rabbit),但是很多是没有意义的(如wese tilel)

这个基于字符模型得到像这样的结果,这一事实是不错的。让你了解了LSTM网络的学习能力。结果并不完美。在下部分我们将看看通过构建更大的LSTM网络提高质量。

23.4 更大规模循环神经网络

我们得到结果,但是没有比上节好。现在,我们通过创建更大的网络尝试提高生成文本的质量。我们将保持256个记忆单元的数量,但是再加一层。

model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), return_sequences=True)) 
model.add(Dropout(0.2)) 
model.add(LSTM(256)) 
model.add(Dropout(0.2)) 
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')

我们将改变检查点权重文件的名字,以便于我们能够区别现在网络和之前网络(在文件名中加上Bigger单词)。

filepath="weights-improvement-{epoch:02d}-{loss:.4f}-bigger.hdf5"

最后,我们将增加训练的迭代次数,从2050,并减少了批处理大小,从128降到64,给网络更多的机会更新权重和学习。为了完整性下面给出了所有的代码。

# Larger LSTM Network to Generate Text for Alice in Wonderland  
import numpy  
from keras.callbacks import ModelCheckpoint  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.models import Sequential  
from keras.utils import np_utils  
  
# load ascii text and covert to lowercase  
filename = "wonderland.txt"  
raw_text = open(filename).read()  
raw_text = raw_text.lower()  
# create mapping of unique chars to integers  
chars = sorted(list(set(raw_text)))  
char_to_int = dict((c, i) for i, c in enumerate(chars))  
# summarize the loaded data  
n_chars = len(raw_text)  
n_vocab = len(chars)  
print("Total Characters: ", n_chars)  
print("Total Vocab: ", n_vocab)  
# prepare the dataset of input to output pairs encoded as integers  
seq_length = 100  
dataX = []  
dataY = []  
for i in range(0, n_chars - seq_length, 1):  
    seq_in = raw_text[i:i + seq_length]  
    seq_out = raw_text[i + seq_length]  
    dataX.append([char_to_int[char] for char in seq_in])  
    dataY.append(char_to_int[seq_out])  
  
n_patterns = len(dataX)  
print("Total Patterns: ", n_patterns)  
# reshape X to be [samples, time steps, features]  
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))  
# normalize  
X = X / float(n_vocab)  
# one hot encode the output variable  
y = np_utils.to_categorical(dataY)  
# define the LSTM model  
model = Sequential()  
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))  
model.add(Dropout(0.2))  
model.add(LSTM(256))  
model.add(Dropout(0.2))  
model.add(Dense(y.shape[1], activation='softmax'))  
model.compile(loss='categorical_crossentropy', optimizer='adam')  
# define the checkpoint  
filepath = "weights-improvement-{epoch:02d}-{loss:.4f}-bigger.hdf5"  
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True,  
                             mode='min')  
callbacks_list = [checkpoint]  
# fit the model  
model.fit(X, y, epochs=50, batch_size=64, callbacks=callbacks_list)

运行上面的代码需要一定时间,每个迭代周期至少700s。运行这个例子之后,你可能获得大约1.2的损失。这个例子,我们获得最好的结果保存在检查点文件里,名字如下:

weights-improvement-47-1.2219-bigger.hdf5

47次迭代时,获得了1.2219的损失。正如上一节,我们使用最好的模型来生成文本。唯一不同的是网络拓扑结构。

为了完整性提供了下面的代码。

# Load Larger LSTM network and generate text  
import sys  
  
import numpy  
from keras.layers import Dense  
from keras.layers import Dropout  
from keras.layers import LSTM  
from keras.models import Sequential  
from keras.utils import np_utils  
  
# load ascii text and covert to lowercase  
filename = "wonderland.txt"  
raw_text = open(filename).read()  
raw_text = raw_text.lower()  
# create mapping of unique chars to integers, and a reverse mapping  
chars = sorted(list(set(raw_text)))  
char_to_int = dict((c, i) for i, c in enumerate(chars))  
int_to_char = dict((i, c) for i, c in enumerate(chars))  
# summarize the loaded data  
n_chars = len(raw_text)  
n_vocab = len(chars)  
print("Total Characters: ", n_chars)  
print("Total Vocab: ", n_vocab)  

# prepare the dataset of input to output pairs encoded as integers  
seq_length = 100  
dataX = []  
dataY = []  
for i in range(0, n_chars - seq_length, 1):  
    seq_in = raw_text[i:i + seq_length]  
    seq_out = raw_text[i + seq_length]  
    dataX.append([char_to_int[char] for char in seq_in])  
    dataY.append(char_to_int[seq_out])  
    n_patterns = len(dataX)  
print("Total Patterns: ", n_patterns)  

# reshape X to be [samples, time steps, features]  
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))  

# normalize  
X = X / float(n_vocab)  

# one hot encode the output variable  
y = np_utils.to_categorical(dataY)  

# define the LSTM model  
model = Sequential()  
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2]), return_sequences=True))  
model.add(Dropout(0.2))  
model.add(LSTM(256))  
model.add(Dropout(0.2))  
model.add(Dense(y.shape[1], activation='softmax'))  

# load the network weights  
filename = "weights-improvement-47-1.2219-bigger.hdf5"  
model.load_weights(filename)  
model.compile(loss='categorical_crossentropy', optimizer='adam')  

# pick a random seed  
start = numpy.random.randint(0, len(dataX) - 1)  
pattern = dataX[start]  
print("Seed:")  
print("\"", ''.join([int_to_char[value] for value in pattern]), "\"")  

# generate characters  
for i in range(1000):  
    x = numpy.reshape(pattern, (1, len(pattern), 1))  
    x = x / float(n_vocab)  
    prediction = model.predict(x, verbose=0)  
    index = numpy.argmax(prediction)  
    result = int_to_char[index]  
    seq_in = [int_to_char[value] for value in pattern]  
    sys.stdout.write(result)  
    pattern.append(index)  
    pattern = pattern[1:len(pattern)]  
print("\nDone.")

运行了这个文本生成脚本得到下面的结果,随机选择种子文本:

d herself lying on the bank, with her
head in the lap of her sister, who was gently brushing away s

用随机种子生成的文本(为了表示做了清理)如下:

herself lying on the bank, with her  
head in the lap of her sister, who was gently brushing away  
so siee, and she sabbit said to herself and the sabbit said to herself and the sood  
way of the was a little that she was a little lad good to the garden,  
and the sood of the mock turtle said to herself, 'it was a little that  
the mock turtle said to see it said to sea it said to sea it say it  
the marge hard sat hn a little that she was so sereated to herself, and  
she sabbit said to herself, 'it was a little little shated of the sooe  
of the coomouse it was a little lad good to the little gooder head. and  
said to herself, 'it was a little little shated of the mouse of the  
good of the courte, and it was a little little shated in a little that  
the was a little little shated of the thmee said to see it was a little  
book of the was a little that she was so sereated to hare a little the  
began sitee of the was of the was a little that she was so seally and  
the sabbit was a little lad good to the little gooder head of the gad  
seared to see it was a little lad good to the little good

我们能够看到有很少的拼写错误而且文本看起来更加真实,但是依然存在无意义的。举个例子,同样的词组重复一次又一次就像对自己说一样。引用已经打开但是未关闭。可以有个更好的结果但需要额外的空间来提高。

23.5 提高性能的额外想法

下面是一些需要验证的想法可以进一步提高模型性能:

  • 给定一个随机种子,预测少于1000个字符作出输出。
  • 从源文件中移除标点符号,所以也从模型的词汇中移除。
  • 对输入序列尝试使用one hot编码。
  • 在填充的句子上训练而不死随机字符序列。
  • 增加训练周期到100或者更多。
  • 在显示层加dropout并考虑调整dropout的百分比。
  • 调接批处理大小,用批处理为1的作为基准,尝试更大的批处理。
  • 增加更多的记忆单元到层中或者增加更多层。
  • 当解释预测概率时,用规模因素来实验。
  • 改变LSTM层为有状态的用于保存跨批处理的状态。

23.6 总结

在这个项目中,你已经学写了如何用Keras构建一个LSTM循环神经网络用于文本生成,完成之后你已经了解:

  • 在哪免费下载ASCII格式的经典书籍用于训练。
  • 如何在文本序列上训练LSTM网络以及如何使用已训练的网络生成新序列。
  • 如何开发stacked LSTM网络并提高模型的性能。
  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

技术人Howzit

钱不钱的无所谓,这是一种鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值