1.前言

在自然语言处理领域,近几年最火的是什么?是BERT!谷歌团队2018提出的用于生成词向量的BERT算法在NLP的11项任务中取得了非常出色的效果,堪称2018年深度学习领域最振奋人心的消息。而BERT算法又是基于Transformer,Transformer又是基于attention机制。这次咱们从Encoder-Decoder->Attention->Transformer逐步讲解,一步一步深入,将他们一网打尽,写这篇博客既是对我自己学习的一个总结,也希望或许能对你有所帮助!!!
因为涉及的内容较多,我决定将博客分为上下两篇,上篇主要介绍Attention,下篇介绍Transformer。
那么废话不多说,开始咱们上篇 Attention详解。

2.Encoder-Decoder

2.1Encoder-Decoder简介

Encoder-Decoder框架顾名思义也就是编码-解码框架,目前大部分attention模型都是依附于Encoder-Decoder框架进行实现,在NLP中Encoder-Decoder框架主要被用来处理序列-序列问题。也就是输入一个序列,生成一个序列的问题。这两个序列可以分别是任意长度。具体到NLP中的任务比如:
文本摘要,输入一篇文章(序列数据),生成文章的摘要(序列数据)
文本翻译,输入一句或一篇英文(序列数据),生成翻译后的中文(序列数据)
问答系统,输入一个question(序列数据),生成一个answer(序列数据)
基于Encoder-Decoder框架具体使用什么模型实现,由大家自己决定~用的较多的应该就是seq2seq模型和Transformer了。

2.2Encoder-Decoder结构原理


上图就是Encoder-Decoder框架在NLP领域中抽象后的最简单的结构图。
Encoder:编码器,对于输入的序列<x1,x2,x3…xn>进行编码,使其转化为一个语义编码C,这个C中就储存了序列<x1,x2,x3…xn>的信息。
Encoder究竟是如何编码的呢?
编码方式有很多种,在文本处理领域主要有RNN/LSTM/GRU/BiRNN/BiLSTM/BiGRU,可以依照自己的喜好来选择编码方式,这也是为什么我在之前的博客里先写了RNN/LSTM/GRU的详解,不搞懂RNN/LSTM/GRU的原理,这个Encoder部分那肯定是看不懂地。
我们以RNN为例来具体说明一下:
以上图为例,输入<x1,x2,x3,x4>,通过RNN生成隐藏层的状态值<h1,h2,h3,h4>,如何确定语义编码C呢?最简单的办法直接用最后时刻输出的ht作为C的状态值,这里也就是可以用h4直接作为语义编码C的值,也可以将所有时刻的隐藏层的值进行汇总,然后生成语义编码C的值,这里就是C=q(h1,h2,h3,h4),q是非线性激活函数。
得到了语义编码C之后,接下来就是要在Decoder中对语义编码C进行解码了。

Decoder:解码器,根据输入的语义编码C,然后将其解码成序列数据,解码方式也可以采用RNN/LSTM/GRU/BiRNN/BiLSTM/BiGRU。Decoder和Encoder的编码解码方式可以任意组合,并不是说我Encoder使用了RNN,Decoder就一定也需要使用RNN才能解码,Decoder可以使用LSTM,BiRNN这些。
Decoder究竟是如何解码的呢?
基于seq2seq模型有两种解码方式:
[论文1]Cho et al., 2014 . Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation.

论文1中指出,因为语义编码C包含了整个输入序列的信息,所以在解码的每一步都引入C。文中Ecoder-Decoder均是使用RNN,在计算每一时刻的输出yt时,都应该输入语义编码C,即ht=f(ht-1,yt-1,C),p(yt)=f(ht,yt−1,C)。ht为当前t时刻的隐藏层的值,yt-1为上一时刻的预测输出,作为t时刻的输入,每一时刻的语义编码C是相同地。

[论文2]Sutskever et al., 2014. Sequence to Sequence Learning with Neural Networks.

