RNN and LSTM
学习如何使用RNN来预测和序列处理。
循环神经网络除了用于预测模型(做出预测)之外,他们还可以学习问题的序列,然后为问题域生成全新的合理序列。
初次尝试将问题分解为三个子问题。
- 1.下载一个免费的文本语料库,您可以使用它来训练文本生成模型
- 2.如何将文本序列的问题构建成循环神经网络生成模型
- 3.如何开发一个LSTM来为给定的问题生成合理的文本序列
实验利用[爱丽丝梦游仙境]全书作为实验数据,没有测试数据。(https://www.gutenberg.org/ebooks/11)
导入数据
load ascii text and covert to lowercase
filename = "wonderland.txt"
raw_text = open(filename).read()
raw_text = raw_text.lower()`
插入说一下read(),readline(),readlines()三个函数的区别
- read 一次性读取所有文件,将所有文件放到一个字符串变量里
- readline 每次讲一行读入内存,速度较慢(未比较)
readlines 读取时将所有文件一次性读取,然后按行解析成列表,一般读取时用这个
导入数据之后首先lower()一下,因为后面生成的时候我们没有在意英文的首字母语法,这个有待改进。
数据预处理
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))
n_chars = len(raw_text)
n_vocab = len(chars)
- 首先获取全部字符的set,然后做两个dict方便后面向量化,一个char2int,一个int2char,这个之后每个字符对应一个整数。
- 接着获取全文字符数和set后的字符数,大约一个在15W一个在50左右。
- 之后,做字符的向量化过程,因为字符是不能够之间拉入LSTM中训练的,我们预设序列长度为100,前100个数据没有输出,则有15W减去100个训练数据,将他们用char2int转换成向量形式。
首先,我们必须将输入序列列表变换为LSTM网络预期的[样本,时间步长,特征]。接下来,我们需要将整数重新缩放到0到1的范围,以使缺省情况下使用Sigmoid激活功能的LSTM网络更容易学习模式。
reshape()dataX为预期的张量形式,用utils中的to_categorical将labelY从类别向量(从0到nb_classes的整数向量)映射为二值类别矩阵
# 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))
搭建网络
- LSTM(input_shape=(100,1) ,output = 256)
- DropOut(0.2)
- Dense(256,vocabNum(大约在50))
编译之后把最好的weight用该回调函数将在每个epoch后保存模型到filepath。误差用的交叉熵,adam优化方法。误差大约在1.9-2.9之间
模型代码
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')
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True, mode='min')
callbacks_list = [checkpoint]
model.fit(X, y, nb_epoch=20, batch_size=128, callbacks=callbacks_list)
生成预测文本
首先给一个种子序列作为输入,可以random随机给种子。然后把序列转化为[样本,时间步长,特征]形式,这点非常重要!非常重要!非常重要!下面是生成代码:
# 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的初次尝试,一开始在网络输入上摸不到头脑,把序列问题当成了一般的分类做了处理,没有考虑到张量的问题。每个数据都有固定的序列。估计程序还是要跑好久。下面说下问题:
- 生成的文本学习不到语法
- 有大量单词没有无效单词
- 有没有可能做成中文文本生成
- 时间效率太低