0%

vision_transformer

vision transformer

transformer的自注意力机制解读

本质上是对RNN无法实现并行计算的一种改进(并且这种改进本质上就是通过简化的举证乘法来实现的)

使用RNN(单向或者双向)去处理sepuence—to—sepuence时,对于输入序列 输出为序列 ,在双向RNN的情况在,对于每一个输出序列中的元素 都是和全部的 相关的,但是对于RNN中存在一个问题,不便于实现并行优化。要计算 必须逐个处理

RNN

因此提出自注意力机制的思想就是:希望对于输出变量 和每一个 都相关(也就是能够看到每一个序列,并且还希望即可向前看又能够向后看),并且希望他是能够进行并行计算的。

实现方式:在query,key,value的基础上通过矩阵运算实现。

query and key

首先,对于输入序列进行embeding得到相应的嵌入编码 ,然后对于每一个向量 ,与三个transformation矩阵相乘得到 query 、key 、value

在此基础上进一步计算attention值(本质上就是在计算两个向量之间的相似性,相似性越大,那么在对当前向量进行预测是,就应该对其他向量赋予更加多的注意力),计算方式就是简单的向量内积,只需要计算一个权值。

然后得到四个注意力值 ,使用softMax对其进行归一化,在完成归一化后,相应的权值与value值做乘法,再累加(本质上就是加权平均,让当前向量的value值与其他向量的value相关)

compute_value

在此基础上实现并行计算:首先是完成嵌入编码,在此基础上在计算每一个向量的query、key、value值。嵌入编码 直接和transformation矩阵做乘法得到(矩阵乘法,最后的值也是矩阵,但是在矩阵中的列向量对应的就是相应的qkv值)

matrix_compute

接下来就是query矩阵和key矩阵计算attention值,此处的计算方式是向量的内积。但是本质上还是基于矩阵运算实现,将key矩阵进行转转置即可。然后进行矩阵乘法,这样就能够计算出全部向量的注意力值(每个向量的注意力值本质上也是一个向量)

attention_compute

attention_compute_2

attention_compute_3

多头的自注意力机制

将上述的self-attention,扩展为两头计算,对于一个嵌入编码 分别计算 相同的key和value也如此计算,那么最后能够得到两个权重值 ,将两个权重值进行连接,然后再利用一个transformation矩阵去计算最终的 Multi-Head Attention矩阵

multi-scaled-attention-contact

contact-output

使用这种多头的注意力机制,就能够实现不同的关注,比如让其中一头的注意力机制更加关心全局信息,另外一头更加关注于局部信息。

位置编码

在上述实现中,将序列中每一个向量都是平等的对待的,并不包含相应的位置信息(在计算key value query时并有考虑相应的位置信息)

在每一个词向量处设定一个位置编码 ,将这个位置编码与词向量叠加作为新的嵌入编码作为模型的输入: (位置编码是人工设定的,基于公式计算得到)

position_encoding

采取相加而没有采取concat的原因在于:对于采取concat的方式,为保持模型输入的维度必然需要与transformation矩阵做乘法,在做完乘法后实际上也就转化为了相加的形式:

位置编码的实现方式:

pos是单词的位置,i是Positional Encoding的维度,取值范围是: 对于第一个位置上的向量进行位置编码的结果为:

使用self-attention替代encoder-decoder中的RNN:

encoder_decoder

将这种自注意力机制应用于图像处理,也就是在处理当前像素时,可计算整张图像的attention值,原本的固定的CNN的感受野,转变到现在的自学习的感受野。

transformer的总体架构

transformer_network

  • encoder部分

在上述框架中encoder部分,绿色的block总计有n个,并且编码的方式为(FFN是一个前馈网络):

  • decoder阶段

在decoder阶段,绿色的block部分依旧会重复N次,Masked Multi-Head Self-attention,masked的意思是使attention只会attend on已经产生的sequence。

decoder的输出是,对应i位置的输出词的概率分布。

