之前介绍了seq2seq模型,简单来说它分为两个过程,第一个是encoder,将输入的序列压缩成一个语义向量,然后在decoder过程中再利用RNN重新转换成新的序列。
seq2seq主要有一个问题,因为在encoder中使用了RNN处理输入序列,这就意味着对于序列的开头,语义向量包含了较少的信息,在模型的学习过程中,序列开头的贡献也较少,所以就提出了结合注意力机制对seq2seq进行改进。
所谓的注意力机制其实不仅仅应用在seq2seq,这是一个在很多模型中都被应用的思想。简单来说,他模仿了人脑的注意力机制,这是一种资源分配模型,在某个时刻,人的注意力总是集中在某个地方,比如看一幅图片我们往往会关注某个焦点部分,我们的视角也无法聚焦完整的场景,把这个思想应用在模型中,本质上就是一种对数据的加权处理,针对感兴趣的或者和问题解决相关的数据,赋予更大的权重。
在详细介绍注意力机制前,先看回之前的seq2seq,假设我们已经得到了语义向量c,把c输入到decoder会得到一个个新的序列:
y 1 = f ( C ) y_1 = f(C) y1=f(C)
y 2 = f ( C , y 1 ) y_2 = f(C,y_1) y2=f(C,y1)
y 2 = f ( C , y 1 , y 2 ) y_2 = f(C,y_1,y_2) y2=f(C,y1,y2)
可以看到,这些新生成的单词,他们使用的语义向量c都是一样的,这就导致了在生成单词的过程中没有倾向性地利用输入,比如我们在进行翻译过程中,每个生成的单词都应该对原输入有不同的侧重,可是seq2seq就忽略了这点,所以可以理解成这是一个注意力不集中的分心模型。
那么引入了注意力机制的seq2seq又应该是怎样的呢,答案是针对每个生成的输出,都分别对应一个新的语义向量c,也就是语义向量也变成了一个变化的序列,根据当前的输出单词来调整生成语义向量时分配到原输入的不同权重:
这时候,输出序列就变成:
y 1 = f ( C 1 ) y_1 = f(C_1) y1=f(C1)
y 2 = f ( C 2 , y 1 ) y_2 = f(C_2,y_1) y2=f(C2,y1)
y 2 = f ( C 3 , y 1 , y 2 ) y_2 = f(C_3,y_1,y_2) y2=f(C3,y1,y2)
接下来主要分析对于encoder中的RNN如何针对不同的输入分配权重。
首先对于encoder的RNN,每次进行输入都能得到一个隐层输出,比如现在输入一个句子"how are you",针对how的语义向量就可以表示为:
c h o w = g ( w 1 ∗ h ( " h o w " ) , w 2 ∗ h ( " a r e " ) , w 3 ∗ h ( " y o u " ) ) c_{how} = g(w_1 * h("how"),w_2 * h("are"),w_3 * h("you")) chow=g(w1∗h("how"),w2∗h("are"),w3∗h("you"))
其中h为隐层输出,w为权重,g为生成语义向量的变换函数,,最简单的变换函数就是直接加权求和。通过模型的学习,就可以得到合适针对各个词的合适权重,关于具体的学习算法,有很多论文提到不同的方法,这里暂不详细讨论,以上的模型就是Soft Attention Model,在这里,任何的数据都能得到一个权重,权重不会变为0,所以都可以微分(还有一种模型是Hard Attention,它会通过设置权重为0筛选掉一部分不符合条件的部分,让注意力权重为0)
最近本人在github写了一个自然语言处理的入门教程,包括模型的代码和模型的分析介绍,欢迎交流:NLPBeginner
想浏览更多关于数学、机器学习、深度学习的内容,可浏览本人博客