Self-attention

针对输入是多个向量,且输入的向量数目可以改变的情况。

image-20210403221220604

向量集作为输入

在介绍算法之前,我们先讨论一下有多个向量输入的情况处理。

文字处理

假设我们今天要Network的输入是一个句子,每一个句子的长度都不一样,每个句子裡面词汇的数目都不一样

image-20210403221757797

如果我们把一个句子裡面的每一个词汇,都描述成一个向量,那我们的Model的输入,就会是一个Vector Set,而且这个Vector Set的大小,每次都不一样,句子的长度不一样,那你的Vector Set的大小就不一样。

怎麼把一个词汇表示成一个向量,最简单的做法是

One-Hot编码

image-20210403222112679

你就开一个很长很长的向量,这个向量的长度跟世界上存在的词汇的数目是一样多的,每一个维度对应到一个词汇,Apple就是100,Bag就是010,Cat就是001,以此类推

但是这样子的表示方法有一个非常严重的问题,它假设所有的词汇彼此之间都是没有关係的,从这个向量裡面你看不到:Cat跟Dog都是动物所以他们比较接近,Cat跟Apple一个动物一个植物,所以他们比较不相像。这个向量裡面,没有任何语义的资讯

Word Embedding

image-20210403222544230

Word Embedding就是,我们会给每一个词汇一个向量,而这个向量是有语义的资讯的

如果你把Word Embedding画出来的话,你会发现,所有的动物可能聚集成一团,所有的植物可能聚集成一团,所有的动词可能聚集成一团等等

Word Embedding,会给每一个词汇一个向量,而一个句子就是一排长度不一的向量

声音信号

一段声音讯号其实是一排向量,我们会把一段声音讯号取一个范围,这个范围叫做一个Window

image-20210404160614690

把这个Window裡面的数据描述成一个向量,这个向量就叫做一个Frame,在语音上,我们会把一个向量叫做一个Frame,通常这个Window的长度就是25个Millisecond

把这麼一个小段的声音讯号变成一个Frame,变成一个向量就有百百种做法,那这边就不细讲

一小段25个Millisecond裡面的语音讯号,為了要描述一整段的声音讯号,你会把这个Window往右移一点,通常移动的大小是10个Millisecond

image-20210404161620047

一段声音讯号,你就是用一串向量来表示,而因為每一个Window啊,他们往右移都是移动10个Millisecond,所以一秒鐘的声音讯号有100个向量,所以一分鐘的声音讯号,就有这个100乘以60,就有6000个向量

所以语音其实很复杂的,一小段的声音讯号,它裡面包含的资讯量其实是非常可观的

一个Graph 一个图,也是一堆向量,我们知道说Social Network就是一个Graph

image-20210404161854708

在Social Network上面每一个节点就是一个人,然后节点跟节点之间的edge就是他们两个的关系连接,比如说是不是朋友等等

每一个节点可以看作是一个向量,你可以拿每一个人的,比如说他的Profile裡面的资讯啊,他的性别啊 他的年龄啊,他的工作啊 他讲过的话啊等等,把这些资讯用一个向量来表示

所以一个Social Network 一个Graph,你也可以看做是一堆的向量所组成的

分子信息

一个分子,它也可以看作是一个Graph

image-20210404162239665

一个分子可以看作是一个Graph,分子上面的每一个球,也就是每一个原子,可以表述成一个向量

一个原子可以用One-Hot Vector来表示,氢就是1000,碳就是0100,然后这个氧就是0010,所以一个分子就是一个Graph,它就是一堆向量。

输出的情况

我们刚才已经看说输入是一堆向量,它可以是文字,可以是语音,可以是Graph,那这个时候,我们有可能有什麼样的输出呢,有三种可能性。

1. 每一个向量都有一个对应的Label

当你的模型,看到输入是四个向量的时候,它就要输出四个Label,而每一个Label,它可能是一个数值,那就是Regression的问题,如果每个Label是一个Class,那就是一个Classification的问题

image-20210404165717142

