赞
踩
转载自:https://zhuanlan.zhihu.com/p/194308943
Seq2Seq模型是输出的长度不确定时采用的模型,这种情况一般是在机器翻译的任务中出现,将一句中文翻译成英文,那么这句英文的长度有可能会比中文短,也有可能会比中文长,所以输出的长度就不确定了。
如下图所,输入的中文长度为4,输出的英文长度为2。
在网络结构中,输入一个中文序列,然后输出它对应的中文翻译,输出的部分的结果预测后面,根据上面的例子,也就是先输出“machine”,将"machine"作为下一次的输入,接着输出"learning",这样就能输出任意长的序列。
机器翻译、人机对话、聊天机器人等等,这些都是应用在当今社会都或多或少的运用到了我们这里所说的Seq2Seq。
举个简单的例子,当我们使用机器翻译时:输入(Hello) --->输出(你好)。
再比如在人机对话中,我们问机器:“你是谁?”,机器会返回答案“我是某某某”。
如下图所示为一个简单的邮件对话的场景,发送方问:“你明天是否有空”;接收方回答:“有空,怎么了?”。
seq2seq属于encoder-decoder结构的一种,这里看看常见的encoder-decoder结构,基本思想就是利用两个RNN,一个RNN作为encoder,另一个RNN作为decoder。encoder负责将输入序列压缩成指定长度的向量,这个向量就可以看成是这个序列的语义,这个过程称为编码。
如下图,获取语义向量最简单的方式就是直接将最后一个输入的隐状态作为语义向量C。也可以对最后一个隐含状态做一个变换得到语义向量,还可以将输入序列的所有隐含状态做一个变换得到语义变量。
而decoder则负责根据语义向量生成指定的序列,这个过程也称为解码,如下图,最简单的方式是将encoder得到的语义变量作为初始状态输入到decoder的RNN中,得到输出序列。可以看到上一时刻的输出会作为当前时刻的输入,而且其中语义向量C只作为初始状态参与运算,后面的运算都与语义向量C无关。
decoder处理方式还有另外一种,就是语义向量C参与了序列所有时刻的运算,如下图,上一时刻的输出仍然作为当前时刻的输入,但语义向量C会参与所有时刻的运算。
如上图所示
在Encoder中,“欢迎/来/北京”这些词转换成词向量,也就是Embedding,我们用 v i v_i vi来表示,与上一时刻的隐状态 h t − 1 h_{t-1} ht−1按照时间顺序进行输入,每一个时刻输出一个隐状态 h t h_{t} ht ,我们可以用函数 f f f 表达RNN隐藏层的变换: h t = f ( v i , h t − 1 ) h_t=f(v_i,h_{t-1}) ht=f(vi,ht−1) 。假设有t个词,最终通过Encoder自定义函数 q q q 将各时刻的隐状态变换为向量 c = q ( h 0 , h 1 , . . . , h t ) c=q(h_0,h_1,...,h_{t}) c=q(h0,h1,...,ht),这个 c c c就相当于从“欢迎/来/北京”这几个单词中提炼出来的大概意思一样,包含了这句话的含义。
Decoder的每一时刻的输入为Eecoder输出的 c c c 和Decoder前一时刻解码的输出 s t − 1 s_{t-1} st−1 ,还有前一时刻预测的词的向量 E t − 1 E_{t-1} Et−1 (如果是预测第一个词的话,此时输入的词向量为“_GO”的词向量,标志着解码的开始),我们可以用函数g 表达解码器隐藏层变换: s i = g ( c , s t − 1 , E t − 1 ) s_i=g(c,s_{t-1},E_{t-1}) si=g(c,st−1,Et−1)。直到解码解出“_EOS”,标志着解码的结束。
上面提到的Seq2Seq是最基础的模型,下面介绍的方法基于Seq2Seq,但是能够使它的性能能有一定程度的提升:
在基础的模型中,Decoder的每一次解码又会作为下一次解码的输入,这样就会导致一个问题就是错误累计,如果其中一个RNN单元解码出现误差了,那么这个误差就会传递到下一个RNN单元,使训练结果误差越来越大。Teacher Forcing在一定程度上解决了这个问题,它的流程如下图所示,在训练过程中,使用要解码的序列作为输入进行训练,但是在inference阶段是不能使用的,因为你不知道要预测的序列是个啥,当然只在训练过程中效果就很不错了,它帮助模型加速收敛。
相比大家都听过Attention,也就是注意力机制,是2015年Bahdanau等人提出的,大概意思就是让Encoder编码出的c向量跟Decoder解码过程中的每一个输出进行加权运算,在解码的每一个过程中调整权重取到不一样的c向量,更通俗的讲就是c 就是包含“欢迎来北京”这句话的意思,翻译到第一个词“welcome”的时候,需要着重去看“欢迎”这个词。
假设编码器每个隐藏状态为 h j h_j hj,序列长度为T,那么在第 i i i个时刻 c c c向量的计算方式如下 :
c
i
=
∑
j
=
1
T
a
i
j
h
j
c_i=\sum_{j=1}^T{a_{ij}h_{j}}
ci=j=1∑Taijhj
那么这个权重
a
i
j
a_{ij}
aij怎么算呢?
给定 i i i, a i j a_{ij} aij其实就是在 j = 1 , 2 , . . . , T j=1,2,...,T j=1,2,...,T 时刻的一个概率分布,我们可以使用 s o f t m a x softmax softmax进行计算, a i j = s o f t m a x ( e ( s i − 1 , h j ) ) a_{ij}=softmax(e(s_{i-1},h_{j})) aij=softmax(e(si−1,hj)) ,其中 s i − 1 s_{i-1} si−1为解码器在 i − 1 i-1 i−1时刻的隐状态,函 e e e 为距离计算函数,有多种方式供选择,最简单的就是内积,其他的方式就不在赘述。
这里借用一个大佬说过的话:Attention听上去就是一个很屌,不明觉厉的东西,实际实现起来就是,哦原来是这么回事。总结一下吧,Attention机制就是让编码器编码出来的向量根据解码器要解码的东西动态变化的一种机制,貌似来源灵感就是人类视觉在看某一个东西的时候会有选择的针对重要的地方看。
在inference阶段,不能使用Teacher Forcing,那么只能使用上一时刻解码的输出作为下一个解码的输入,刚才也说过了这样会导致误差传递,怎么解决这个问题呢?答案就是Beam Search,使用流程是这样的,在每个时刻解码器都会选择Top k个预测结果作为下一个解码器的输入,将这K个结果逐一输入到解码器进行解码,就会产生k倍个预测结果,从所有的解码结果中再选出Top K个预测结果作为下一个解码器的输入,在最后一个时刻再选出Top 1作为最终的输出,这样避免的错误传递。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。