seq2seq翻译模型里的attention model(注意力模型)

现在深度学习各种技术,概念,模型让人眼花撩乱,每次进展日新月异。但其实不用担心,关键点就那么几个,卷积算一个,lstm/rnn算一个。其实换个loss
function,加几个层,改一个优化函数,或者换个训练数据集,都在不停的刷论文罢了。
但注意力模型不一样,这个是有生产力的。
一个最直观的说明,啥是注意力。想想我们在人群中,无意间看到一个多年认识的一个老朋友,或者说找一个人吧,我们不用一张张脸去扫描吧。或者你过马路的时候,你会从街左边一直扫描到街右边么,更多注意红绿灯和来往车辆。这就是人类观察事物的注意力分配(人类是为了省能量)。
http://s10/bmiddle/001rxTlvzy7fR4cErkl19&690model(注意力模型)" />
上面是传统的seq2seq模型,encoder产生了语义编码信息c(其实就是RNN产生的hidden_state)。然后y用这个hidden做为输入状态。
先直观理解一下seq2seq。
输入是一个单词序列,输出也是一个单词序列。可以是同一种语言,比如做文摘,或者不同语言,那就是做翻译。所以seq2seq是一个较通用的模型框架。
encoder就是对输入X序列进行编码。
C = F(X) = F(x1,x2,x3...,xn),编码保存在C里。
然后把C传递给解码器进行解码:Y=G(C,y1,y2....,yn-1)。这里可以看到,对于每一步yi,我们使用的C都是一样的,这显然是不合理的。在翻译一个句子的时候,每个时刻需要关注的词肯定是有所区别的。而且rnn/lstm最后的输入是权重最大,这就更不合理了。所以google有一个模型里,把词序倒过的效果会更好,其实就有这样的原因。
没有注意力模型,相当于我们读了一个英文句子Tom chase jerry,我们记录它的语义在C里。然后我们开始翻译成中文,第一个词“汤姆”,但第二词的时候G(C,汤姆),还是用C的语义。但在翻译杰瑞的时候,jerry的权重应该更高才对。
https://mmbiz.qpic.cn/mmbiz_jpg/DC4PhSqvZPuSRbK67SWdCFNWQl2MpJh7QZhdb5HdbcFceZoFZ9JGfhSuM1A1NX4aaupC3USdDhVjFVmFjWrq4w/0?wx_fmt=jpegmodel(注意力模型)" TITLE="seq2seq翻译模型里的attention
就是每一步翻译的时候,输入的语义编码是有权重上的区别的。
http://s14/bmiddle/001rxTlvzy7fR4kFdNz6d&690model(注意力模型)" />
如果用的rnn,这里f2输出就是编码器hidden_state(注意不是最终的,是中间态,其实就是每个input的output)。
那这个概率权值怎么来,就是注意力模型的关键所在了。
很多论文里都会定义这么一个函数:F(hj,Hi),就是需要对齐单词。
pytorch的代码实现片段如下:
def forward(self, input, hidden, encoder_output, encoder_outputs):
embedded = self.embedding(input).view(1, 1, -1)
embedded = self.dropout(embedded)
#这里计算注意力权重,input和encode的context线性
#把hidden和input cat之后,线性组合成softmax概率 attn_weights = F.softmax(
self.attn(torch.cat((embedded[0], hidden[0]), 1)))
#和每个output做bmm,不广播,encoder提供的每个output中间态做加权,得到新的hidden
attn_applied = torch.bmm(attn_weights.unsqueeze(0),
encoder_outputs.unsqueeze(0))
#这一步也是常规的,embedded+hidden之后做线性
output = torch.cat((embedded[0], attn_applied[0]), 1)
output = self.attn_combine(output).unsqueeze(0)
就是这样,就实现了权重注意力的分配。明天继续在这个问题上深化一下,写一个从输出到输出计算的过程,这样看得更直观一些。