清明假期被封在家里,我就利用这三天时间学习了下著名的Transfomer,参考的主要是Blibli UP主霹雳吧啦Wz的视频教程,过程有不懂的我就自己查资料,补充了一些自己的理解观点,目前还没有机会对Transformer进行实践,只是进行了简单的理论学习,有问题欢迎读者指出交流。
参考内容:
11.1 Vision Transformer(vit)网络详解
Vision Transformer 超详细解读 (原理分析+代码解读) (一)
12.1 Swin-Transformer网络结构详解
Transformer来源于2017年的一篇论文《Attention Is All You Need》,Transformer的提出最开始是针对NLP领域的,在此之前,NLP领域里使用的主要是RNN、LSTM这样一些网络,这些网络都存在一些问题,一方面是记忆长度有限,另一方面是无法并行,而Transeformer理论上记忆长度是无限长的,并且可以做到并行化。
而Vision Transformer是2020年发表于CVPR的论文《An Image Worth 16x16 Words: Transformers for Image Recognition as Scale》提出的,论文性能对比如下:
其中,Position Encoder主要是由Norm Block、Multi-Head Attention Block和MLP Block构成,MLP Block的结构由Linear+GELU+Dropout+Linear+Dropout的结构构成,Norm Block和Multi-Head Attention的结构可以参看下面的关键知识点。
用于输出的MLP Head可以为Linear+Tanh+Linear的结构或者直接为一层Linear,具体结构可以根据不同数据集做适当改变。
论文中一共给出了三种网络结构:
其中Layer为Transform Encoder重复堆叠的个数,Hidden Size为通过Embedding层后每个Token的维度,MLP Size是Transformer Encoder中MLP Block第一个全连接的节点个数,Heads代表Mutli-Head Attention的Head数。
Self-Attention是Transformer中最重要的模块之一,Self-Attention最核心的公式就是下面这三个: Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text { Attention }(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) V Attention (Q,K,V)=softmax(dkQKT)V MultiHead ( Q , K , V ) = Concat ( h e a d 1 , … , head h ) W O \left.\operatorname{MultiHead}(Q, K, V)=\operatorname{Concat}( \mathrm{head}_{1}, \ldots, \text { head }_{\mathrm{h}}\right) W^{O} MultiHead(Q,K,V)=Concat(head1,…, head h)WO where head = Attention ( Q W i Q , K W i K , V W i V ) \text { where head }=\text { Attention }\left(Q W_{i}^{Q}, K W_{i}^{K}, V W_{i}^{V}\right) where head = Attention (QWiQ,KWiK,VWiV)下面我们先对第一个公式展开来讲,其过程分为如下图所示:
其中图中最下方的 x 1 x_1 x1和 x 2 x_2 x2为输入向量,在Vision Transformer中就是输入的图像Patch,图中最上方的 b 1 b_1 b1和 b 2 b_2 b2为经过Self-Attention编码后输出的特征,我将其中的步骤分为五步:
Step1:通过Embedding层将输入向量映射到一个更高的维度上。在Vision Transformer中这里有一层卷积层构成,这里我们可以先简单将其理解为将向量 x 1 x_1 x1和 x 2 x_2 x2映射通过某个函数 f ( x ) f(x) f(x)映射到了向量 a 1 a_1 a1和 a 2 a_2 a2。
Step2:将向量向量 a i a_i ai分别与矩阵 W q W_q Wq, W k W_k Wk和 W v W_v Wv相乘得到 q i q_i qi, q k q_k qk和 q v q_v qv。在Vision Transformer中这里是由三个MLP组成,如果我们忽略偏置的话,我们就可以将抽象为三个矩阵, W q W_q Wq, W k W_k Wk和 W v W_v Wv三个矩阵的参数是可以学习的,且针对不同的 a i a_i ai参数是共享的。
其中, q i q_i qi是从 a i a_i ai中提取的用于进行匹配的向量,我们称为query。 k i k_i ki是从 a i a_i ai中提取的待匹配的向量,我们称为key。 v i v_i vi是从 a i a_i ai中提取的用于描述信息的向量,我们成为value,在接下来的步骤中我们将利用不同 a i a_i aiquery和key进行点乘获得权重,再利用该权重对value进行加权平均或者最后的输出。
Step3:依次遍历所有的 q i q_i qi和 k i k_i ki以 o ( n 2 ) o(n^2) o(n2)的计算复杂度进行向量点乘获得 α i \alpha_i αi, α i \alpha_i αi其实描述的是不同 a i a_i ai之间的一种相似性,由于是点乘,这里的 α i \alpha_i αi已经是一个标量 α 1 , i = q 1 ⋅ k i / d \alpha_{1, i}=q^{1} \cdot k^{i} / \sqrt{d} α1,i=q1⋅ki/d α 2 , i = q 2 ⋅ k i / d \alpha_{2, i}=q^{2} \cdot k^{i} / \sqrt{d} α2,i=q2⋅ki/d . . . ... ...其中 d d d为向量的长度。
Step4:将 α i \alpha_i αi经过一个Softmax进行归一化得到 β i \beta_i βi, β i \beta_i βi就是我们对 v i v_i vi进行加权的权重,因为 q i q_i qi和 k i k_i ki都是等长的向量,因此上述Step3和Step4的操作其实就是 q i q_i qi和 k i k_i ki组成的两个矩阵 Q Q Q和 K K K进行矩阵乘法: softmax ( Q K T d k ) \operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) softmax(dkQKT)
Step5: β i \beta_i βi与 v i v_i vi进行加权平均就得到最后输出 b i b_i bi,因此以上整个流程可以抽象为我们上述给出的第一个公式: Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text { Attention }(Q, K, V)=\operatorname{softmax}\left(\frac{Q K^{T}}{\sqrt{d_{k}}}\right) V Attention (Q,K,V)=softmax(dkQKT)V这部分操作其实就是一堆矩阵操作,如下图所示,因此可以进行GPU加速:
将上述Self-Attention的流程整理清楚后,Multi-Head Self-Attention的计算过程如下图所示:
上图展示的是head=2情况,可以看出来,所谓Multi-Head其实就是将 q i q_i qi, q k q_k qk和 q v q_v qv这几个向量均分成几部分,然后分别给计算后面的权重和加权求和结果,结构非常类似于Group卷积,最后 b i 1 b_{i1} bi1和 b i 2 b_{i2} bi2是通过Concatenate的操作输出的。因此Mutli-Head的计算公式为: MultiHead ( Q , K , V ) = Concat ( h e a d 1 , … , head h ) W O \left.\operatorname{MultiHead}(Q, K, V)=\operatorname{Concat}( \mathrm{head}_{1}, \ldots, \text { head }_{\mathrm{h}}\right) W^{O} MultiHead(Q,K,V)=Concat(head1,…, head h)WO where head = Attention ( Q W i Q , K W i K , V W i V ) \text { where head }=\text { Attention }\left(Q W_{i}^{Q}, K W_{i}^{K}, V W_{i}^{V}\right) where head = Attention (QWiQ,KWiK,VWiV)Multi-Head的优势在哪儿呢?如下图所示,绿色的部分是一个head的query和key,而红色部分则是另一个head的query和key,我们可以看出来,红色head更关注全局信息,绿色head更关注局部信息,Multi-Head的存在其实就是是的网络更加充分地利用了输入的信息:
了解了Self-Attention的结构后,我们其实应该能够理解为什么Transformer的效果比传统的CNN效果要好,使用CNN的时候一个卷积核只能获得其感受野内的信息,而感受野的范围和大小是人为决定的,但是在Transformer中,是通过Self-Attention中去全局中搜索相关的信息,就像是感受野是的范围和大小是通过学习获得的,因此CNN可以看作是一种简化版的Transformer。
从上述Self-Atttention或者Mutli-Head Self-Attention的结构我们可以发现一个问题,假如由三个输入,我们修改后两个输入的顺序,对于第一个输入的结构是完全没有影响的,也就是说“我和你”和“我你和“可能表征的是同一个意思,这种问题的发生是因为Self-Attention模块的输入中并没有位置相关的信息。解决该问题的方法就是Positional Embedding,结构如下图所示:
Position Embedding结构其实就是原始的Embedding层 a i a_i ai上加上一个Position Embedding的向量 e i e_i ei向量,然后再送入后面的运算过程,向量 e i e_i ei通常是人工设定的一个值,那么为什么是采用相加这种方式来表达位置关系呢?有解释如下:
假设我们给每一个位置的 x i ∈ R ( d , 1 ) x_{i} \in R(d, 1) xi∈R(d,1)并上一个One-Hot编码的向量 p i ∈ R ( N , 1 ) p_{i} \in R(N, 1) pi∈R(N,1),得到一个新的输入向量 x i p ∈ R ( d + N , 1 ) x^{p}_{i} \in R(d+N, 1) xip∈R(d+N,1),然后我们乘以一个变换矩阵 W = [ W I , W P ] ∈ R ( d , d + N ) W=\left[W_{I}, W_{P}\right] \in R(d, d+N) W=[WI,WP]∈R(d,d+N),那么有: W ⋅ x i p = [ W I , W P ] ⋅ [ x i p i ] = W I ⋅ x i + W P ⋅ p i = a i + e i W \cdot x^{p}_{i}=\left[W_{I}, W_{P}\right] \cdot\left[\begin{array}{c} x_{i} \\ p_{i} \end{array}\right]=W_{I} \cdot x_{i}+W_{P} \cdot p_{i}=a_{i}+e_{i} W⋅xip=[WI,WP]⋅[xipi]=WI⋅xi+WP⋅pi=ai+ei因此我们可以得到一个结论, e i e_i ei和 a i a_i ai相加就等于原来的输入 x i x_i xi和表示位置的编码 p i p_i pi进行Concatenate后再经过一个变换的结果。在Vision Transformer中通过下面这样一张图来描述训练得到的不同输入的Position Embedding向量的差异,越黄表示该输入该位置的值与该位置作为真值的余弦相似度越大:
论文中还对比了加入Positional Embedding和不加入Positional Embedding的结果上的区别:
这个结果说明,加入那种形式的Positional Embedding并不重要的,关键是要加上。
我们比较熟悉的Batch Normalization是针对CNN设计的,其作用主要是保证输入卷积的Feature Map满足一定的分布规律,因此Batch Normalization的做法是对Feature Map的每一个维度进行标准化处理(即对某一个维度的所有通道及所有Sample的值进行标准化),而在RNN场景,同一Batch中不同Feature的维度可能是不同的,如下图所示,这就会导致**在某些维度进行标准化处理时,通道数过少甚至只有一个通道,这样统计出来的均值和方差都不能反应全局的统计分布,**因此Batch Normalization效果会变得非常差。
针对这个问题,由学者就提出了Layer Normalization,其和Batch Normalization的区别如下图所示:
可以看出来,Layer Normalization是针对每一个Sample进行标准化处理(及某一个Sample的所有通过维度和所有通道的值进行标注化),标准化处理的公式和Batch Normalization是一样的: y = x − E [ x ] Var [ x ] + ϵ ∗ γ + β y=\frac{x-\mathrm{E}[x]}{\sqrt{\operatorname{Var}[x]+\epsilon}} * \gamma+\beta y=Var[x]+ϵx−E[x]∗γ+β其中 E [ x ] \mathrm{E}[x] E[x]为所有值的的期望, Var [ x ] \operatorname{Var}[x] Var[x]为所有值的方差, γ \gamma γ和 β \beta β是可学习参数,用与恢复标准化后的特征分布。
Swin Transformer原论文名为《Swin Transformer: Hearchical Vision Tranformer using Shifted Windows》, 为2021年ICCV的Best Paper,Swin Tranformer和Vision Transformer的网络结构差别如下图所示:
可以看到Swin Transformer具备层次结构的,每一层的特征图由一个或多个Window构成,不同层Window的大小不相同,每个Window经过Self-Attention,Window之间是不进行信息交流的;而Vision Transformer不具备层次结构且每一层都是对整个特征图进行Self-Attention。算法性能对比如下:
值得注意的一点是,Vision Transformer在ImageNet-1K的数据集上如果不经过ImageNe-22K的预训练,其效果其实是不好的,但是Swin Transfomer却能够取得很好的效果。而在FLOPs这个参数上,Swin Transformer也要优于Vision Transformer。
Swin Transformer的网络构架如下图(a)所示:
W-MSA指的的Windows Multi-Head Self-Attention,前文有介绍的Multi-Head Self-Attention是在整个特征图进行计算,而W-MSA是将特征图先均分为若干个Window,在Window上作用Multi-Head Self-Attention,这样做的好处是可以减少计算量,缺点是窗口之间无法进行信息交互,导致感受野变小。这里我们分别来计算下Multi-Head Self-Attention和W-MSA的计算量区别:
首先我们知道Self-Attention公式如下: Attention ( Q , K , V ) = SoftMax ( Q K T d ) V \operatorname{Attention}(Q, K, V)=\operatorname{SoftMax}\left(\frac{Q K^{T}}{\sqrt{d}}\right) V Attention(Q,K,V)=SoftMax(dQKT)V我们假设输入的输入的特征矩阵A的大小为 h w × C hw\times C hw×C,并且我们忽略 SoftMax \operatorname{SoftMax} SoftMax和 d \sqrt{d} d的计算量,那么上述计算公式可以拆分成如下几步: A h w × C ⋅ W q C × C = Q h w × C A^{h w \times C} \cdot W_{q}^{C \times C}=Q^{h w \times C} Ahw×C⋅WqC×C=Qhw×C A h w × C ⋅ W k C × C = K h w × C A^{h w \times C} \cdot W_{k}^{C \times C}=K^{h w \times C} Ahw×C⋅WkC×C=Khw×C A h w × C ⋅ W v C × C = V h w × C A^{h w \times C} \cdot W_{v}^{C \times C}=V^{h w \times C} Ahw×C⋅WvC×C=Vhw×C Q h w × C ⋅ K T ( C × h w ) = X h w × h w Q^{h w \times C} \cdot K^{T(C \times h w)}=X^{h w \times h w} Qhw×C⋅KT(C×hw)=Xhw×hw X h w × h w ⋅ V h w × C = B h w × C X^{h w \times h w} \cdot V^{h w \times C}=B^{h w \times C} Xhw×hw⋅Vhw×C=Bhw×C我们知道对于矩阵乘法 A a × b × B b × c A^{a\times b}\times B^{b\times c} Aa×b×Bb×c的计算量为 a × b × c a\times b\times c a×b×c那么,上述三步的计算量总共是 ( h w × C × C ) × 3 + h w × C × h w + h w × h w × C = 3 h w C 2 + 2 ( h w ) 2 C (hw\times C\times C)\times 3+hw\times C\times hw +hw\times hw\times C=3hwC^2+2(hw)^2C (hw×C×C)×3+hw×C×hw+hw×hw×C=3hwC2+2(hw)2C以上就是Self-Attention的计算量,在此基础上Multi-Head Self-Attention多了最后一步融合矩阵 W o W_o Wo的计算量,也就是 B h w × C ⋅ W O C × C = O h w × C B^{h w \times C} \cdot W_{O}^{C \times C}=O^{h w \times C} Bhw×C⋅WOC×C=Ohw×C因此计算过量为 4 h w C 2 + 2 ( h w ) 2 C 4hwC^2+2(hw)^2C 4hwC2+2(hw)2C,对于W-MSA而言,由于输入被划分成了多个Window,我们假设每个Window的大小为 M × M M\times M M×M,一共有 h M × w M \frac{h}{M}\times\frac{w}{M} Mh×Mw个Window,每个Window都是Mutli-Head Self-Attention的计算量,因此总共的计算量为: ( 4 ( M C ) 2 + 2 ( M ) 4 C ) × h M × w M = 4 h w C 2 + 2 M 2 h w C (4(M C)^{2}+2(M)^{4} C) \times\frac{h}{M}\times\frac{w}{M} = 4 h w C^{2}+2 M^{2} h w C (4(MC)2+2(M)4C)×Mh×Mw=4hwC2+2M2hwC综上所述: Ω ( M S A ) = 4 h w C 2 + 2 ( h w ) 2 C \Omega(\mathrm{MSA})=4 h w C^{2}+2(h w)^{2} C Ω(MSA)=4hwC2+2(hw)2C Ω ( W − M S A ) = 4 h w C 2 + 2 M 2 h w C \Omega(\mathrm{W-MSA})=4 h w C^{2}+2 M^{2} h w C Ω(W−MSA)=4hwC2+2M2hwC相较之下,W-MSA的计算量要小很多
SW-WSA的全称为Shifted Windows Multi-Head Self-Attention,其目的主要是实现不同窗口间的信息交互,其原理如下图所示:
其中window partition和cyclic shift的原理如下图所示:
我们以 3 × 3 3\times3 3×3的Window为例,从(a)到(b)即网格Shift的过程,Shift的大小原论文介绍是窗口大小的一半取整,因此 3 × 3 3\times3 3×3的Window为Shift大小为1,Shift完成后就得到了图(c)所示的9个Window,以最中间的Window为例,它其实是使用到了(a)中四个Window的信息,这也就是Window之间信息交互的模式,但是这样存在一个问题就是9个Window导致计算量增大,为了解决这个问题,作者将图(c)中带颜色的区域进行移动至图(d)所示,最后再重新划分4个Window如图(e)所示,这样计算量和及逆行Shift之前就完全相同。
那么还有一个问题就是图(e)这样的形态虽然对计算量有收益,但是除了左上角的Window之外,其他三个Window实际上都是由两个甚至四个子Window组成,他们不应在同一个Multi-Head Self-Attention中计算,为了解决这个问题,作者使用了masked MSA这样一个模块,实际操作将某一个特征的query和整个Window中的所有特征的key点乘后得到,在不和该特征属于同一个子Window的点乘结果上减100,这样经过Softmax后,不属于同一个子Window的权重就接近于零,后面输出也就不会用到不属于同一个子Window中的value,这样说可能会有些抽象,没理解的同学可以参考Swin-Transformer网络结构详解视频中的讲解。
在完成以上操作后,最后我们将输出的特征都恢复到原来的位置就完成整个SW-WSA的流程。可以看到,SW-WSA在不增加计算量的基础上,实现了窗口间的信息交互,这种操作确实很天才。从下图实验结果我们也可以看出来使用Shifted Windows确实可以带来较大的收益。
Relative Position Bias指的是在Self-Attention的计算过程中,在query和key点乘后加入一个和相对位置相关的bias,其本质是希望在Attention Map能够进一步有所偏重,因此Self-Attention的公式就变成: Attention ( Q , K , V ) = SoftMax ( Q K T / d + B ) V \operatorname{Attention}(Q, K, V)=\operatorname{SoftMax}\left(Q K^{T} / \sqrt{d}+B\right) V Attention(Q,K,V)=SoftMax(QKT/d+B)V下面我们主要来研究下这个 B ∈ R n × n B \in R^{n \times n} B∈Rn×n到底是啥, B B B并不是一个随机初始化的参数,其基本使用过程如下:
我觉得这其中最核心的部分就是就是这个相对位置到Bias Table的映射关系了,如下图所示:
首先我们将各个像素的相对位置进行二维编码 ( x , y ) (x,y) (x,y),其中 x x x表示相对当前像素的行偏移, y y y表示相对像素的列偏移,假设Window的大小为 M × M M\times M M×M,对 ( x , y ) (x, y) (x,y)进行排列组合发现一共由 ( 2 M − 1 ) 2 (2M-1)^2 (2M−1)2种可能,这也就是为什么Bias Table的大小为 ( 2 M − 1 ) 2 (2M-1)^2 (2M−1)2,接下来我们就需要建立一个二维编码到一维编码一一对应映射关系,关系的确定一共分为三步,:
上图中的表格中的数字说明了这一变化过程,这一过程有点二进制的味道,我们可以观察下,4的左边永远是5,4的上面永远是7,这也就完成了Relative Position Bias的映射过程,接下来就去Bias Table取值更新即可,从下面这张对比表中我们可以看到,加上Relative Position Bias收益也是非常明显的: