Transformer - 注意力机制

91 阅读9分钟

1. Self-attention

自注意力机制。

解决的问题:到目前为止,我们的Input都是一个向量,输出是一个数值或者一个类别。如果我们的输入是一排向量,且输入的向量的输入数目会改变,那么该怎么处理?

|200

如,我们输入一个句子,句子长短不一样,那么输入的向量数目就会不一样。

将一个词汇表示成一个向量

  • 使用one-hot encoding方法

    |345

  • 使用word embedding方法

    |345

声音、图等等都是可以表示成一堆向量。

输出类型:

  • 每个向量都有一个对应的label(Sequence Labeling)

    |555

  • 整体只需要输出一个label

    |590

  • 不知道该输出多少个label,机器自己决定应该输出多少个label,这种任务叫做seq2seq

    |590

    如:翻译,语音转文字等。

现在,只考虑每个向量都有一个对应的label

像词性分类,如下

|505

这样,显然存在很大的问题,对于saw在这里面既是名词,又是动词。所以,我们就想让全连接层考虑更多的上下文信息。

|550

但是,如上这种方法还是存在问题的。如果我们有某一个任务,不是要考虑一个window就可以解决的,而是要考虑一整个序列信息才能解决,那么该怎么解决呢?如果简单的将window扩大,但是这样会存在问题,全连接层的参数量会非常大。

解决方法:Self-Attention

|505

Self-attention可以叠加很多次。

|500

Self-attention原理

输入为一串的向量,它可能整个网络的输入,也可能是某个隐藏层的输出。

|545

那么,对于具体每个输出向量是怎么产生的呢?

对于b1b^1向量怎么产生,首先根据a1a^1找出输入序列里面跟a1a^1相关的其他向量。其他向量和a1a^1关联的程度用数值α\alpha进行表示。

|610

那么,self-attention怎么自动决定两个向量的关联性呢?

需要一个计算attention的模组,输入两个向量,输出两个向量的关联性α\alpha

那么,对于α\alpha的值具体怎么计算呢?

有很多不同的办法,如Dot-productAdditive等。

  • Dot-product

    将两个输入向量,分别乘上两个不同的矩阵,然后得到qkq,k两个向量,然后将qkq,k做点积,结果就是α\alpha

    |355

  • Additive

    |325

总之,有很多不同的方法来计算α\alpha。最常用的方法,也是用在Transformer中的方法就是Dot-product

将该方法运用在Self-attention中:

q:query

k:key

a1a^1分别与其他向量进行计算关联性α\alpha。将a1a^1乘以WqW^q得到q1q^1,其他向量a2,a3,a4a^2,a^3,a^4分别乘以WkW^k得到k2,k3,k4k^2,k^3,k^4

如,q1=Wqa1q^1 = W^qa^1k2=Wka2k^2=W^ka^2。那么,α1,2=q1k2\alpha_{1,2}=q^1·k^2

这个α\alpha关联性也被称作attention score

|595

一般在实际操作的时候,a1a^1也会和自己算关联性,得到k1=Wka1k^1 = W^ka^1

计算出a1a^1和其他每个向量的关联性后,后面会跟上一个softmax激活函数。这里不一定要用softmax,或者可以尝试使用ReLU或者其他。

|530

得到α\alpha'后,我们就要根据关联性α\alpha'抽取出这个序列中重要的信息。

那么,怎么抽取重要的信息呢?

a1,a2,a3,a4a^1,a^2,a^3,a^4每个向量乘上WvW^v得到新的向量v1,v2,v3,v4v^1,v^2,v^3,v^4。然后,将v1,v2,v3,v4v^1,v^2,v^3,v^4每个向量分别乘上对应的α\alpha',最后将结果进行相加。

|580

从矩阵计算角度进行分析:qi=Wqaiq^i=W^qa^i

可以将这些aa合起来,组成一个矩阵,如

|415

我们将aa组成的矩阵用II进行表示,将结果qq组成的矩阵用QQ进行表示。所以,即Q=WqIQ=W^qI

