我们熟悉的Transformer就是变形金刚,因此可以说擎天柱就是一个Transformer,但是这里要说的并不是变形金刚,而是谷歌在发表在NIPS-2017上的《Attention Is All You Need》中提出的强大的特征提取器Transformer。下面主要从Attention model、Self-attention和Transformer三个方面对Transformer的机制做一个剖析。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/30d7e116bb16e7cf8281f676d7c05027.png)
注意力机制(Attention)
在深度学习中,卷积神经网络、循环神经网络已在CV、NLP的诸多领域各放异彩。根据通用近似定理,前馈神经网络和循环神经网络都有很强的能力,但由于优化算法和计算能力的限制,在处理复杂任务,比如需要处理大量的输入信息或复杂的计算流程时,仍然很难达到通用的近似能力。因此,为了提高网络处理信息的能力,可以借鉴人脑处理过在信息的机制,主要是如下两个:
- 注意力机制:过滤掉大量的无关信息
- 外部记忆:优化神经网络的记忆结构来提高神经网络存储信息的容量
source:https://cn.dreamstime.com
其中注意力(Attention)机制被广泛应用到基于深度学习的自然语言处理各个任务中,特别是2017年Google提出后,模型成效、复杂度又取得了更大的进展,它的发展历程大体上如下所示
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e3bb2a5d6f93840e91abf510b0af4083.png)
注意力是指人脑可以有意或无意的从大量的输入信息中选择小部分的有用信息来重点处理,并忽略其他的信息,主要分为:
- 聚焦式注意力:它是一种自上而下有意识的注意力,根据某一具体目的、任务主动有意识的聚焦于某一对象
- 基于显著性的注意力:它是一种自下而上的注意力,只由外界因素驱动,不依赖于具体的任务和目的
最典型的一个例子便是 鸡尾酒会效应:当一个人在嘈杂的鸡尾酒会上,尽管影响因素很多,他仍可以听到朋友的谈话内容,而忽略其他人的声音;同时,如果未注意到的背景声中有重要的。
更形象的示例如下所示,当看一份报纸时,我们并不会平等的关注报纸上每一部分的内容,可能在标题或是图片部分分配大部分的注意力,而在其余的部分关注较少
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b50e274b0fb494dffe1fcca40e34c2b1.png)
source:https://blog.csdn.net/malefactor/article/details/78767781
以机器翻译为例,一个典型的Encoder-Decoder模型如下所示。Encoder接收一个语句的序列数据,经过非线性的转换得到中间的语义编码 c c c,然后Decoder对 c c c进行解码得到目标序列数据
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/eb61a9462e116d0cb4c9bdbc23d84cd5.png)
其中Target中每个单词的生成过程可以表示为: y 1 = f ( C ) y 2 = f ( C , y 1 ) y 3 = f ( C , y 1 , y 2 ) \begin{array}{l}{\mathbf{y}_{1}=\mathbf{f}(\mathbf{C})} \\ {\mathbf{y}_{2}=\mathbf{f}\left(\mathbf{C}, \mathbf{y}_{1}\right)} \\ {\mathbf{y}_{3}=\mathbf{f}\left(\mathbf{C}, \mathbf{y}_{1}, \mathbf{y}_{2}\right)}\end{array} y1=f(C)y2=f(C,y1)y3=f(C,y1,y2)从中我们可以看出,在每个单词的生成过程中,使用的语义编码并没有改变,即在生成 y i y_{i} yi时,source中的任意单词对于 y i y_{i} yi的影响力都是相同的,因此这样的模型并没有体现注意力机制。例如当翻译Tom chase Jerry时,如果使用上述的Encoder-Decoder的模型,在翻译"Jerry-杰瑞"时,source中每个单词到“杰瑞”的权重都是 1 3 \frac {1}{3} 31,这显然是不合常理的
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/0220018afa9b09d3ade2c42aa8ba0cbe.png)
将注意力机制引入Encoder-Decoder模型后,整体的模型结构可以简单的表示为:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/176fe7f3990c89d8a142472d9e2a6e6c.png)
此时Target中每个单词的生成过程变为: y 1 = f 1 ( C 1 ) y 2 = f 1 ( C 2 , y 1 ) y 3 = f l ( C 3 , y 1 , y 2 ) \begin{array}{l}{\mathbf{y}_{1}=\mathbf{f} \mathbf{1}\left(\mathbf{C}_{1}\right)} \\ {\mathbf{y}_{2}=\mathbf{f} \mathbf{1}\left(\mathbf{C}_{2}, \mathbf{y}_{1}\right)} \\ {\mathbf{y}_{3}=\mathbf{f} \mathbf{l}\left(\mathbf{C}_{3}, \mathbf{y}_{1}, \mathbf{y}_{2}\right)}\end{array} y1=f1(C1)y2=f1(C2,y1)y3=fl(C3,y1,y2)其中 f f f表示某种变换函数, g g g表示加权求和。那么在上面的例子中翻译“Tom”的过程可表示为
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/bd6da43d8bb4eda9240f16a46120fde1.png)
Attention函数的本质可以描述为一个查询(query)到一系列键值对(key-value)的映射,如下所示:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/f47a9847fc49037433a3f42e8d98c033.png)
在计算 Attention 时主要分为三步:
- 将 query 和每个 key 进行相似度计算得到权重,常用的相似度函数有点积,拼接,感知机等;
- 一般是使用一个 softmax 函数对这些权重进行归一化;
- 将权重和相应的键值 value 进行加权求和得到最后的 Attention。
注意力机制主要可分为如下的几种:
- 多头注意力(Multi-Head Attention)
- 硬注意力 (Hard Attention)
- 结构化注意力 (Structure Attention)
- 指针网络 (Pointer Network)
- 双向注意力(Bi-Directional Attention)
- 键值对注意力 (Key-Value Attention)
- 自注意力 (Self/Intra Attention)
下面是注意力机制在图像生成中的一个简单的例子,当根据输入的语句A person is standing ona beach with a surfboard生成对应的图像时,我们可以发现语句中不同的词在生成图像中中关注的区域中是不同的
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/b64e6db51706439cc62c1bcb9c520b06.png)
Self-Attention
Self-Attention也称为Intra-Attention,即内部注意力,在一般任务的Encoder-Decoder框架中,Source和Target内容是不一样的,比如对于英-中机器翻译来说,Source是英文句子,Target是对应的翻译出的中文句子,Attention机制发生在Target的元素Query和Source中的所有元素之间。Self Attention指的不是Target和Source之间的Attention机制,而是Source内部元素之间或者Target内部元素之间发生的Attention机制,也可以理解为Target=Source这种特殊情况下的注意力计算机制。其具体计算过程是一样的,只是计算对象发生了变化。
Self-Attention的一大优点就是他可以捕获同一句子中单词之间的一些句法特征或是语义特征。相比于传统的RNN、LSTM,引入Self-Attention后的模型更容易捕获句子中长距离的相互依赖的特征,从而可以有效的利用句子中存在的特征。此外Self-Attention对计算并行性的良好支持,也成为它逐渐取代一般的Attention的重要原因。
Transformer
下面介绍重头戏:TRANSFORMER。
论文地址:https://arxiv.org/abs/1706.03762
pyTorch GitHub:https://github.com/jadore801120/attention-is-all-you-need-pytorch
Tensorflow GitHub:https://github.com/Kyubyong/transformer 或 https://github.com/tensorflow/tensor2tensor
收录于:NIPS 2017
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/75ad37a94232b5650d483f41d8766d59.png)
下面并不对原论文进行按章节的进行分析,主要是借助李宏毅老师的《机器学习2019-transformer》和网络上的资料来进行分析。
youtobe: https://www.youtube.com/watch?v=ugWDIIOHtPA&list=PLJV_el3uVTsOK_ZK5L0Iv_EQoL1JefRL4&index=58
B站:https://www.bilibili.com/video/av46561029/?p=58
Transformer可以看作为引入了Self-Attention的Seq2Seq模型。目前被广泛使用的LSTM、GRU、SRU,整体来看都是属于RNN架构的模型。如下所示,它的输入是一个序列数据,输出也是一个序列数据。在单向的RNN中,每个输出 b i b^{i} bi都看过了 a 1 − a i − 1 a^{1}-a^{i-1} a1−ai−1;而在双向的RNN中,每个输出 b i b^{i} bi看过了整个的输入序列。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/4742ef48d476a1d655aa51b35ae64214.png)
RNN结构本身比较简单,也很适合序列建模,但它们明显缺点之一就是无法并行,因此速度较慢,显然不能充分利用如今强大的算力。另外RNN也无法很好地学习到全局的结构信息,因为它本质是一个马尔科夫决策过程。
为了避开上述RNN的诸多不足,人们开始尝试改造传统的CNN来实现并行的需求,同时实现易捕捉到一些全局的结构信息。如下所示,我们可以采用多个Fileter来处理输入的序列数据,通过加深网络的层数,理论上也可以实现每个输出都是在看过整个输入的情况下得到的,而且不同的Filter之间彼此独立,也满足并行化的需求。但是,网络层数的加深必然导致了计算负担的增大,又会出现新的问题。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/09ca2c377885d95dd7705ff7d8b5ecc9.png)
而Google的提供了第三个思路:纯 Attention,单靠注意力就可以。RNN 要逐步递归才能获得全局信息,因此一般要双向 RNN 才比较好;CNN 事实上只能获取局部信息,是通过层叠来增大感受野;Attention 的思路最为粗暴,它一步到位获取了全局信息。每一个输出 b i b^i bi同样看过了整个的输入序列,而且 b i , i = 1 , 2 , . . . b^i,i=1,2,... bi,i=1,2,...之间可以并行的计算。因此所有用RNN做的东西,理论上都可以用Self-Attention最的更好。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/85b5ae590b1c3457e883f250fb7ed8b5.png)
那Self-Attention内部是如何工作的呢,我们以下图为例进行阐述。假设输入序列为 x 1 , x 2 , x 3 , x 4 x^1,x^2,x^3,x^4 x1,x2,x3,x4,它们分别乘以一个转换矩阵 W W W经计算 a i = W x i a^i = Wx^i ai=Wxi得到 a 1 , a 2 , a 3 , a 4 a^1,a^2,a^3,a^4 a1,a2,a3,a4。然后每个 a i a^i ai再乘以转换矩阵 W q 、 W k 、 W v W^q、W^k、W^v Wq、Wk、Wv得到 q i , k i , v i q^i,k^i,v^i qi,ki,vi。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/965eb3345d4a913015df4027488e345b.png)
计算公式为: q i = W q a i K i = W k a i v i = W v a i q^i=W^qa^i \\ K^i=W^ka^i \\ v^i=W^va^i qi=WqaiKi=Wkaivi=Wvai
其中
- q:query
- k:key
- v:value
接下来就拿每个q去对每个k做Attention的计算,公式为Scaled Dot-Product Attention: α 1 , i = q 1 ⋅ k i / d \alpha_{1, i}=q^{1} \cdot k^{i} / \sqrt{d} α1,i=q1⋅ki/d ,其中 ⋅ \cdot ⋅ 表示点积(dot product), d d d是q和k的维度大小。以 q 1 q^1 q1为例( q 2 , q 3 , q 4 q^2,q^3,q^4 q2,q3,q4是相同的计算过程),计算过程如下所示
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/78b6b482618835b537b77d01f836c878.png)
将得到的 α i , j \alpha_{i,j} αi,j经过一个softmax层计算得到对应的 α i , j ^ \hat{\alpha_{i,j}} αi,j^,计算公式为 α ^ 1 , i = exp ( α 1 , i ) / ∑ j exp ( α 1 , j ) \hat{\alpha}_{1, i}=\exp \left(\alpha_{1, i}\right) / \sum_{j} \exp \left(\alpha_{1, j}\right) α^1,i=exp(α1,i)/∑jexp(α1,j)
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/70929a02e0fbc07f8fab0d936c147003.png)
接着将每个 α ^ \hat{\alpha} α^和每个 v i v^i vi相乘得到 b i b^i bi,计算公式是 b 1 = ∑ i α ^ 1 , i v i b^{1}=\sum_{i} \hat{\alpha}_{1, i} v^{i} b1=∑iα^1,ivi,最后就可以得到输出序列 b i , i = 1 , 2 , 3 , 4 b^i,i=1,2,3,4 bi,i=1,2,3,4,每个 b i b^i bi的计算是并行的。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/37fe351533bc9c5625c32f6c29a87067.png)
如果将 a 1 , a 2 , a 3 , a 4 a^1,a^2,a^3,a^4 a1,a2,a3,a4记为 I I I,将所有的 q i , k i , v i q^i,k^i,v^i qi,ki,vi分别记为 Q , K , V Q,K,V Q,K,V,那么根据前面的计算公式,我们就可以将整个的计算过程转换为矩阵相乘的形式,如下所示:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/18708cd12e8230b7c0a5fbf34d18e229.png)
因此将前面的计算过程用矩阵的形式表示,就变成了如下的形式:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/389ddefb17ccf73cfaf70706b41657fc.png)
所有的 q i q^i qi都转成矩阵计算的形式的话,Attention的计算过程可表示为:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/204a3cf61a8911ecf7b61e7950ade4d1.png)
同样的计算输出的过程也可以转换成矩阵相乘的形式
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/fc88d71cbc8740938adf01e5ef5a71d6.png)
最后整体来看,整个的计算过程为下面的样子
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e7999d3c69b67b451eed9020a5ea199f.png)
对于Self-Attention的一个变体就是Multi-head Self-Attention,我们以2-head的情况为例说明。所谓的2-head就是将每个 q i , k i , v i q^i,k^i,v^i qi,ki,vi分裂得到 q i , 1 , q i , 2 , k i , 1 , k i , 2 , v i , 1 , v i , 2 q^{i,1},q^{i,2},k^{i,1},k^{i,2},v^{i,1},v^{i,2} qi,1,qi,2,ki,1,ki,2,vi,1,vi,2,然后按照前面的方法同样做Attention的计算,的到最后的输出序列
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/929a747a6e4c195ad07dbd3b76124ddd.png)
你可以将得到的每个 b i , j b^{i,j} bi,j组合起来,然后乘以某个矩阵 W o W^o Wo进行降维得到想要形式的输出 b i b^i bi
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/ea6609d981716c05450a7217a14e181a.png)
但是从前面的过程中我们可以看出,Self-Attention的计算并没有考虑输入序列中元素位置的信息,这显然在很多情形下是不合理的。因此在《Attention is all you need》的文章中,作者是另外首设了一个向量 e i e^i ei来表示位置的信息,然后和 a i a^i ai相加再进行后续Attention的计算。
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/e347ae41d337f73cf649b834d2d22b6b.png)
那为什么这里是相加而不是将其组合起来呢?李宏毅老师给出了一种解释。如果现在有一个one-hot形式的向量 p i p^i pi,它取值为1的维度信息就表示了位置信息。然后将它和输入序列中的元素 x i x^i xi组合起来,再乘以一个矩阵 W W W,这里我们将矩阵 W W W分解为两部分 W I W^I WI和 W P W^P WP,分别和 x i x^i xi、 p i p^i pi相乘得到如下的结果。我们就可以将前一部分记为 a i a^i ai,后一部分记为 e i e^i ei。
![]()
而 W W W可视化的效果就是如下的样子
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/450bf6107caea87a3e79ea77b3934b37.png)
一个传统的Seq2Seq model包括一个Encoder,一个Decoder,如果网络模型是RNN的话,基本结构如下所示
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/1748c3b733098d878d931b602c119349.png)
将Self-Attention引入到Seq2Seq model中,所有以前RNN可以做的事,现在都可以使用Self-Attention来做,模型如下所示
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/6f92d69045d773c97c330c780886ad77.png)
而在《Attention is all you need》中的Transformer如下所示,左半部分就是Encoder,右半部分是Decoder:
![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/a6b2f63bae860b5ef46f3c4722ad4d81.png)
Layer Norm: https://arxiv.org/abs/1607.06450
参考:
从Seq2seq到Attention模型到Self Attention(一)
从Seq2seq到Attention模型到Self Attention(二)
自然语言处理中的自注意力机制(Self-Attention Mechanism)
深度学习中的注意力机制
BERT大火却不懂Transformer?
The Illustrated Transformer
Easy Introduction to Transformer paper review — “Attention is all you need”
Attention? Attention!
Attention From Wikipedia, the free encyclopedia