这篇博客的写作过程参考了《Keras深度学习实战》这本书,写作的目的在于将最近学到的关于循环神经网络的内容,尤其是关于其实现的部分进行总结,博客仅供学术交流之用,谢谢。
循环神经网络(Recurrent Neural Networks, RNN)是一类利用了输入数据的序列化特性的神经网络。序列化输入可以是文本、语音、时间序列或者任意其元素的出现依赖于它之前元素的序列。
RNN被广泛应用于自然语言处理领域,其中一种应用是构建语言模型。语言模型允许我们根据文本给定的前置词预测下一个词出现的概率,这对很多高级任务如机器翻译、拼写更正等都很重要。这种根据给定的前置词预测下一个词的能力的附带产物是生成模型,这种模型允许我们通过从输入概率中取样来生成文本。在语言建模中,输入通常是单词的序列,输出是预测的单词的序列。
下面要介绍的用Keras实现SimpleRNN的例子是《Keras深度学习实战》中第六章循环神经网络–RNN中的第一个例子,要处理的任务是生成文本,即给出一段文本,生成后续的固定长度的文本。下面以具体的代码+注释的形式介绍本任务。
1 数据
本实验使用的文本数据是古藤保项目网站中爱丽丝梦游仙境的文本。
2 具体程序注解
2.1 导入需要用到的模块
from __future__ import print_function
from keras.layers import Dense, Activation
from keras.layers.recurrent import SimpleRNN
from keras.models import Sequential
import numpy as np
2.2 读取文件,并将文件内容解码为ASCII码
# 读取文件,并将文件内容解码为ASCII码
fin = open('alice_in_wonderland.txt', 'rb')
lines = [] #
for line in fin: # 遍历每行数据
line = line.strip().lower() # 去除每行两端空格
line = line.decode('ascii', 'ignore') # 解码为ASCII码
if len(line) == 0:
continue
lines.append(line)
fin.close()
text = ' '.join(lines)
2.3 构建字符到索引之间的映射关系
chars = set([c for c in text]) # 获取字符串中不同字符组成的集合
nb_chars = len(chars) # 获取集合中不同元素数量
char2index = dict((c, i) for i, c in enumerate(chars)) # 创建字符到索引的字典
index2char = dict((i, c) for i, c in enumerate(chars)) # 创建索引到字符的字典
2.4 创建标签和输入文本
SEQLEN = 10 # 超参数,输入字符串长度
STEP = 1 # 输出字符串长度
input_chars = [] # 输入字符串列表
label_chars = [] # 标签列表
for i in range(0, len(text) - SEQLEN, STEP):
input_chars.append(text[i: i + SEQLEN])
label_chars.append(text[i + SEQLEN])
2.5 将输入和标签文本向量化
# 将输入文本和标签文本向量化: one-hot编码
X = np.zeros((len(input_chars), SEQLEN, nb_chars), dtype=np.bool) # 输入文本张量
Y = np.zeros((len(input_chars), nb_chars), dtype=np.bool) # 标签文本张量
for i, input_char in enumerate(input_chars): # 遍历所有输入样本
for j, ch in enumerate(input_char): # 对于每个输入样本
X[i, j, char2index[ch]] = 1
Y[i, char2index[label_chars[i]]] = 1
2.6 构建网络
# 构建模型
HIDDEN_SIZE = 128
BATCH_SIZE = 128
NUM_ITERATIONS = 25
NUM_EPOCH_PER_ITERATIONS = 1
NUM_PREDS_PER_EPOCH = 100
model = Sequential()
model.add(SimpleRNN(HIDDEN_SIZE, return_sequences=False, input_shape=(SEQLEN, nb_chars), unroll=True))
model.add(Dense(nb_chars))
model.add(Activation('softmax'))
2.7 编译及训练模型
# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
for iteration in range(NUM_ITERATIONS):
print('=' * 50)
print('Iteration #: %d' % (iteration)) # 打印迭代次数
# 训练模型
model.fit(X, Y, batch_size=BATCH_SIZE, epochs=NUM_EPOCH_PER_ITERATIONS) # 每次迭代训练一个周期
# 使用模型进行预测
test_idx = np.random.randint(len(input_chars)) # 随机抽取样本
test_chars = input_chars[test_idx]
print('Generating from seed: %s' % (test_chars))
print(test_chars, end='') # 不换行输出
for i in range(NUM_PREDS_PER_EPOCH): # 评估每一次迭代后的结果
Xtest = np.zeros((1, SEQLEN, nb_chars))
for i, ch in enumerate(test_chars):
Xtest[0, i, char2index[ch]] = 1 # 样本张量
# pred = model.predict(Xtest, verbose=0)[0]
# ypred = index2char[np.argmax(pred)] # 找对类别标签对应的字符
ypred = index2char[model.predict_classes(Xtest)[0]]
print(ypred, end='')
# 使用test_chars + ypred继续
test_chars = test_chars[1:] + ypred
print()
结果截图如下:
欢迎交流! QQ:3408649893