论文2的方式相对简单,只在Decoder的初始输入引入语义编码C,将语义编码C作为隐藏层状态值h0的初始值,p(yt)=f(ht,yt−1)。

至于Decoder到底使用哪一种呢,答案是两种都不建议使用!
普通的Encoder-Decoder结构还是存在很多问题地:

1.如果按照论文1解码,每一时刻的输出如上式所示,从这里可以看出,在生成目标句子的单词时,不论生成哪个单词,是y1,y2也好,还是y3也好,他们使用的语义编码C都是一样的,没有任何区别。而语义编码C是由输入序列X的每个单词经过Encoder 编码产生的,这意味着不论是生成哪个单词,y1,y2还是y3,其实输入序列X中任意单词对生成某个目标单词yi来说影响力都是相同的,没有任何区别(其实如果Encoder是RNN的话,理论上越是后输入的单词影响越大,并非等权的,估计这也是为何Google提出Sequence to Sequence模型时发现把输入句子逆序输入做翻译效果会更好的小Trick的原因)

2.将整个序列的信息压缩在了一个语义编码C中,用一个语义编码C来记录整个序列的信息,序列较短还行,如果序列是长序列,比如是一篇上万字的文章,我们要生成摘要,那么只是用一个语义编码C来表示整个序列的信息肯定会损失很多信息,而且序列一长,就可能出现梯度消失问题,这样将所有信息压缩在一个C里面显然就不合理。

既然一个C不行,那咱们就用多个C,诶~这个时候基于Encoder-Decoder的attention model就出现了。

3.Attention Model

3.1Attention 注意力机制简介


什么是注意力机制?
就上图为例,老实告诉我当你第一眼看到上图时,你的视线停留在哪个位置?对于我这种老二次元是在妹子身上,但是对于舰船迷来说,可能注意力就是在舰船上。同一张图片,不同的人观察注意到的可能是不同的地方,这就是人的注意力机制。attention 就是模仿人的注意力机制设计地。那么究竟是如何实现的呢?咱们接着往下看。

3.2Attention 原理


上图就是引入了Attention 机制的Encoder-Decoder框架。咱们一眼就能看出上图不再只有一个单一的语义编码C,而是有多个C1,C2,C3这样的编码。当我们在预测Y1时,可能Y1的注意力是放在C1上,那咱们就用C1作为语义编码,当预测Y2时,Y2的注意力集中在C2上,那咱们就用C2作为语义编码,以此类推,就模拟了人类的注意力机制。
那么现在只剩下一个问题就是怎么计算出C1,C2,C3…Cn呢?如何判断我每次在做解码的时候注意力应该放在哪个位置呢?

以机器翻译例子"Tom chase Jerry" - "汤姆追逐杰瑞"来说明:
当我们在翻译"杰瑞"的时候,为了体现出输入序列中英文单词对于翻译当前中文单词不同的影响程度,比如给出类似下面一个概率分布值:
(Tom,0.3)(Chase,0.2)(Jerry,0.5)
每个英文单词的概率代表了翻译当前单词“杰瑞”时,注意力分配模型分配给不同英文单词的注意力大小。这对于正确翻译目标语单词肯定是有帮助的,因为引入了新的信息。同理,目标句子中的每个单词都应该学会其对应的源语句子中单词的注意力分配概率信息。这意味着在生成每个单词Yi的时候,原先都是相同的中间语义表示C会替换成根据当前生成单词而不断变化的Ci。理解AM模型的关键就是这里,即由固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的Ci。

f2(“Tom”),f2(“Chase”),f2(“Jerry”)就是对应的隐藏层的值h(“Tom”),h(“Chase”),h(“Jerry”)。g函数就是加权求和。αi表示权值分布。因此Ci的公式就可以写成:
Ci=∑j=1nαijhjC_i = \sum_{j=1}^n \alpha_{ij}h_jCi​=j=1∑n​αij​hj​
那么现在的问题就只剩下,怎么知道attention模型所需要的输入句子单词注意力分配概率分布值呢?也就是αij?