那这种输入跟输出数目一样多的状况又叫做Sequence Labeling

2. 一整个Sequence,只需要输出一个Label

image-20210404165454032

举例来说,如果是文字的话,我们就说情感分析,给机器看一段话,它要决定说这段话是正面的还是负面的

3. 机器要自己决定,应该要输出多少个Label

我们不知道应该输出多少个Label,机器要自己决定,应该要输出多少个Label,可能你输入是N个向量,输出可能是N’个Label,為什麼是N’,机器自己决定

image-20210404170045293

举例来说,翻译就是sequence to sequence的任务,因為输入输出是不同的语言,它们的词汇的数目本来就不会一样多。

Self-Attention

假设我们是在处理一个句子时,如何让Fully-Connected的Network,考虑更多的,比如说上下文的Context的特征?

这就是我们现在要讨论的 Self-Attention 。

Self-Attention的运作方式就是,Self-Attention会吃一整个Sequence的数据

image-20210404174805338

这4个Vector,他们都是考虑一整个Sequence以后才得到的。

Self-Attention不是只能用一次,你可以叠加很多次

image-20210404194146583

所以可以把Fully-Connected的Network,跟Self-Attention交替使用

  • Self-Attention处理整个Sequence的资讯
  • Fully-Connected的Network,专注於处理某一个位置的资讯
  • 再用Self-Attention,再把整个Sequence资讯再处理一次
  • 然后交替使用Self-Attention跟Fully-Connected

Self-Attention过程

我们用$a$来表示它,Self-Attention的Input就是一串的Vector。

image-20210404202435331

每一个b都是考虑了所有的a以后才生成出来的,所以如何a1与其他的a2…的关系怎么描述呢?

我们将每一个向量跟$a^1$的关联的程度,用一个数值叫α来表示

image-20210404204458431

这个计算attention的模组,就是拿两个向量作為输入,然后它就直接输出α那个数值

计算这个α的数值有各种不同的做法

  • 比较常见的做法呢,叫做用dot product(内积),输入的这两个向量分别乘上两个不同的矩阵,左边这个向量乘上$W^q$这个矩阵得到矩阵$q$,右边这个向量乘上$W^k$这个矩阵得到矩阵$k$

    再把$q$跟$k$做dot product,就是把他们做element-wise 的相乘,再全部加起来以后就得到一个 scalar,这个scalar就是α,这是一种计算α的方式

  • 有另外一个叫做Additive的计算方式,它的计算方法就是,把同样这两个向量通过$W^q$ $W^k$,得到$q$跟$k$,那我们不是把它做Dot-Product,是把它这个串起来,然后丢到这个过一个Activation Function,然后再通过一个Transform,然后得到α。

但是在接下来的讨论裡面,我们都只用左边这个方法,这也是今日最常用的方法,也是用在Transformer裡面的方法

详细介绍一下dot product

计算$a^1$的输出,就把$a^1$去跟这边的$a^2 a^3 a^4$,分别都去计算他们之间的关联性,也就是计算他们之间的α

image-20210404211656032

把$a^1$乘上$W^q $得到$q^1$,那这个q有一个名字,我们叫做Query

$a^2 a^3 a^4$你都要去把它乘上$W^k$,得到$k$这个Vector,$k$这个Vector叫做Key

把这个Query q1,跟这个Key k2,算Inner-Product就得到α,这个α这个关联性叫做Attention的Score,叫做Attention的分数。

接下来也要跟$a^3 a^4$来计算

image-20210404211950882

一般在实际工作中,$q^1$也会跟自己算关联性,自己跟自己计算关联性这件事情有多重要。

计算出a1跟每一个向量的关联性以后,接下来这边可以选择接入一个Soft-Max,不一定要用Soft-Max,用别的替代也没问题,如:RELU

image-20210404212945356

根据这个$α’$去抽取出这个Sequence裡面重要的资讯,根据这个α我们已经知道说,哪些向量跟$a^1$是最有关係的,怎麼抽取重要的资讯呢?

