这是我参与更文挑战的第15天,活动详情查看: 更文挑战
RNN 模型的多种结果
使用 RNN 搭建的模型由于输入和输出的不同,可以分为多种类型的机构,不同的结构可以应用到不同的任务中。
如上图所示,一般有四种结构
- one to one 中输入是一个 vector ,输出也是一个 vector 结果的结构,例如输入一个图片,然后输出一个预测的类别。
- one to many 中输入是一个 vector ,输出是多个 vector 结果的结构,这种结构可用于为一张输入的图片用文字描述图片中的场景。
- many to one 是输入是多个 vector ,输出是一个 vector 结果的结构,这种结构可用于文本情感分析,输入一个文本,判断是消极还是积极情感。
- many to many 是输入是多个 vector ,输出是多个 vector 结果的结构,这种结构可用于机器翻译或聊天对话场景。
- 同步 many to many 和上一个结构类似,但是它是经典的 rnn 结构,前一输入的状态会带到下一个状态中,而且每个输入都会对应一个输出,我们最熟悉的就是用于字符预测了,同样也可以用于视频分类,对视频的帧打标签。
Seq2Seq
机器翻译是一个多对多的问题,这里以把法语翻译成英语的任务为例子,输入的法语单词数量不固定的句子,输出的英语单词数量也是不固定的。虽然有很多种机器翻译模型,但是最经典的就是 Seq2Seq 模型,它也是一种 many to many 的结构。
训练过程
Seq2Seq 模型主要分为两部分,左边有一个 Encoder 编码器,右边还有一个 Decoder 解码器。
-
Encoder 是 LSTM 或者其他 RNN 及其变体,用来从输入的法语句子中提取特征,Encoder 的输出是 LSTM 最后时刻的状态向量 h 和细胞状态 c ,其他时刻的输出都没有用到,所以图中没有显示。
-
Decoder 也是 LSTM 或者其他 RNN 及其变体,用来将法语翻译成英语,它和上篇文章中所讲到的文本生成原理基本相同,唯一不同的地方就是上篇文章中的文本生成的初始状态是全 0 向量,但是 Decoder 的初始状态是 Encoder 的最后时刻输出的状态向量 h 。解码的过程如下:
a)Decoder 通过拿到 Encoder 输出的最后时刻的状态向量 h 可以知道输入的文本内容。
b)开始输入第一个单词开始训练,Decoder 的第一个输入必须是起始符号,设置 Decoder 的起始符号为 “<START>” (任意其他不存在于当前字典的字符串都可以)表示开始翻译,此时 Decoder 有了初始向量)h 和当前时刻的输入 “<START>”,Decoder 会输出一个预测单词概率分布,由于我们已知了下一时刻的输入为 “the”,所以用下一时刻的输入作为标签,我们要训练模型使当前时刻的 Decoder 输出与标签的损失值越小越好。
c)有了损失函数,我们就可以反向传播梯度,梯度会从损失函数传递到 Decoder ,然后从 Decoder 传递到 Encoder ,然后用梯度下降来更新 Encoder 和 Decoder 的参数。
d)然后输入第二个单词开始训练,此时的输入为已有的两个单词 “<START>” 和 “the” ,Decoder 会输出对第二个单词的预测的单词概率分布,我们已知下一个时刻的单词为 “poor” ,用它来做标签,所以我们要使当前时刻的 Decoder 的输出与标签的损失值越小越好。
e)继续反向传播,更新 Encoder 和 Decoder 的参数。
f)然后输入第三个单词开始训练,与上面的类似,此时的输入为已有的三个单词 “<START>” 、 “the” 和 “poor” ,Decoder 会输出对第三个单词的预测的单词概率分布,我们已知下一个时刻的单词为 “don‘t” ,用它来做标签,所以我们要使当前时刻的 Decoder 的输出与标签的损失值越小越好。
g)继续反向传播,更新 Encoder 和 Decoder 的参数。
h)重复以上过程,直到最后一个时刻,此时将整句“ the poor don't have any money”作为当前时刻的输入,此时我们已经没有了下一时刻的内容,所以我们定义现在已经翻译结束,用“<END>” 作为标签,所以我们要使当前时刻的 Decoder 的输出与标签的损失值越小越好。
i)继续反向传播,更新 Encoder 和 Decoder 的参数。
j)使用大量的法语和英语的二元组合数据来训练这个模型
预测过程
当模型训练好之后,我们可以用来进行翻译,我们假如现在有法语 “les pauvres sont demunis”,要翻译成英语过程和训练原理类似。流程如下:
a)将法语的每个单词输入到 Encoder 中,将特征积累到最后一个时刻的特征向量 h 中,并将其传输到 Decoder 作为其初始状态。
b)预测第一个单词,Decoder 做的工作和上篇文章所说的文本生成一样,我们将和初始状态 h 和起始单词 “<START>” 输入到 Decoder 中,Decoder 会输出当前时刻的状态向量 h0 ,以及单词概率分布,此时我们可以选取概率最大的单词,也可以根据概率值进行随机抽样,不管用哪种方式,我们现在得到了预测的单词,假如模型是有效的,此时的预测出的单词应该为 “the” ,当然如果模型不准,可能会预测成其他单词。
c)预测第二个单词,我们将上一个时刻得到的状态向量 h0 和预测到的单词 “the” 输入到 Decoder ,Decoder 会生成当前的状态向量 h1 以及单词概率分布,可以用上面的方法,选取概率最大单词或者根据概率抽样的到的单词作为当前的预测结果,假如我们模型有效,此时应该会预测为 “poor”,如果模型无效,则可能预测称为其他单词。
d)预测第三个单词,我们将上一个时刻得到的状态向量 h1 和预测到的单词 “poor” 输入到 Decoder ,Decoder 会生成当前的状态向量 h2 以及单词概率分布,可以用上面的方法,选取概率最大单词或者根据概率抽样的到的单词作为当前的预测结果,假如我们模型有效,此时应该会预测为 “don't”,如果模型无效,则可能预测称为其他单词。
e)不断重复上述过程,直到最后我们将上一个时刻得到的状态向量 h5 和预测到的单词 “money” 输入到 Decoder ,Decoder 会生成当前的状态向量 h6 以及单词概率分布,可以用上面的方法,选取概率最大单词或者根据概率抽样的到的单词作为当前的预测结果,假如我们模型有效,此时应该会预测为 “<END>”,表示我们的翻译过程结束。此时我们的翻译输出结果为 “the poor don't have any money </END>” ,因为我们定义的"</END>"只是个标识翻译结束的符号,经过整理就的到我们的翻译结果 “the poor don't have any money”。如果模型无效,则可能预测称为其他单词,这时就要继续进行翻译工作。
Encoder 优化技巧一
因为 Encoder 的主要功能就是提取输入的特征,可能有时候输入太长,特征提取效果就会不佳,这时候我们可以用 Bi-LSTM 来代替我们使用的 LSTM 或者 RNN ,这样的 Encoder 会从正向和反向两个方向提取输入特征并积累到最后一个时刻,这时候的特征更加丰富。
【注意】这只是适用于 Encoder ,Decoder 只能是单向的从左往右翻译。
Encoder 优化技巧二
一般情况下我们都用单词作为输入,而不是字符作为输入,因为单词的平均长度为 4 个字符,如果用单词代替字符作为输入,则可以缩短输入的长度近 4 倍,这样也有利用 Encoder 提取特征,不容易遗忘最前面的内容。
但是如果想用单词作为输入,所用的单词如果不超过 100 ,可以使用 one-hot 向量进行表示,但是一般常用单词有几千,此时我们应该用 word embedding 得到低维度词向量。
Embbeding 层的参数太多了,如果不用大数据集进行训练,会出现过拟合现象,或者对 Embedding 层做预训练。
Encoder 优化技巧三
我们还可以充分利用不同语种翻译的相关性,用多任务学习来提升模型性能,我们这里只介绍了法语翻译成英语,我们还可以用这里的 Encoder ,来训练将法语翻译成德语的,用法语翻译成中文,因为不管添加多少个任务,我们的 Encoder 始终是同一个,而训练数据多了两倍,经过训练之后 Encoder 大大被语言逻辑优化,再执行我们的法语翻译英语的任务,效果会有明显提升。
Encoder 优化技巧四
对机器翻译提升最大的方法就是用 Attention 机制,我们在下一篇文章中详细介绍。
案例
这里有我自己实现的小案例,将单词翻译成另一个对立含义的单词,案例简单,只为说明 Seq2Seq 的含义,有详细的注释,觉好留赞哦。 juejin.cn/post/694941…