以普通的RNN-RNN Encoder-Decoder结构为例,注意上图Decoder初始输入用初始符,这里使用eos作为初始符。将输入eos与初始S0通过RNN生成h(eos),然后分别计算h(eos)与h1,h2,h3…hm的相关性,这个相关性怎么计算一会儿再介绍。得到h(eos)与h1,h2,h3…hm的相关性评分[f1,f2,f3…fm],然后跟多分类一样使用softmax,就能得到相关性的概率分布α(eos)。
推广到预测decoder的每一个输出值Yi:

decoder上一时刻的输出值Yi-1与上一时刻传入的隐藏层的值Si-1通过RNN生成Hi,然后计算Hi与h1,h2,h3…hm的相关性,得到相关性评分[f1,f2,f3…fm],然后对Fi进行softmax就得到注意力分配αij。然后将encoder的输出值h与对应的概率分布αij进行点乘求和,就能得到注意力attention值了。
注意一下,这里咱们使用的是Soft Attention是所有的数据都会注意,都会计算出相应的注意力权值,不会设置筛选条件。还有一种Hard Attention会在生成注意力权重后筛选掉一部分不符合条件的注意力,让它的注意力权值为0,即可以理解为不再注意这些不符合条件的部分。

3.3Attention 机制的本质思想

上面咱们说了Attention的原理,但是是基于Encoder-Decoder框架来介绍地,Attention机制并不是一定要基于Encoder-Decoder框架,那么他的本质思想是什么呢?以及在上面遗留下来的Hi与h1,h2,h3…hm的相关性到底应该怎么算呢?现在就来为大家讲解!

参照上图可以这么来理解Attention,将Source中的构成元素想象成是由一系列的<Key,Value>数据对构成(对应到咱们上里面的例子,key和value是相等地,都是encoder的输出值h),此时给定Target中的某个元素Query(对应到上面的例子也就是decoder中的hi),通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对Source中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。即可以将其本质思想改写为如下公式:

Lx表示source的长度,Similarity(Q,Ki)计算如下:

MLP多层感知机感觉在这里用得比较少,反正我没怎么用过,就不介绍了。搞懂下面这两种计算相似性的方法:
点积:就是将Query和Keyi进行点积,Transformer中就是用的这种方法。
Cosine相似性-余弦相似度
分子就是两个向量Query与Key的点积
分母就是两个向量的L2范数,(L2范数:指向量各元素的平方和然后求平方根)

计算出Query和Keyi的相似性后,第二阶段引入类似SoftMax的计算方式对第一阶段的相似性得分进行数值转换,一方面可以进行归一化,将原始计算分值整理成所有元素权重之和为1的概率分布;另一方面也可以通过SoftMax的内在机制更加突出重要元素的权重。即一般采用如下公式计算:

第二阶段的计算结果 ai 即为 Valuei 对应的权重系数,然后进行加权求和即可得到Attention数值:

通过如上三个阶段的计算,即可求出针对Query的Attention数值,目前绝大多数的注意力机制计算方法都符合上述的三阶段计算过程。

最后对上述计算Attention值地三个阶段做一个总结:

阶段1:Query与每一个Key计算相似性得到相似性评分s
阶段2:将s评分进行softmax转换成[0,1]之间的概率分布
阶段3:将[a1,a2,a3…an]作为权值矩阵对Value进行加权求和得到最后的Attention值

3.4Attention优缺点

