NLP学习笔记(七)神经网络机器翻译(NMT)

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战」。

导语

本文为我之前在CSDN平台上的一篇博客记录。原链接为:NLP学习笔记(七)神经网络机器翻译(NMT)

神经网络机器翻译(Neural Machine Translation)

这节课我们利用RNN来做机器翻译,机器翻译模型有很多种,这节课我们介绍Seq2Seq模型,把英文翻译为德文。机器翻译是一个Many to Many的问题。

在这里插入图片描述

首先,我们要处理数据。

机器翻译数据(Machine Translation Data)

这里,我们仅是学习需要,使用一个小规模数据集即可。如图所示,文件有两栏,左边是英语句子,右边是德语句子。一个英语句子对应了多个德语句子。给定一句英语,如果翻译可以完全匹配到其中一个,那么就认为翻译完全正确。 在这里插入图片描述 我们首先要预处理数据,包括:大写变小写、去掉标点符号等等。

在这里插入图片描述

在预处理之后,我们做分词(Tokenization),把一句话变成很多个单词或字符等。需要注意的是,做Tokenization时需要用两个不同的Tokenizer。经过Tokenization后建立两个字典。

Tokenization可以是字符级别(character-level)和单词级别(word-level)的。本节课为了简单起见使用字符级别,实际系统中由于训练数据集很大,基本都是单词级别的。

在这里插入图片描述

在这里插入图片描述

至于为什么要用两个不同的Tokenizer,也很好理解。在字符层面上,不同的语言通常有不同的字母表,两种语言的字符通常是不同的,所以应该用两个不同的词汇表。如果是单词级别,则就更应该如此了。此外,不同的语言还有不同的分词方法。

在这里插入图片描述 使用Keras提供的库做Tokenization,结束后自动生成了字典。左边是英语字典,26个字母加一个空格符号。右边是德语字典,26个字母和一个空格符,同时添加了两个特殊符号,一个是起始符,一个是中止符,这里用\t做起始符,\n做中止符,(注:用什么字符做都可以,只要不与字典里已有的字符冲突就可以) 在这里插入图片描述

这样之后,一句英语句子就变成了一个字符列表,然后用字典映射成一个数字的列表。 在这里插入图片描述 一句德语句子也是这样。 在这里插入图片描述

做完One-hot encoding后,一个字符用一个One-hot向量表示,一个句子就用一个矩阵表示。然后,我们把这些One-hot向量拼接起来,作为一个矩阵输入到RNN中。 在这里插入图片描述

Seq2seq Model

数据已经准备好了,接下来我们要搭建一个seq2seq模型并训练它。

在这里插入图片描述

seq2seq模型由一个编码器和一个解码器构成。编码器Encoder是一个RNN或LSTM等,用于从输入的句子中提取特征。Encoder最后一个状态就是从句子中提取的特征,包含这句话的信息。Encoder其余的状态没有用,都被丢掉了。Encoder的输出是LSTM最后一个状态h和传输带c。

在这里插入图片描述

seq2seq模型还有一个解码器Decoder用于生成德语。这个Decoder其实就是上篇博客中讲到的文本生成器。它跟上节课文本生成器的唯一区别在于初始状态,上节课的初始向量是个全零向量,而这里则是LSTM的最后一个状态h和c。Encoder通过这个向量来概括英语句子,Decoder通过这个向量来知道英语的意思是'go away'。 在这里插入图片描述

第一个输入是起始符\t,Decoder会输出一个概率分别记作向量p。起始符后面一个字符就是要输出的字符label,我们拿这个label的One-hot向量y和p来计算损失函数。我们希望标签p尽量接近标签y,损失越小越好。有了损失函数,就可以反向传播计算梯度,梯度会从损失函数传到Decoder,然后再从Decoder传到Encoder,然后用梯度下降来更新Encoder和Decoder的参数。让损失函数值减小。

在这里插入图片描述

然后将\tm作为输入,字符a作为label继续计算loss,以此类推,不断重复这个过程,知道最后一个字符出来后,将整句作为输入,停止符\n作为label。不断重复这个过程,拿所有的(英语-德语)二元组来进行训练。

其Keras结构如下: 在这里插入图片描述 如图,Encoder网络的输入是一个One-hot encoding,用一个矩阵表示。Encoder网络有一层或多层LSTM,用于从英文句子里提取特征,LSTM的输出是最终的状态h和传送带c,Decoder网络的初始状态时h和c,这样可以让Encoder和Decoder连起来,Decoder的输入是德语的上半句话,Decoder输出当前状态h,然后全连接层输出对下一个字符的预测。 在这里插入图片描述

使用Seq2seq模型进行推断(Inference Using the Seq2Seq Model)

训练好了seq2seq模型后,我们可以拿它把英语翻译成德语。把一句英语的每个字符输入Encoder,Encoder会在状态h和c中积累这句话的信息。Encoder输出最后的状态,记作 h 0 h_0 c 0 c_0 ,它们是从这句话里提取的特征,送给Decoder。

在这里插入图片描述

Encoder的输出 h 0 h_0 c 0 c_0 被作为Decoder的初始状态。这样一来,Decoder就知道输入的句子是“go away”,现在Decoder就跟上节课讲的文本生成器一样工作。首先把起始符输入Decoder,有了新的输入,Decoder就会更新状态h和传输带c,并且预测下一个字符。Decoder输出的预测是每个字符的概率值,我们要根据概率值来选取一个字符。可以选取概率最大的字符,也可以根据概率值做随机抽样。假设我得到字符“m”,于是我把“m”记录下来。

在这里插入图片描述

现在。Decoder的状态成为了 h 1 h_1 c 1 c_1 ,字符“m”作为输入,让LSTM来预测下一个字符。基于状态 h 1 h_1 c 1 c_1 以及新的输入“m”,LSTM会更新状态为 h 2 h_2 c 2 c_2 ,并且输出一个概率分布。根据概率分布抽样,我们可能得到字符“a”。把字符“a”给记录下来。

在这里插入图片描述

然后继续重复以上过程,不断的更新状态和生成记录新的字符,然后用新生成的字符作为下一轮的输入。

在这里插入图片描述 运行到最后,我们就可以得到最终的输出,即为翻译得到的德语。 在这里插入图片描述

总结(Summary)

这节课我么讲了用Seq2seq模型做机器翻译,模型有一个Encoder网络和一个Decoder网络。在本节课的示例中,Encoder的输入是一句英语,每输入一个字符,RNN就会更新状态,把积累的信息放到状态里。Encoder最后一个状态就是从英文句子里提取的特征。Encoder只输出最后一个状态,会扔掉之前所有的状态。把最后一个状态传递给Decoder网络,把Encoder网络的最后一个状态作为Decoder网络的初始状态。 在这里插入图片描述

初始化之后,Decoder就知道输入的英文句子了,然后Decoder就作为一个文本生成器,生成一句德语。

在这里插入图片描述

首先把起始符作为RNN的输入。Decoder RNN会更新状态为 s 1 s_1 ,然后全连接层会输出预测的概率,记为 p 1 p_1 。根据概率分布做抽样得到下一个字符 z 1 z_1 在这里插入图片描述

Decoder网络拿 z 1 z_1 做输入,更新状态为 s 2 s_2 ,然后全连接层会输出预测的概率,记为 p 2 p_2 。根据概率分布做抽样得到下一个字符 z 2 z_2 在这里插入图片描述

然后以此类推,不停重复这个过程,直到输出停止符,终止文本生成,返回这个生成的序列。我们设计了一个Seq2seq模型,它的Encoder和Decoder都是LSTM。那么,我们可以如何改进这个模型呢?

Seq2seq模型的原理是这样的,输入的信息放入Encoder,把信息都压缩到状态向量里面,Encoder最后一个状态是整句话的一个概要。理想情况下,Encoder最后一个状态包含整句英语的完整信息。假如英语句子很长,那么前面的信息就很可能被遗忘。 在这里插入图片描述

一种很显而易见的改进就是在Encoder端用双向LSTM。Decoder是一个文本生成器,必须是单向的。 在这里插入图片描述

这节课为了简便起见使用了字符级别,但更好的方式是使用单词级别。英语中每个单词平均有4.5个字符,那么输入的序列就能短4.5倍。序列更短就更不容易被遗忘。

但是,使用word级别的话就必须要有大的数据集,必须用word embedding得到低维词向量。Embedding层的参数太多了,用小数据集没有办法很好的训练。 或者对Embedding层做预训练。 在这里插入图片描述

另一种方法是多任务学习。比如原来只是英语句子翻译成德语,现在可以新增一个把英语句子翻译成英语的,这样一来训练数据多了一倍,Encoder可以被训练的更好。还可以添加其他很多任务,有英文翻译成其他语言的数据集。

但是Encoder只有一个,所以Encoder被多训练了很多倍,尽管Decoder没有改进,但效果还是会提升。 在这里插入图片描述

还有一种方法叫Attention,这个方法是最强的,对机器翻译的提高非常大,我们下节课再讲。

猜你喜欢

转载自juejin.im/post/7066609417902358559