在transformer中的encoder过程是能够实现并行计算的,但是在decoder阶段并不能进行并行计算。需要按照RNN的方式去进行处理。(实际上只有在测试阶段才会采取RNN的方式去进行处理,在训练阶段通过mask的方式依旧是在进行并行运算的。)

  • 包含两个 Multi-Head Attention 层。
  • 第一个 Multi-Head Attention 层采用了 Masked 操作。
  • 第二个 Multi-Head Attention 层的Key,Value矩阵使用 Encoder 的编码信息矩阵 进行计算,而Query使用上一个 Decoder block 的输出计算。
  • 最后有一个 Softmax 层计算下一个翻译单词的概率(上述条件是对每一个decoder层都成立的)

此处的mask操作,为的是在翻译的过程,处理第i个单词时只能使用与第i个以及它之前的信息,在self-attention的基础上加入了一个mask操作。

mask_self_attention

在上图的实现方式中:

  1. 输入矩阵包含 “\< Begin > I have a cat” (0, 1, 2, 3, 4) 五个单词的表示向量,Mask是一个 5×5 的矩阵。在Mask可以发现单词 0 只能使用单词 0 的信息,而单词 1 可以使用单词 0, 1 的信息,即只能使用之前的信息。
  2. 得到 Attention矩阵 ,此时先不急于做softmax的操作,而是先于一个 Mask矩阵相乘,使得attention矩阵的有些位置归0,得到Masked Attention矩阵 。Mask矩阵是个下三角矩阵,想在计算矩阵的某一行时,只考虑它前面token的作用。即:在计算第一行时,刻意地把矩阵第一行的后面几个元素屏蔽掉,只考虑 。在产生have这个单词时,只考虑 I,不考虑之后的have a cat,即只会attend on已经产生的sequence,这个很合理,因为还没有产生出来的东西不存在,就无法做attention。
  3. Masked Attention矩阵进行 Softmax,每一行的和都为 1。但是单词 0 在单词 1, 2, 3, 4 上的 attention score 都为 0。得到的结果再与 矩阵相乘得到最终的self-attention层的输出结果
  4. 将多头注意力机制的结果进行concat,做线性变换输出最终的结果。

:第2个Multi-Head Self-attention的query来自第1个Self-attention layer的输出,key、value来自Encoder的输出

通常将key、value视为句子/图片的内容信息,将query视为一种引导信息(那么在decoder中,这种引导信息的来源就是已经完成翻译的词向量)

最后得到transformer的总体结构:

transformer_network_detailed

vision transformer的前向传播基本流程

patch & position embeding

思想:将CV问题也转化为seq2seq问题,并且需要减少计算的复杂度。

实现:将一个 的图片进行分片,按照每一个patch: 进行划分,那么将会得到196个patch(此处可以将每一个patch理解为nlp领域的单词,每一个单词的编码为 ),那么输入序列的长度为 196。输入数据的维度为 然后将其输入到一个线性层进行embeding操作。线性层的维度为 输出结果依旧是

在此基础上加入一个额外的token(借鉴nlp领域,cls)在transformer encoder中计算的是每个patch之间的自注意力,无法选择最终哪一个patch的输出去实现分类,因此加入一个cls,让他和其他的patch进行注意力的计算,将cls的输出作为分类的依据,因此输入encoder的矩阵为

位置编码:使用一个表实现,表总计196行(和patch的数量保持一致),每一行对应的一个向量,向量的维度为768,对于位置信息是直接加到输入向两中的(直接做对应位置的加法)

transformer encoder

vision_transformer_encoder

接下来就是一个标准的transformer的encoder,首先是layer norm 维度不发生改变,在此基础上转化为三个 q,k,v,三个 q,k,v的维度和多头自注意力的头数有关,假设存在n个头,那么每一个 q,k,v的维度就是 ,在进行完多头注意力后需要将每一个头的输出进行拼接。

在后续的MLP层中,通常是先将维度放大四倍,在对其进行还原。最终序列的输出依旧是 在此基础上,对tansformer encoder进行叠加,得到一个L层的transformer encoder。

-------------本文结束感谢您的阅读-------------

欢迎关注我的其它发布渠道