image-20210404213559086

  • 首先把$a^1$到$a^4$这边每一个向量,乘上$W^v $得到新的向量,这边分别就是用$v^1 v^2 v^3 v^4$来表示

  • 接下来把这边的$v^1$到$v^4$,每一个向量都去乘上Attention的分数,都去乘上$α’$

  • 然后再把它加起来,得到$b^1$

    所以谁的那个Attention的分数最大,谁的那个$v$就会在你抽出来的结果里占主导地位。

Self-Attention的特点

image-20210409092350116

  1. b1…b4的生成并没有依赖关系,所以可以并发同时处理每个输入向量。

矩阵的角度分析

首先,每一个 a 都产生q k v

image-20210409100334528

每一个 a,都乘上一个矩阵,我们这边用 $W^q$ 来表示它,得到 $q^i$,每一个 a 都要乘上 $W^q$,得到$q^i$,这些不同的 a 你可以把它合起来,当作一个矩阵来看待

image-20210409100755718

从 $a^1$ 到 $a^4$,得到 $q^1$ 到 $q^4$这个操作,其实就是把 I 这个矩阵,乘上另外一个矩阵 $W^q$,得到矩阵$Q$$W^q$其实是 network 的参数,它是等一下会被learn出来的

接下来產生 k 跟 v 的操作跟 q 是一模一样的

image-20210409101331347

所以每一个 a 得到 q k v ,其实就是把输入的这个vector sequence 乘上三个不同权重矩阵,你就得到了 q,k, v

下一步是,每一个 q 都会去跟每一个 k,去计算这个 inner product,去得到这个 attention 的分数

你可以看作是我们把 $k^1$ 到 $k^4$ 拼起来,当作是一个矩阵的四个 row,所以这些 attention 的分数可以看作是两个矩阵的相乘

image-20210409103622596

我们可能会在 attention 的分数,做一下 normalization,比如说你会做 softmax,你会对这边的每一个 column,每一个 column 做 softmax,让每一个 列 裡面的值相加是 1。

那我们把这个$v^1$ 到 $v^4$乘上这边的 α 以后,就可以得到 b

image-20210409105935046

总结:

所以其实整个 Self-attention,就是先根据3个权重矩阵产生了 q k v,然后再根据这个 q 去找出相关的位置,然后再对 v 做 weighted sum,其实这一串操作,就是一连串矩阵的乘法而已

image-20210409110638357

其中 $A’$,叫做Attention Matrix

Q矩阵就是为了得到Attention的score

其实 Self-attention 里,唯一需要学的参数,就只有 $W^q$ $W^k$ 跟$ W^v$ 而已

Multi-head Self-attention

Self-attention 有一个进阶的版本,叫做 Multi-head Self-attention,多相关性。

至於需要用多少的 head,这个又是另外一个 hyperparameter,也是你需要调的。

我们在做这个 Self-attention 的时候,我们就是用 q 去找相关的 k,但是相关这件事情有很多种不同的形式,有很多种不同的定义,所以也许我们不能只有一个 q,我们应该要有多个 q,不同的 q 负责不同种类的相关性

所以假设你要做 Multi-head Self-attention 的话,你会怎麼操作呢?

image-20210412193656512

  • 先把 a 乘上一个矩阵得到 q
  • 再把 q 乘上另外两个矩阵,分别得到 $q^1$ 跟 $q^2$,那这边还有 这边是用两个上标,i 代表的是位置,然后这个 1 跟 2 代表是,这个位置的第几个 q,所以这边有 $q^{i,1}$ 跟 $q^{i,2}$,代表说我们有两个 head。

这边只用了其中一个 head,那你会用另外一个 head,也做一模一样的事情。

image-20210412194533453

总结:

就是简单在Self-attention的基础上,将原来的1个相关条件q,扩展到多个。也就是多了几个q的权重矩阵,每个q直接的操作还是一样的。

考虑向量的位置

到目前為止,讲的 Self-attention 的操作裡面,根本就没有位置的资讯。

