Transformer - 注意力机制

1. Self-attention

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

|595

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

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

  • 使用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

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

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

|544

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

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

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

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

  • Dot-product

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

    |355

  • Additive

    |325

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

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

q:query

k:key

\(a^1\)分别与其他向量进行计算关联性\(\alpha\)。将\(a^1\)乘以\(W^q\)得到\(q^1\),其他向量\(a^2,a^3,a^4\)分别乘以\(W^k\)得到\(k^2,k^3,k^4\)

如,\(q^1 = W^qa^1\)\(k^2=W^ka^2\)。那么,\(\alpha_{1,2}=q^1·k^2\)

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

|595

一般在实际操作的时候,\(a^1\)也会和自己算关联性,得到\(k^1 = W^ka^1\)

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

|530

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

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

\(a^1,a^2,a^3,a^4\)每个向量乘上\(W^v\)得到新的向量\(v^1,v^2,v^3,v^4\)。然后,将\(v^1,v^2,v^3,v^4\)每个向量分别乘上对应的\(\alpha'\),最后将结果进行相加。

|580

从矩阵计算角度进行分析:\(q^i=W^qa^i\)

可以将这些\(a\)合起来,组成一个矩阵,如

|415

我们将\(a\)组成的矩阵用\(I\)进行表示,将结果\(q\)组成的矩阵用\(Q\)进行表示。所以,即\(Q=W^qI\)

同理,\(k^i=W^ka^i\),即\(K=W^kI\)

|420

\(v^i=W^va^i\),即\(V=W^vI\)

|425

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

|500

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

|427

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

|515

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

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

|500

整体过程

|495

self-attention layer里面要学的参数仅仅为:\(W^q,W^k,W^v\)


2. Multi-head Self-attention

多头注意力机制。

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

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

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

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

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

先让\(a^i\)乘上矩阵\(W^q\)得到\(q^i\),然后在把\(q^i\)乘上另外两个矩阵,得到\(q^{i,1},q^{i,2}\)。同理,获得\(k和v\)。对于其他位置,也是同理获得多个\(q,k,v\)

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

|500

|515

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


3. Positional Encoding

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

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

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

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

使用positional encoding技术。

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

把这个\(e^i\)加到\(a^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

也就是,产生\(b^1\)的时候,只能考虑\(a^1\)的信息,产生\(b^2\)的时候,只能考虑\(a^1,a^2\)的信息。以此类推。

更具体一点:比如在计算\(b^2\)的时候,只用\(a^2\)\(q^2\)\(k^1与k^2\)进行计算不需要去管其他的k。

那为什么需要加masked呢?

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

原来的self-attention,\(a^1-a^4\)是一次性整个输入到模型里面的。也就是说,对于Mask self-attention,在计算\(b^2\)的时候\(a^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

posted @ 2025-03-12 22:50  mango0219  阅读(65)  评论(0)    收藏  举报