同理,ki=Wkaik^i=W^ka^i,即K=WkIK=W^kI

图片转存失败,建议将图片保存下来直接上传

vi=Wvaiv^i=W^va^i,即V=WvIV=W^vI

|425

对于,求α\alpha的过程,我们也可以看作是矩阵与向量相乘的过程:

|500

我们可以把k1,...,k4k^1,...,k^4拼起来作为矩阵的4行,则

|427

上面,仅仅是对a1a^1来求对应的α\alpha,那么对于全部的向量,则

|515

由此,上述过程,可以看作是两个矩阵相乘。即,可以写成A=KTQA = K^TQ

计算出α\alpha'后,然后分别乘以viv^i,然后相加,就可以得到最后的结果。即O=VAO = VA'

|500

整体过程

|495

self-attention layer里面要学的参数仅仅为:Wq,Wk,WvW^q,W^k,W^v


2. Multi-head Self-attention

多头注意力机制。

是self-attention的一个进阶版本。

并不是所有的任务都适合用比较少的head,比如说翻译等,使用比较多的head可以得到比较好的结果。

使用多少个head,这是一个超参数,是需要调整的。

为什么需要多个head呢?相关这件事情,在做self-attention时,我们使用qq去找相关的kk。但是相关这一事情,有很多不同的形式。

所以,我们也许不能只有一个qq,我们应该有多个qq,不同的qq负责不同种类的相关性。

先让aia^i乘上矩阵WqW^q得到qiq^i,然后在把qiq^i乘上另外两个矩阵,得到qi,1qi,2q^{i,1},q^{i,2}。同理,获得kvk和v。对于其他位置,也是同理获得多个q,k,vq,k,v

接下来,做self-attention的时候,1类的一起做,2类的一起做。

|500

|515

得到bi,1bi,2b^{i,1}和b^{i,2}后,将它们接起来,然后乘上一个矩阵得到bib^i,然后送到下一层。


3. Positional Encoding

self-attention这一层少了位置信息。

这样的设计,可能会有一些问题,有时候位置的信息很重要。

当我们在做self-attention的时候,如果我们觉得位置信息是非常重要的,那我们可以把位置的信息塞进去。

那怎么把位置的信息塞进去呢?

使用positional encoding技术。

为每个位置设置一个vector,叫做positional vector,使用eie^i进行表示。每个不同的位置有不同的vector。

把这个eie^i加到aia^i上面就可以了。

|334

positional vector是手动设置的。

但是positional vector是可以通过学习获得的。

self-attention不是只可以用在NLP相关的应用上,它还可以用在其他的问题上。

|500

BERT(Bidirectional Encoder Representations from Transformers)和DETR(DEtection Transfomer)是两个不同领域的深度学习模型。

  • BERT主要应用于自然语言处理(NLP)领域。它是一种预训练的语言模型,使用Transformer架构进行训练。BERT能够理解上下文关系,因为它是双向的(Bidirectional),能够同时考虑输入文本的前后文信息。BERT的预训练模型在多个NLP任务上表现出色,包括文本分类、命名实体识别、问答等。
  • DETR则主要应用于计算机视觉领域,特别是目标检测。它采用了Transformer架构,但不同于传统的目标检测方法,DETR将目标检测任务转化为一个端到端的Transformer问题,消除了传统两阶段目标检测方法的需要。DETR在目标检测任务上取得了一些令人瞩目的成果。

在self-attention处理图像时

|590

|710

Self-attention v.s. CNN

CNN:可以看作是简化版的self-attention,只考虑临近区域的信息。

self-attention:考虑整张图片的信息。


4. Transformer

Transformer是Sequence-to-sequence(Seq2seq)的model。

Sequence-to-sequence:输入是一个sequence,输出是一个sequence,但是我们不知道输出的长度,由机器自己决定输出的长度。

如:语言辨识,翻译等。

Seq2seq可以分为两块:Encoder和Decoder。

