个基于TensorFlow的简单故事生成案例:带你了解LSTM

深度学习中,循环神经网络 (RNN) 是一组擅长从序列数据中学习的神经网络。长短期记忆(LSTM)是一类循环神经网络,由于其对长期依赖问题的鲁棒性,已经找到了实际应用。LSTM方面有大量的文章和文献,其中推荐以下两篇:

有很多很棒的库可以帮助您构建基于 LSTM 的机器学习应用程序。在撰写本文时, 的明星已超过 50,000 次,表明它在机器学习从业者中的受欢迎程度。

相比之下,似乎相对缺乏关于如何基于 LSTM 构建可理解的应用程序的良好文档和示例,这正是本文试图解决的问题。

假设我们想使用一个短篇小说样本来训练一个 LSTM 来预测下一个单词 Aesop’s :

很久以前,老鼠有一种可以拿来对付敌人猫的东西。有人这么说,有人这么说,但最后一只小老鼠站了起来,说他有一个要做,他会遇到这个案子。你们都会同意的,他说,我们的首领在狡猾而敌人在我们当中。现在,如果我们可以从她那里得到一些,我们就可以从她那里得到。我,,,给那一只小铃铛,绕着猫的脖子。通过这种方式我们知道她什么时候在,并且可以在她在的时候。这一次见了面,直到一只老老鼠起身说,一切都很好,可是谁来给猫铃铛呢?老鼠们一齐说话。然后老老鼠说很容易。

1. 取自伊索寓言的短篇小说,有 112 个不同的符号。单词和标点符号都被视为符号。

如果我们将文本中的 3 个符号以正确的顺序输入 LSTM,并以 1 个标记符号作为输出,最终神经网络将学会正确预测下一个符号 ( )。

图片[1]-个基于TensorFlow的简单故事生成案例:带你了解LSTM-唐朝资源网

图 1. 具有 3 个输入和 1 个输出的 LSTM 单元

严格来说,LSTM 只能理解输入的实数。将符号转换为数字的一种方法是根据每个符号出现的频率为每个符号分配一个相应的整数。例如,上面的短文本中有 112 个不同的符号。清单 2 中所示的函数构建了一个字典,其中包含以下条目 [“,”: 0 ] [“the”: 1 ], …, [“”: 37 ],…,[“spoke” = 111 ]。为了解码 LSTM 的输出,还生成了一个反向字典。

def build_dataset(words):
   count = collections.Counter(words).most_common()
   dictionary = dict()
   for word, _ in count:
       dictionary[word] = len(dictionary)
   reverse_dictionary = dict(zip(dictionary.values(), dictionary.keys()))
   return dictionary, reverse_dictionary

2.建字典和反转字典的功能

类似地,预测值也是与预测符号在逆字典中的索引对应的唯一整数值​​。例如:如果预测值为37,则预测符号为“”。

输出生成看似简单,但实际上 LSTM 为下一个符号生成一个 112 元素的预测概率向量,并使用 () 函数进行归一化。具有最高概率值的元素的索引是预测符号在逆向字典中的索引(例如,单热向量)。图 2 显示了这个过程。

图 2. 每个输入符号都被分配给它的唯一整数值​​替换。输出是一个单热向量,指示反向字典中预测符号的索引。

LSTM 模型是这个应用程序的核心部分。令人惊讶的是,它很容易实现:

def RNN(x, weights, biases):

   # reshape to [1, n_input]
   
x = tf.reshape(x, [-1, n_input])

   # Generate a n_input-element sequence of inputs
   # (eg. [had] [a] [general] -> [20] [6] [33])
   
x = tf.split(x,n_input,1)

   # 1-layer LSTM with n_hidden units.
   
rnn_cell = rnn.BasicLSTMCell(n_hidden)

   # generate prediction
   
outputs, states = rnn.static_rnn(rnn_cell, x, dtype=tf.float32)

   # there are n_input outputs but
   # we only want the last output
   
return tf.matmul(outputs[-1], weights['out']) + biases['out']

3. 512个LSTM单元的网络模型

最难的部分是以正确的格式和顺序获取输入。在这个例子中,LSTM 的输入是 3 个整数的序列(例如:1×3 整数向量)

网络的常数、权重和偏差设置如下:

vocab_size = len(dictionary)
n_input = 3

# number of units in RNN cell
n_hidden = 512

# RNN output node weights and biases
weights = {
   'out': tf.Variable(tf.random_normal([n_hidden, vocab_size]))
}
biases = {
   'out': tf.Variable(tf.random_normal([vocab_size]))
}

4. 常数和训练参数

在训练过程的每一步,都会在训练数据中检索 3 个符号。然后将 3 个符号转换为整数以形成输入向量。

symbols_in_keys = [ [dictionary[ str(training_data[i])]] for i in range(offset, offset+n_input) ]

. 将符号转换为整数向量作为输入

训练标签是跟随 3 个输入符号的 one-hot 向量。

symbols_out_onehot = np.zeros([vocab_size], dtype=float)
symbols_out_onehot[dictionary[str(training_data[offset+n_input])]] = 1.0

6. 单向量作为标签

转换为输入字典的格式后,进行如下优化过程:

_, acc, loss, onehot_pred = session.run([optimizer, accuracy, cost, pred], feed_dict={x: symbols_in_keys, y: symbols_out_onehot})

7. 训练过程中的优化

累积准确度和损失以监控训练过程。通常 50,000 次迭代足以达到可接受的精度要求。

...
Iter= 49000, Average Loss= 0.528684, Average Accuracy= 88.50%
['could', 'easily', 'retire'] - [while] vs [while]
Iter= 50000, Average Loss= 0.415811, Average Accuracy= 91.20%
['this', 'means', 'we'] - [should] vs [should]

8. 一个训练区间的预测和准确率数据示例(相隔 1000 步)

代价是标签和 () 预测之间的交叉熵,使用 0.001 的学习率进行优化。在本例中,它的性能通常优于 Adam 和 SGD。

pred = RNN(x, weights, biases)

# Loss and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))
optimizer = tf.train.RMSPropOptimizer(learning_rate=learning_rate).minimize(cost)

9.损失和优化器

通过添加层可以提高 LSTM 的准确性。

rnn_cell = rnn.MultiRNNCell([rnn.BasicLSTMCell(n_hidden),rnn.BasicLSTMCell(n_hidden)])

10. 改进的 LSTM

现在,到有趣的部分。让我们通过将预测输出作为输入中的下一个符号提供给 LSTM 来生成一个故事。示例输入是“had a”,LSTM 给出了正确的输出预测“”。然后将“”作为新输入“a”的一部分输入神经网络,以获得下一个输出“to”,依此类推。令人惊讶的是,LSTM 创造了一个具有某种意义的故事。

had a general council to consider what measures they could take to outwit their common enemy , the cat . some said this , and some said that but at last a young mouse got

11.样本故事生成的故事中前32个预测值被截断

如果我们输入另一个序列(例如:“mouse”、“mouse”、“mouse”)但不一定是这个故事中的序列,那么会自动生成另一个故事。

mouse mouse mouse , neighbourhood and could receive a outwit always the neck of the cat . some said this , and some said that but at last a young mouse got up and said

12. 不是从示例故事中的输入序列导出的

示例代码可以在这里找到:

示例文本的链接在这里:

提示:

1. 用整数值编码符号很容易操作但失去了单词的意义。本文中符号到整数值的转换用于简化关于构建 LSTM 应用程序的讨论。更推荐将符号编码为向量。

2. 将输出表示为单个向量效率较低,尤其是当我们有一个实际的字长时。牛津词典有超过 170,000 个单词,而上面的示例只有 112 个单词。同样,本文中的示例只是为了简化讨论。

3. 这里使用的代码灵感来自 – :

4. 本例中的输入大小为 3,看看使用其他大小的输入(例如 4、5 或更大)时会发生什么情况。

5. 每次运行代码可能会产生不同的结果,LSTM 的预测能力也会有所不同。这是因为精度取决于初始参数的随机设置。训练次数越高(超过 150,000 次),准确率也会相应提高。每次运行代码,创建的字典都会不同

6. 在调试中很有用,尤其是在检查代码是否正确构建图形时。

7. 尝试用另一个故事测试 LSTM,尤其是用另一种语言编写的故事。

© 版权声明
THE END
喜欢就支持一下吧
点赞15赞赏 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容