堆叠多个 LSTM 层
正如我们可以增加神经网络或 CNN 的深度,我们可以增加 RNN 网络的深度。在这个秘籍中,我们应用了一个三层深度的 LSTM 来改进我们的莎士比亚语言生成。
做好准备
我们可以通过将它们叠加在一起来增加循环神经网络的深度。从本质上讲,我们将获取目标输出并将其输入另一个网络。
要了解这对于两层的工作原理,请参见下图:
图 5:在上图中,我们扩展了单层 RNN,使它们具有两层。对于原始的单层版本,请参阅上一章简介中的绘图。左侧架构说明了使用多层 RNN 预测输出序列中的一个输出的方法。正确的架构显示了使用多层 RNN 预测输出序列的方法,该输出序列使用输出作为输入
TensorFlow 允许使用MultiRNNCell()
函数轻松实现多个层,该函数接受 RNN 单元列表。有了这种行为,很容易用MultiRNNCell([rnn_cell(num_units) for n in num_layers])
单元格从 Python 中的一个单元格创建多层 RNN。
对于这个秘籍,我们将执行我们在之前的秘籍中执行的相同的莎士比亚预测。将有两个变化:第一个变化将是具有三个堆叠的 LSTM 模型而不是仅一个层,第二个变化将是进行字符级预测而不是单词。进行字符级预测会将我们潜在的词汇量大大减少到只有 40 个字符(26 个字母,10 个数字,1 个空格和 3 个特殊字符)。
操作步骤
我们将说明本节中的代码与上一节的不同之处,而不是重新使用所有相同的代码。有关完整代码,请参阅 https://github.com/nfmcclure/tensorflow_cookbook 上的 GitHub 仓库或 https://github.com/PacktPublishing/TensorFlow-Machine-的 Packt 仓库 Learning-Cookbook-Second-Edition 。
- 我们首先需要设置模型的层数。我们将此作为参数放在脚本的开头,并使用其他模型参数:
num_layers = 3
min_word_freq = 5
rnn_size = 128
epochs = 10
- 第一个主要变化是我们将按字符加载,处理和提供文本,而不是按字词加载。为了实现这一点,在清理文本之后,我们可以使用 Python 的
list()
命令逐个字符地分隔整个文本:
s_text = re.sub(r'[{}]'.format(punctuation), ' ', s_text)
s_text = re.sub('s+', ' ', s_text ).strip().lower()
# Split up by characters
char_list = list(s_text)
- 我们现在需要更改 LSTM 模型,使其具有多个层。我们接受
num_layers
变量并使用 TensorFlow 的MultiRNNCell()
函数创建一个多层 RNN 模型,如下所示:
class LSTM_Model():
def __init__(self, rnn_size, num_layers, batch_size, learning_rate,
training_seq_len, vocab_size, infer_sample=False):
self.rnn_size = rnn_size
self.num_layers = num_layers
self.vocab_size = vocab_size
self.infer_sample = infer_sample
self.learning_rate = learning_rate
...
self.lstm_cell = tf.contrib.rnn.BasicLSTMCell(rnn_size)
self.lstm_cell = tf.contrib.rnn.MultiRNNCell([self.lstm_cell for _ in range(self.num_layers)])
self.initial_state = self.lstm_cell.zero_state(self.batch_size, tf.float32)
self.x_data = tf.placeholder(tf.int32, [self.batch_size, self.training_seq_len])
self.y_output = tf.placeholder(tf.int32, [self.batch_size, self.training_seq_len])
请注意,TensorFlow 的
MultiRNNCell()
函数接受 RNN 单元列表。在这个项目中,RNN 层都是相同的,但您可以列出您希望堆叠在一起的任何 RNN 层。
- 其他一切基本相同。在这里,我们可以看到一些训练输出:
Building Shakespeare Vocab by Characters
Vocabulary Length = 40
Starting Epoch #1 of 10
Iteration: 9430, Epoch: 10, Batch: 889 out of 950, Loss: 1.54
Iteration: 9440, Epoch: 10, Batch: 899 out of 950, Loss: 1.46
Iteration: 9450, Epoch: 10, Batch: 909 out of 950, Loss: 1.49
thou art more than the
to be or not to the serva
wherefore art thou dost thou
Iteration: 9460, Epoch: 10, Batch: 919 out of 950, Loss: 1.41
Iteration: 9470, Epoch: 10, Batch: 929 out of 950, Loss: 1.45
Iteration: 9480, Epoch: 10, Batch: 939 out of 950, Loss: 1.59
Iteration: 9490, Epoch: 10, Batch: 949 out of 950, Loss: 1.42
- 以下是最终文本输出的示例:
thou art more fancy with to be or not to be for be wherefore art thou art thou
- 最后,以下是我们如何绘制几代的训练损失:
plt.plot(train_loss, 'k-')
plt.title('Sequence to Sequence Loss')
plt.xlabel('Generation')
plt.ylabel('Loss')
plt.show()
图 6:多层 LSTM 莎士比亚模型的训练损失与世代的关系图
工作原理
TensorFlow 只需一个 RNN 单元列表即可轻松将 RNN 层扩展到多个层。对于这个秘籍,我们使用与上一个秘籍相同的莎士比亚数据,但是用字符而不是单词处理它。我们通过三层 LSTM 模型来生成莎士比亚文本。我们可以看到,在仅仅 10 个周期之后,我们就能够以文字的形式产生古老的英语。