|485

4.1 Encoder

encoder做的就是输入一排向量,输出一排向量。

|565

Encoder里面会分为很多block,每个block输入一排向量,输出一排向量。每个block是好几个layer组成。

在transformer的encoder里面:每个block,先做self-attention,然后经过全连接层。

|575

在原Transformer中做的是更复杂的。

在Transformer中,加入了一个设计,经过self-attention后,输出一个向量,我们要把输出的这个向量与它本身输入相加,得到输出。这样的操作叫做residual connection。

得到输出后,再将输出进行Layer Normalization。Layer Normalization不需要考虑batch。Layer Normalization计算输入向量的平均值和标准差,Layer Normalization对同一个feature,同一个example里面,不同的dimension去计算平均值和标准差。计算出平均值和标准差后做Normalization。得到Normalization的输出,这个输出才是全连接层的输入。

全连接层也使用了residual connection的架构。经过redisual后,将输出再做一次layer normalization,得到的输出才是一个block的输出。

|615

4.2 Decoder

decoder要做的就是产生输出。其要先读入encoder的输出。

Decoder分为两种:Autoregressive(AT)Non-autoregressive(NAT)

4.2.1 Autoregressive

对于语音识别,Decoder怎么能产生一段文字呢?

首先给decoder一个特殊的符号,这个特殊的符号代表开始BOS(special token)。在decoder本来可能产生的文字里面多加一个特殊的字,这个字就代表了开始begin。得到一个输出向量,这个向量的长度,对于中文来说,可能就是汉字的数量。每一个字都会对应到一个数值,值最高的对应的字就是最终的输出。比如这个字。

|585

然后将出了将begin作为输入外,还将作为decoder的输入,然后得到一个输出,。然后再将也作为输入,最后输出。然后再将也作为输入,最后输出

|580

decoder得到的输入,其实是它在前一个时间点自己的输出。也就是说,decoder可能会得到一个错误的输入。那这样可能会造成一步错步步错的问题。

decoder结构

在transformer中,decoder的结构:

|570

self-attentionMasked Self-attention

|525

也就是,产生b1b^1的时候,只能考虑a1a^1的信息,产生b2b^2的时候,只能考虑a1a2a^1,a^2的信息。以此类推。

更具体一点:比如在计算b2b^2的时候,只用a2a^2q2q^2k1k2k^1与k^2进行计算不需要去管其他的k。

那为什么需要加masked呢?

因为decoder的运作方式,输出是一个一个产生的,先有a1,再有a2,再有a3...a^1,再有a^2,再有a^3...

原来的self-attention,a1a4a^1-a^4是一次性整个输入到模型里面的。也就是说,对于Mask self-attention,在计算b2b^2的时候a3a4a^3,a^4还不存在,所以没有办法让其参与进来。

还有一个非常关键的问题,decoder必须自己决定输出的序列的长度。也就是说,对于上面的例子,可能输出之后,可能又将作为新的输入,然后再输出,然后一直进行下去…

所以,我们要让decoder输出一个,我们需要准备一个特殊的符号,用End来表示。

|590

这样,当输出之后,再将作为新的输入,这时输出应该得到End。然后整个encoder的运作过程就结束了。

4.2.2 Non-autoregressive

NAT不是一次产生一个字,而是一次把整个句子产生出来。

|575

但是,我们不是不知道输出的长度说多少吗?那begin该给多少个呢?

解决方法:

  • 另外设置一个分类器,这个分类器将encoder的输出作为输入,输出是数字,这个数字代表encoder应该要输出的长度。
  • 给它一堆begin,假设这个句子的长度绝对不会超过300个字,那就给它300个begin,然后看其什么地方输出了End,然后将后面的输出忽略掉。

NAT的优点

  • 并行化 。
  • 可以控制输出的长度。

4.3 Encoder-Decoder

encoder与decoder连接。

|495

Cross attention的两个输入来自于encoder,一个输入来自于decoder。

|585

4.4 Training

|600