看到这你应该已经能够Attention的强大之处了,但是如此强大的Attention真的是无懈可击,没有一点缺点的吗?
优点:
1.速度快。Attention机制不再依赖于RNN,解决了RNN不能并行计算的问题。这里需要说明一下,基于Attention机制的seq2seq模型,因为是有监督的训练,所以咱们在训练的时候,在decoder阶段并不是说预测出了一个词,然后再把这个词作为下一个输入,因为有监督训练,咱们已经有了target的数据,所以是可以并行输入的,可以并行计算decoder的每一个输出,但是再做预测的时候,是没有target数据地,这个时候就需要基于上一个时间节点的预测值来当做下一个时间节点decoder的输入。所以节省的是训练的时间。
2.效果好。效果好主要就是因为注意力机制,能够获取到局部的重要信息,能够抓住重点。
缺点:
1.只能在Decoder阶段实现并行运算,Encoder部分依旧采用的是RNN,LSTM这些按照顺序编码的模型,Encoder部分还是无法实现并行运算,不够完美。
2.就是因为Encoder部分目前仍旧依赖于RNN,所以对于中长距离之间,两个词相互之间的关系没有办法很好的获取。

为了改进上面两个缺点,更加完美的Self-Attention出现了。

4.Self-Attention

在一般任务的Encoder-Decoder框架中,输入Source和输出Target内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attention机制发生在Target的元素和Source中的所有元素之间。而Self Attention顾名思义,指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。其具体计算过程是一样的,只是计算对象发生了变化而已,相当于是Query=Key=Value,计算过程与attention一样,所以这里不再赘述其计算过程细节。

例如上图是self-attention的一个例子:
我们想知道这句话中的its,在这句话里its指代的是什么,与哪一些单词相关,那么就可以将its作为Query,然后将这一句话作为Key和Value来计算attention值,找到与这句话中its最相关的单词。通过self-attention我们发现its在这句话中与之最相关的是Law和application,通过我们分析语句意思也十分吻合。
如此引入Self Attention后会更容易捕获句子中长距离的相互依赖的特征,因为如果是RNN或者LSTM,需要依次序序列计算,对于远距离的相互依赖的特征,要经过若干时间步步骤的信息累积才能将两者联系起来,而距离越远,有效捕获的可能性越小。但是Self Attention在计算过程中会直接将句子中任意两个单词的联系通过一个计算步骤直接联系起来,所以远距离依赖特征之间的距离被极大缩短,有利于有效地利用这些特征。除此外,Self Attention对于增加计算的并行性也有直接帮助作用。正好弥补了attention机制的两个缺点,这就是为何Self Attention逐渐被广泛使用的主要原因。

5.结语

感谢您能看到这里,上篇到这里基本上就结束了,本来是想一口气全写完地,但写了快一万字了实在是有点写不动了。剩下的Transformer和BERT就留着下篇再讲解吧。希望看到这里,能帮助小伙伴你搞懂Attention机制,下一篇看Transformer的时候才能不那么费劲。
生命不息,学习不止,大家一起加油吧,奥利给!!!

6.参考

自己学习的时候就是看了张俊林博士的博客,以上部分内容也参考自张大神部分博客内容,感谢~
深度学习中的注意力机制(2017版)

