来源 | Natural Language Processing for Beginners
作者 | AI Publishing
翻译 | 悉尼没睡醒
校对 | gongyouliu
编辑 | auroral-L
全文共2555字,预计阅读时间30分钟。
第十一章 使用 Seq2Seq 模型进行文本翻译
1. 创建 Seq2Seq 训练模型
2. 用 Seq2Seq 作出预测
Seq2Seq模型的理论在第三章的第5节已经解释过了。Seq2seq 模型基于编码器-解码器架构,它学习不同长度的输入和输出句子之间的映射。Seq2seq 模型可用于开发聊天机器人、文本翻译、问答机等。
在本章中,你将看到 Seq2Seq 模型在文本翻译中的应用。所以,让我们开始吧。
1. 创建Seq2Seq 训练模型
Seq2seq 模型通常由两个模型组成。在训练阶段,编码器接收输入句子并将其传送到解码器。在我们的例子中,解码器然后预测输出或翻译的句子。编码器和解码器都是连接的 LSTM 网络。该过程如下图所示。这里,解码器输入的偏移标签是“<s>”,解码器输出的偏移标签是</s>。
编码器的输入是原始语言的句子,在上面的例子中是英语。编码器的输出是隐藏状态和单元状态。解码器的输入是来自编码器的隐藏层和单元状态加上目标数据集(进行一步偏移)。
例如,如果你查看解码器输入,则在第一步中,输入始终是 <s>。第一个时间步的解码器输出是真实翻译的输出词。例如,在上面的例子中,第一个输出词是“Je”。在第二步中,解码器的输入是上一步的隐藏状态和单元状态加上输出句子中的第一个实际单词,即“Je”。将先前输出的真实值作为输入到下一个时间步的过程称为Teacher Forcing。为了阻止解码器在遇到句尾标签时进行预测,所有句子都以句尾标记结束,即上图中的</s>。
让我们对上面的训练模型进行编码。与往常一样,你首先导入所需的库。
接下来,我们需要为基于 LSTM 的编码器和解码器模型以及基于 word2vec 的嵌入层定义一些配置。
由于本章中的脚本是使用 Google Collaboratory 运行的,因此将数据集上传到 Google Drive 然后导入到应用程序中。要将数据集从 Google Drive 导入 Google Collaboratory,请运行以下脚本。
我们将用于训练 seq2seq 模型的数据集可在此链接免费获得:http://www.manythings.org/anki/
转到链接,然后下载 fra-eng.zip 文件。解压缩文件,你应该会看到 fra.txt 文件。该文件包含我们的数据集。该文件也位于 Resources/Datasets 文件夹中。文件的前 10 行如下所示:
fra.txt 文件中的每一行都包含一个英文句子,然后是一个制表符,然后是法语英语句子的翻译,再次是制表符,然后是属性。
我们只对英语和法语句子感兴趣。以下脚本创建三个列表。第一个列表包含所有英语句子,用作编码器输入。第二个列表包含法语中的解码器输入句子,其中偏移量 <sos> 位于所有句子之前。最后,第三个列表包含解码器输出,其中 <eos> 附加在法语每个句子的末尾。
让我们看看我们的数据集中有多少英语和法语句子:
让我们随机打印一个英文句子及其法文翻译(解码器输入和解码器输出)。
你可以看到索引 175 处的句子是“I’m shy.”。在解码器输入中,翻译的句子开头包含 <sos> 标签,而输出包含 <eos> 标签。
接下来,我们需要标记两个输入的英语句子。这是词嵌入之前的强制性步骤。
类似地,以下脚本对输出的法语句子进行标记。
正如我们在前一章中对文本分类所做的那样,我们需要填充我们的输入和输出序列,以便它们具有相同的长度。以下脚本将填充应用于编码器的输入序列。
由于英语句子的最大长度是 6,你可以看到编码器输入句子的形状是 (20000, 6),这意味着所有句子现在都变成了等长的 6。例如,如果你打印索引 175 处句子的填充版本,你会看到 [0, 0, 0, 0, 6,307]。由于实际句子是“I‘m shy”,我们可以打印这些单词的索引,并查看索引 (6, 307) 与索引 175 处的句子的填充序列中的索引匹配。
类似地,以下脚本将填充应用于解码器输入法语句子。
以下脚本将填充应用于解码器输出法语句子。
下一步是为输入和输出句子创建词嵌入。对于输入句子,我们可以使用 Glove 词嵌入,因为句子是英语。以下脚本为Glove向量。
以下脚本创建了一个嵌入矩阵,该矩阵将在嵌入层中用于编码器 LSTM。
以下脚本为编码器 LSTM 创建了一个嵌入层。
下一步是创建解码器嵌入层。第一步是创建一个空的形状嵌入矩阵(输出句子的数量,输出中最长句子的长度,以及输出中唯一词的总数)。
下面的脚本就是这样做的。
下一步是在解码器嵌入矩阵中的那些索引处添加一个,其中一个词存在于原始解码器输入和输出序列中。
以下脚本创建编码器模型.
以下脚本创建解码器模型。你可以看到在解码器模型中,正在使用自定义嵌入层。
以下脚本为我们的 seq2seq 模型创建完整的训练模型。
执行以下脚本显示训练模型。
最后,以下脚本训练模型。
在 20 个 epoch 结束时,达到了大约 79.67 的准确率。
2. 用 Seq2Seq 做出预测
你在上一节中看到了如何训练模型。在本节中,你将看到如何进行预测。下图详细说明了进行预测的过程。
在预测阶段,编码器的输入是原始语言的完整句子,就像编码器一样。
然而,解码器的输入之一是来自编码器的隐藏状态和单元状态。然而,不同于训练阶段,整个目标句子同时作为输入,在第一步的预测期间,单词 <sos> 作为解码器输入。
解码器根据隐藏和单元状态以及第一个词 <sos> 对第一个翻译的词进行预测,即上图中的“suis”。在第二个时间步,解码器的输入是第一个解码器时间步的隐藏状态和单元状态,以及第一个解码器时间步的输出,即“Je”。该过程一直持续到解码器预测 <eos>,这对应于句子的结尾。
以下脚本实现了使用 seq2seq 模型预测将文本从英语翻译成法语的模型。
预测模型通过以下脚本绘制:
预测模型以整数形式进行预测,你需要将整数转换回文本。以下脚本为输入和输出句子创建单词词典的索引。
在下面的脚本中,我们创建了一个“perform_translation()”方法,它接受一个句子的输入序列。编码器对输入序列进行编码,并将隐藏状态和单元状态传递给解码器。解码器的第一个输入是“sos”标签以及来自编码器的隐藏层和单元状态。循环运行最大句子长度这么长的时间单位。
在每次迭代期间,都会进行预测。如果预测词是“<eos>”,则循环终止。否则,使用预测索引,从索引到单词字典中找到实际单词,并将该单词附加到输出句子中。
解码器的索引和隐藏状态和单元状态被更新,新值用于再次使用解码器模型进行预测。以下脚本包含“perform_translation()”函数的代码逻辑。
现在是做出预测的时候了。以下脚本从输入句子序列列表中随机选择一个输入句子。句子序列被传递给“perform_translation()”方法,该方法返回翻译后的法语句子。
输出显示我们的脚本随机选择的句子是“You need sleep”,这句话已经成功翻译成法语“vous avez besoin de sommeil”。
拓展阅读 – Seq2Seq模型
要学习有关 word seq2seq 建模的更多信息,请参阅以下资源:
https://bit.ly/2Y8L9Znhttps://bit.ly/2ZkvmWI。