比如:我并不会决定第一个输入向量和第二个输入向量有什么关系,但是在句子里,前后的关系也很重要。

如何考虑位置的关系呢? 这边就要用到一个叫做 positional encoding 的技术

image-20210412201736447

为每一个位置设定一个 vector,叫做 positional vector用 $e^i$ 来表示,上标 i 代表是位置,每一个不同的位置,就有不同的 vector,就是 $e^1$ 是一个 vector,$e^2$ 是一个vector,$e^{128}$ 是一个vector,不同的位置都有一个它专属的 e,然后把这个 e 加到 $a^i$ 上面,就结束了

就是告诉你的 Self-attention,位置的资讯,如果它看到说 $a^i$ 好像有被加上 $ e^i$,它就知道说现在出现的位置,应该是在 i 这个位置。

总结:positional encoding仍然是一个尚待研究的问题

应用

Self-attention 目前在NLP方向应用广泛,如:Transfer、BERT都有用到。

但除了NLP、在语音、图像上也能使用。

Self-attention for Speech

在做语音的时候,会对 Self-attention,做一些小小的改动。

因为要把一段声音讯号,表示成一排向量的话,这排向量可能会非常地长

Truncated Self-attention

Truncated Self-attention 做的事情就是,我们今天在做 Self-attention 的时候,不要看一整句话,就我们就只看一个小的范围就好

那至於这个范围应该要多大,那个是人设定的

image-20210412210322691

其效果类似于MBGD、不考虑全部的影响,只考虑一个范围的数据。

在做语音识别的时候,也许只需要看一个小的范围就好,这个范围取决於你对这个问题的理解

Self-attention for Image

Self-attention 适用的范围是:输入是一个 vector set 的时候。

一张图片啊,我们把它看作是一个很长的向量,那其实一张图片,我们也可以换一个观点,把它看作是一个 vector 的 set

image-20210412214143979

如图,每一个 pixel,其实就是一个三维的向量,那整张图片,其实就是 5 乘以 10 个向量的set

Self-attention v.s. CNN

其实 Self-attention 和 CNN是一个意思。Self-attention 是一个复杂化的 CNN

image-20210412215451745

CNN是考虑一个卷积核大小的关系、而Self-attention是考虑某点对整张影像的关系。

在CNN中 receptive field 的范围跟大小,是人决定的

而在 Self-attention 中 receptive field 的范围,不再是人工划定,而是让机器自己学出来

image-20210412215841085

CNN就是 Self-attention 的特例,Self-attention 只要设定合适的参数,它可以做到跟 CNN 一模一样的事情

Self-attention v.s. RNN

image-20210413093042847

在 RNN 裡面

  • 左边是你的 input sequence,你有一个 memory 的 vector
  • 然后你有一个 RNN 的 block,这个 RNN 的 block 呢,它吃 memory 的 vector,吃第一个 input 的 vector
  • 然后 output 一个东西,然后根据这个 output 的东西,我们通常叫做这个 hidden,这个 hidden 的 layer 的 output
  • 然后通过这个 fully connected network,然后再去做你想要的 prediction

RNN通过前面的输入向量的结果传递给后者,相当于后面的输出会考虑前面的,但前面的输出不会考虑后面的。这个问题可以通过双向RNN解决。但因为前后的依赖关系导致RNN 是没有办法平行化的

Self-attention for Graph

Graph 也可以看作是一堆 vector,那如果是一堆 vector,就可以用 Self-attention 来处理。

image-20210413154403199

在 Graph 上面,每一个 node 可以表示成一个向量,但不只有 node 的资讯,还有 edge 的资讯

在做 Self-attention 的时候,所谓的关联性是 network 自己找出来的,但是现在既然有了 edge 的资讯,那关联性q也许就不需要透过机器自动找出来,这个图上面的 edge 已经暗示了我们,node 跟 node 之间的关联性

只计算有 edge 相连的 node 就好,不相连的node,既然没有关係,我们就不需要再去计算它的 attention score,直接把它设為 0 就好了