参考文章:
神经机器翻译 之 谷歌 transformer 模型
Self-attention and Transformer
大数据文摘-BERT大火却不懂Transformer&version=11020201&lang=zh_CN&pass_ticket=sLCET0Y%2BZTkYDsKSej3nfbOS885niL2%2Bt2ffNlFmQw3FszFuawe4q3nwl02gUnCe)
从头开始了解Transformer
背景
- 首先理解Attention模型,个人理解Transformer本质其实就是对selt-attention的包装
- 论文《Attention is all you need》特点:
重点关注了复杂度,并行度,长距离依赖学习三个问题- 现在做神经翻译里最好的BLUE结果
- 没有采取大热的RNN/LSTM/GRU的结构,而是使用attention layer 和全连接层,达到了较好的效果,并且解决了 RNN/LSTM/GRU 里的long dependency problem
- 解决了传统RNN 训练并行度的问题,并降低了计算复杂度
Encoder-Decoder架构
Encoder-Decoder架构整体
- 在编码器的一个网络块中,由一个多头attention子层和一个前馈神经网络子层组成,整个编码器栈式搭建了N个块
- 解码器的一个网络块中多了一个多头attention层。为了更好的优化深度网络,整个网络使用了残差连接和对层进行了规范化(Add&Norm)
- 这里有个特别点就是masking, masking 的作用就是防止在训练的时候 使用未来的输出的单词。 比如训练时, 第一个单词是不能参考第二个单词的生成结果的。 Masking就会把这个信息变成0, 用来保证预测位置 i 的信息只能基于比 i 小的输出
Encode组件
Decode组件
- 编码器通过处理输入序列开启工作。顶端编码器的输出之后会变转化为一个包含向量K(键向量)和V(值向量)的注意力向量集 。这些向量将被每个解码器用于自身的“编码-解码注意力层”,而这些层可以帮助解码器关注输入序列哪些位置合适
- 接下来的步骤重复了这个过程,直到到达一个特殊的终止符号, - 它表示transformer的解码器已经完成了它的输出。每个步骤的输出在下一个时间步被提供给底端解码器,并且就像编码器之前做的那样,这些解码器会输出它们的解码结果
- 这个“编码-解码注意力层”工作方式基本就像多头自注意力层一样,只不过它是通过在它下面的层来创造查询矩阵,并且从编码器的输出中取得键/值矩阵
最终的线性变换和Softmax层
解码组件最后会输出一个实数向量。我们如何把浮点数变成一个单词?这便是线性变换层要做的工作,它之后就是Softmax层- 线性变换层是一个简单的全连接神经网络,它可以把解码组件产生的向量投射到一个比它大得多的、被称作对数几率(logits)的向量里
- 接下来的Softmax 层便会把那些分数变成概率(都为正数、上限1.0)。概率最高的单元格被选中,并且它对应的单词被作为这个时间步的输出
scaled dot-Product attention
- 核心理解
点积表示输入序列中两个向量的由学习任务定义的“相关”程度,并且输出向量是整个输入序列的加权和,其权重由这些点积确定 - 本质:其实scaled dot-Product attention就是我们常用的使用点积进行相似度计算的attention,只是多除了一个(为K的维度)起到调节作用,使得内积不至于太大
- 操作步骤
- 每个query-key 会做出一个点乘的运算过程
- 最后会使用soft max 把他们归一
- 再到最后会乘以V (values) 用来当做attention vector.
- 详细理解
Multi-head attention
- 核心:
我们必须考虑到一个词对不同的邻居有不同的意思,按照上面所描述,一个词对对应的输出也只是一个vector,只对应一种情况,但有些场景相同的语言,句子表达的含义完全不同,所以有了Multi head
Multi-head attention(1)
- 它扩展了模型专注于不同位置的能力
- 我理解就是不同的每个注意力头都会对会有不同的关注点,就是丰富了一个词的注意点
它给出了注意力层的多个“表示子空间”(representation subspaces)
- 接下来我们将看到,对于“多头”注意机制,我们有多个查询/键/值权重矩阵集(Transformer使用八个注意力头,因此我们对于每个编码器/解码器有八个矩阵集合)。这些集合中的每一个都是随机初始化的
- 在训练之后,每个集合都被用来将输入词嵌入(或来自较低编码器/解码器的向量)投影到不同的表示子空间中
如果我们做与上述相同的自注意力计算,只需八次不同的权重矩阵运算,我们就会得到八个不同的Z矩阵
前馈层不需要8个矩阵,它只需要一个矩阵(由每一个单词的表示向量组成)
- 所以我们需要一种方法把这八个矩阵压缩成一个矩阵。那该怎么做?其实可以直接把这些矩阵拼接在一起,然后用一个附加的权重矩阵WO与它们相乘
Multi-head attention(2)
- Query,Key,Value首先进过一个线性变换
- 然后输入到放缩点积attention
- 注意这里要做h次,其实也就是所谓的多头,每一次算一个头
- 每次Q,K,V进行线性变换的参数W是不一样的,所以每个头都计算自己的特征
- 进行h个头计算好处:好处是可以允许模型在不同的表示子空间里学习到相关的信息
- 然后将h次的放缩点积attention结果进行拼接(concat)
- 再进行一次线性变换得到的值作为多头attention的结果
如何使用attention
- 首先在编码器到解码器的地方使用了多头attention进行连接,编码器的层输出(这里K=V)和解码器中都头attention的输入。其实就和主流的机器翻译模型中的attention一样
- 在Encoder,Decoder中都使用的self-attention
- 例如输入一个句子,那么里面的每个词都要和该句子中的所有词进行attention计算。目的是学习句子内部的词依赖关系,捕获句子的内部结构
构建Transformer
- Transformer不只是一个self-attention层,它是一个架构。目前Transformer的定义还不清楚,但在这里我们将使用以下定义:
- 任何用于处理连接单元集 (connected units) 的体系结构——例如序列中的标记或图像中的像素——单元之间的唯一交互是通过self-attention
- 如何构建:大致的结构如下
- 各种组件的顺序不是一成不变的;重要的是将self-attention与本地前馈相结合,并添加归一化和残差连接
- 归一化和残差连接是用于帮助深度神经网络训练更快,更准确的标准技巧。归一化层仅作用于嵌入维度。
- 为什么这么设计?
结合了RNN和CNN的优势,改善他们的缺点:Transformer试图吸收两者的优点。它们可以对输入序列的整个范围建立依赖关系,就像它们彼此相邻的单词一样容易(事实上,没有位置向量,它们甚至无法区分) 。然而,这里没有循环连接- RNN问题
这里最大的弱点是循环连接,串行,并且时间步相隔较远的单元相互影响较小了 - CNN问题
在该模型中,每个输出向量可以与其他每个输出向量并行计算。这使得卷积更快。然而,卷积的缺点在于它们在模拟远程依赖方面受到严重限制。在一个卷积层中,只有相距比卷积核大小更小的单词才能相互交互。为了更长的依赖性,我们需要堆叠许多卷积
- RNN问题
Transformer解决问题
- 并行问题
- 首先each head, 是可以并行计算的, 然后每个head 都有自己对应的weight, 实现不同的线性转换, 这样每个head 也就有了自己特别的表达信息
- 多头attention和CNN一样不依赖于前一时刻的计算,可以很好的并行,优于RNN
- 长距离依赖学习
- self-attention是每个词和所有词都要计算attention,所以不管他们中间有多长距离,最大的路径长度也都只是1。可以捕获长距离依赖关系
- RNN,CNN计算复杂度的比较
- 如果输入序列n小于表示维度d的话,每一层的时间复杂度self-attention是比较有优势的。当n比较大时,作者也给出了一种解决方案self-attention(restricted)即每个词不是和所有词计算attention,而是只与限制的r个词去计算attention
训练部分&损失函数
Transformer只是一个encode-decode框架架构,后面的,训练&损失函数&优化算法就也能共用其他了,比如BP,集束搜索(beam search)…
- 既然我们已经过了一遍完整的transformer的前向传播过程,那我们就可以直观感受一下它的训练过程。
- 在训练过程中,一个未经训练的模型会通过一个完全一样的前向传播。但因为我们用有标记的训练集来训练它,所以我们可以用它的输出去与真实的输出做比较
Transformer应用
- transformer本身并不能识别单词直接次序,句子前后次序等,bert是对transformer很成功的应用,在输入上增加了其他的信息:比如位置嵌入,句子次序,mask等的预训练模型