史上最小白之Attention详解相关推荐

  1. 史上最小白之Transformer详解

    1.前言 博客分为上下两篇,您现在阅读的是下篇史上最小白之Transformer详解,在阅读该篇博客之前最好你能够先明白Encoder-Decoder,Attention机制,self-Attenti ...

  2. 史上最小白之BM25详解与实现

    史上最小白之BM25详解与实现 原理 BM25算法是一种计算句子与文档相关性的算法,它的原理十分简单:将输入的句子sentence进行分词,然后分别计算句子中每个词word与文档doc的相关度,然后进 ...

  3. 史上最小白之Bert详解

    1.前言 关于BERT,张俊林博士有一篇特别好的文章:从Word Embedding到Bert模型-自然语言处理中的预训练技术发展史 非常透彻地讲解了Bert是怎么样从NNLM->Word2Ve ...

  4. 史上最小白之RNN详解

    1.前言 网上目前已经有诸多优秀的RNN相关博客,但是我写博客的出发点主要是为了加深和巩固自己的理解,所以还是决定自己再进行一下总结和描述,如有不正确的地方欢迎指正~ 2.区分RNN 循环神经网络(R ...

  5. 史上最直白之Attention详解(原理+代码)

    目录 为什么要了解Attention机制 Attention 的直观理解 图解深度学习中的Attention机制 总结 为什么要了解Attention机制   在自然语言处理领域,近几年最火的是什么? ...

  6. 史上最简单MySQL教程详解(进阶篇)之存储过程(一)

    史上最简单MySQL教程详解(进阶篇)之存储过程(一) 史上最简单MySQL教程详解(进阶篇)之存储过程(一) 什么是存储过程 存储过程的作用 如何使用存储过程 创建存储过程 DELIMITER改变分 ...

  7. 史上最简单MySQL教程详解(进阶篇)之存储引擎介绍及默认引擎设置

    什么是存储引擎? MySQL存储引擎种类 MyISAM 引擎 InnoDB引擎 存储引擎操作 查看存储引擎 存储引擎的变更 修改默认引擎 什么是存储引擎? 与其他数据库例如Oracle 和SQL Se ...

  8. 史上最简单MySQL教程详解(进阶篇)之索引及失效场合总结

    史上最简单MySQL教程详解(进阶篇)之索引及其失效场合总结 什么是索引及其作用 索引的种类 各存储引擎对于索引的支持 简单介绍索引的实现 索引的设置与分析 普通索引 唯一索引(Unique Inde ...

  9. 史上最简单MySQL教程详解(进阶篇)之视图

    史上最简单MySQL教程详解(进阶篇)之视图 为什么要用视图 视图的本质 视图的作用 如何使用视图 创建视图 修改视图 删除视图 查看视图 使用视图检索 变更视图数据 WITH CHECK OPTIO ...

最新文章

  1. 基于关联规则(Variational Autoencoders)疾病预测系统实战:(pyspark FPGrowth实现频繁项集挖掘、最后给出预测模型topK准确率和召回率)
  2. Go开发之路 -- 指针类型
  3. svn中“clean up”死循环问题解决办法
  4. Python中math模块的使用
  5. linux核显驱动与内核冲突,英特尔第十二代核显现身Linux驱动库
  6. php课后答案 唐四薪_PHP课后小结 12.20
  7. Fddb数据集人脸label可视化(matlab)
  8. Python学习第二章:变量和简单类型
  9. 如何避免B端产品失败(近万字解析)
  10. 小米商城项目实战(一)
  11. 自己当笔记写着玩吧--leetcode- 001
  12. 基于OpenAI的Chatbot开发记录
  13. 财神来了 | 那些年伤害过你的分叉币
  14. CSS之控制所有p段落,首行缩进两个字符!...
  15. 双(三氟甲基磺酰基)酰亚胺钠 cas91742-21-1白色-类白色晶体-粉末 分子量:303.1358892
  16. PTA 7-144 最矮的巨人
  17. 禁止公司内网电脑安装QQ电脑管家和360安全卫士
  18. 怎么将CAD图纸转换为PDF格式?可以将PDF图纸在此转换为CAD格式图纸吗?
  19. 编译mimikatz
  20. 查看git的远程主机名_git pull 主机名

热门文章

  1. appserv mysql 密码_AppServ8.0安装教程,AppServ8.0安装后Mysql密码不对怎么办?
  2. iphone苹果手机定位在哪里打开设置
  3. 常用Web安全扫描工具合集
  4. android手机换,这些技巧,让你的安卓手机如换新机,再用5年!
  5. Ubuntu下的几种常见输入法极其配置方式(zt)
  6. 一款功能完善的智能匹配1V1视频聊天App应该通过的测试CASE
  7. Android应用开发-小巫CSDN博客客户端UI篇,kotlin安卓开发教程视频
  8. Centos中ifcfg-ens33文件参数解释
  9. Linux内核页缓存实现简介
  10. 银河系三维平面全景图