神经网络学习笔记3——Transformer、VIT与BoTNet网络

系列文章目录

神经网络学习笔记1——ResNet残差网络、Batch Normalization理解与代码
神经网络学习笔记2——VGGNet神经网络结构与感受野理解与代码



A、Transformer模型

最近Transformer在CV领域很火,Transformer是2017年Google在Computation and Language上发表的,当时主要是针对NLP自然语言处理领域提出的,主要针对的是NLP领域里的机器翻译任务。在此之前大家处理这类的任务使用的模型都是RNN、LSTM之类的时序网络,但是这类模型不可避免的存在着记忆长度有限或者说所能利用到的语句信息是有限的这种问题,以及随着序列长度增加带来的梯度爆炸梯度消失等问题,虽然LSTM在RNN的基础上一定程度地缓解了这类问题,但这类基于RNN的网络模型另外一个比较严重的问题是不能并行化。想要计算tn时刻的数据,必须要先计算tn-1时刻的数据,无法并行化带来的问题就是计算效率特别低。针对这些问题,谷歌团队提出了Transformer(中文名变形金刚),现在的Transformer被认为成为类似NLP、CNN、RNN之后的第四大类基础模型,或许这就是Attention Is All You Need的含金量吧。transformer的一大核心就是提出一个依赖于注意力机制Attention的模型。


一、细节补充

1.并行计算

数据并行的模型训练中,训练任务被切分到多个进程(设备)上,每个进程维护相同的模型参数和相同的计算任务,但是处理不同的数据(batch data)。数据并行可通过增加并行训练设备来提高训练吞吐量。

输入数据切分整个训练数据集:

  1. 根据并行进程数划分,每个进程只读取自身切分的数据
  2. 读取仅由具体某个进程负责, 根据并行进程数划分,再将不同数据块发送到对应进程上

RNN系列的模型就必须按照顺序从 X1 计算到 Xn ,这个问题导致面对即使是在GPU上RNN的计算性能依然比较差,且过长的序列会导致早期的隐藏历史信息ht会被丢掉迭代掉。
而RNN之所以不能并行化,是因为虽然X0,X1,X2你都知道了,但是由于你计算的时候不止要输入Xi还要输入上一时刻Xi-1计算的依赖ht-1,那么你就不得不一个个的按顺序去计算X0得出的h0,又用h0和X1得出的h1。而你无法和transformer一样直接把这批数据([X0,X1,X2,…,Xn])当作一个完整矩阵同时处理,而需要一条一条的处理。

Transformer的并行化是指在训练阶段的数据并行化,测试阶段只有encoder可以并行化,decoder不能并行化,在decoder阶段可能Transformer在代码层面上可能会有点小不同。
Transformer的并行化被认为主要体现在self-attention模块,在Encoder端Transformer可以并行处理整个序列,并得到整个输入序列经过Encoder端的输出,在self-attention模块,对于某个序列从 X1,X2,…,Xn ,self-attention模块可以直接计算 ​Xi,Xj 的点乘结果。在不考虑batch的问题时,假设输入一个时间序列Xi,表示i时刻X的值(或者可以理解为输入一段视频,Xi表示第i帧图片)。训练的时候进入模型的是所有的训练集Xi同时进入,而不是X0,X1,X2一个个依次序进入。所以transformer可以同时对这批数据进行处理(各种矩阵运算),也就可以并行化。

2、BatchNorm和LayerNorm

BatchNorm一般用于CV领域,而LayerNorm一般用于NLP领域,这是由两个任务的本质差异决定的,视觉的特征是客观存在的特征,而语义特征更多是由上下文语义决定的一种统计特征,因此他们的标准化方法也会有所不同。

BatchNorm批量归一化:批量归一化是对一个中间层的单个神经元进行归一化操作,batch方向做归一化。计算第l层网络中每个神经元在Batch大小为N的样本上输出的N个结果,计算每个神经元输出的N个结果的均值和方差,然后使用均值和方差来对这N个输出结果做归一化,所以归一化的维度是在Batch上进行的

LayerNorm层归一化:层归一化是对一个中间层的所有神经元进行归一化,channel方向做归一化。计算第l层网络中的每个神经元在Batch中每个输入样本的输出,对于每个输入样本,计算所有神经元输出结果的均值和方差,使用均值和方差来归一化对于这个输入样本的输出结果,所以归一化的维度以在整个层上进行的

都是为了更好的获取均值和方差
在这里插入图片描述


二、编码器-解码器(encode-decode)

编码器负责把自然语言序列映射为隐藏层(含有自然语言序列的数学表达),然后解码器把隐藏层在映射为自然语言序列。

自回归步骤:
1.输入自然语言序列到编码器
2.编码器输出的隐藏层,在输入到解码器
3.启动解码器
4.得到第一个字
5.将第一个字落下来再输入到解码器,得到第二个字
6.重复此过程,直到解码器输出终止符,序列生成完成。

原论文的模型图:
在这里插入图片描述
这其实就是一个编码器-解码器架构,可简单划分为


左边的区域为编码器:
Inputs:编码器输入
Positional Enocding:位置编码
Nx:n个这样的层堆叠
Multi-Head Attention:多头注意力机制层
Add & Norm:类似残差设置,归一化
Feed Forward:前馈神经网络

第一个子层连接结构包括一个多头自注意力子层(qkv来自编码器输入,q=k=v)和归一化层以及一个残差连接。
第二个子层连接结构包括一个前馈全连接子层和归一化层以及一个残差连接。

编码器Encoder: 由N=6个相同的layers组成, 每一层包含两个sub-layers. 第一个sub-layer 就是多头注意力层(multi-head attention layer)然后是一个简单的全连接层。 其中每个sub-layer都加了residual connection(残差连接)和normalisation(归一化)。


右边的区域为解码器:
Outputs:解码器输入
Positional Enocding:位置编码
Nx:n个这样的层堆叠
Masked Multi-Head Attention:带掩码的多头注意力机制层,掩盖后面的值,使其权重为0
Multi-Head Attention:多头注意力机制层
Add & Norm:类似残差设置,归一化
Feed Forward:前馈神经网络

第一个子层连接结构包括一个多头掩码自注意力子层(qkv来自解码器输入,q=k=v,做Masked掩码)和归一化层以及一个残差连接。
第二个子层连接结构包括一个多头注意力子层(kv来自编码器输出,q来自解码器第一子层的输出)和归一化层以及一个残差连接。
第三个子层连接结构包括一个前馈全连接子层和归一化层以及一个残差连接。

解码器Decoder: 由N=6个相同的Layer组成,但这里的layer和encoder不一样, 这里的layer包含了三个sub-layers, 其中有一个self-attention layer, encoder-decoder attention layer 最后是一个全连接层。前两个sub-layer 都是基于multi-head attention layer。这里有个特别点就是masking, masking 的作用就是防止在训练的时候 使用未来的输出的单词。比如训练时,第一个单词是不能参考第二个单词的生成结果的。Masking就会把这个信息变成0,用来保证预测位置 i 的信息只能基于比 i 小的输出。


三、注意力机制Attention

所谓Attention机制,便是聚焦于局部信息的机制,比如,图像中的某一个图像区域。随着任务的变化,注意力区域往往会发生变化。其本质是一种通过网络自主学习出的一组权重系数,并以“动态加权”的方式来强调我们所感兴趣的区域同时抑制不相关背景区域的机制。

在计算机视觉领域中,注意力机制可以大致分为两大类:强注意力和软注意力。由于强注意力是一种随机的预测,其强调的是动态变化,虽然效果不错,但由于不可微的性质导致其应用很受限制。与之相反的是,软注意力是处处可微的,即能够通过基于梯度下降法的神经网络训练所获得,因此其应用相对来说也比较广泛。软注意力按照不同维度(如通道、空间、时间、类别等)出发,

目前主流的注意力机制可以分为以下三种:通道注意力、空间注意力以及自注意力(Self-attention)。

针对于注意力机制的引起方式,可以分为两类,一种是非自主提示,另一种是自主提示。其中非自主提示指的是由于物体本身的特征十分突出引起的注意力倾向,自主提示指的是经过先验知识的介入下,对具有先验权重的物体引起的注意力倾向。换句话说,可以理解为非自主提示源自于物体本身,而自主提示源自于一种主观倾向。

关于注意力与自注意力机制区别,具体理解可以看看这篇博客


四、自注意力机制(Self-Attention)

  1. q代表query,后续会去和每一个k进行匹配
  2. k代表key,后续会被每个q匹配
  3. v代表Value,从a中提取得到的信息
  4. 后续q和k匹配的过程可以理解成计算两者的相关性,相关性越大对应v的权重也就越大
  5. q=k=v时,称为自注意机制

在这里插入图片描述

将输入来源中的构成元素想象成是由一系列的<Key,Value>数据对构成,此时给定目标中的某个元素Query,通过计算Query和各个Key的相似性或者相关性,得到每个Key对应Value的权重系数,然后对Value进行加权求和,即得到了最终的Attention数值。所以本质上Attention机制是对输入中元素的Value值进行加权求和,而Query和Key用来计算对应Value的权重系数。

另外,还有一种理解方式,我们可以将查询,键和值理解为一种软寻址(Soft Addressing)。Value可以看作存储器存储的内容,Key看作是存储器的地址。当Key==Query时,则取出Key地址对应存储器中的Value值,这被称为硬寻址。而软寻址则是通过计算Key和Query的相似度来进行寻址,这种方法不只是获取一个Key地址中存储器的Value值,而是获取所有的存储器中的Value值的加权和 。至于每个Value的权重(重要程度),是通过Key和Query相似度计算得到的,最终的输出是所有Value值和其权重的加权和。

Attention机制的具体计算过程,如果对目前大多数方法进行抽象的话,可以将其归纳为两个过程:第一个过程是根据Query和Key计算权重系数,第二个过程根据权重系数对Value进行加权求和。而第一个过程又可以细分为两个阶段:第一个阶段根据Query和Key计算两者的相似性或者相关性;第二个阶段对第一阶段的原始分值进行归一化处理;

在这里插入图片描述

在这里插入图片描述

五、多头注意力机制(Multi-Head Attention)

在这里插入图片描述
根据模型图可以理解为将原始的V、K、Q单独输入线性层处理投影到比较低的维度,然后做h次Scaled Dot-Product Attention并得到h个输出,合并输出最后做一次线性投影。

通过一个注意力机制的多次并行运行,将独立的注意力输出串联起来,线性地转化为预期维度。直观看来,多个注意头允许对序列的不同部分进行注意力运算,允许模型同时关注来自不同位置的不同表示子空间的信息。

多头注意力通过利用同一查询的多个不同版本并行实现多个注意力模块来工作。其思想是使用不同的权重矩阵对查询进行线性变换得到多个查询。每个新形成的查询本质上都需要不同类型的相关信息,从而允许注意模型在上下文向量计算中引入更多信息。

每个头都创建了自己对查询和输入矩阵的表示,从而允许模型学习更多的信息。例如,在训练语言模型时,一个注意力头可以学习关注某些动词(例如行走、驾驶、购买)与名词(例如,学生、汽车、苹果)的关系,而另一个注意力头部则学习关注代词(例如,他、她、it)与名词的关系,可以像卷积一样学到更多东西。
每个头还将创建自己的注意力得分向量,以及相应的注意力权重向量
在这里插入图片描述


B、VIT(Vision Transformer)模型

从深度学习暴发以来,CNN一直是CV领域的主流模型,而且取得了很好的效果,相比之下,基于self-attention结构的Transformer在NLP领域大放异彩。虽然Transformer结构已经成为NLP领域的标准,但在计算机视觉领域的应用还非常有限。

ViT(vision transformer)是Google在2020年提出的直接将Transformer应用在图像分类的模型,通过这篇文章的实验,给出的最佳模型在ImageNet1K上能够达到88.55%的准确率(先在Google自家的JFT数据集上进行了预训练),说明Transformer在CV领域确实是有效的,而且效果还挺惊人。VIT推动了NLP与CV的统一,促进了多模态领域的发展。

一、transformer与图像

硬件支持的序列长度一般为几百到上千,而transformer需要把2维图片转为1维序列,比如说一张图片输入大小为224x224,以像素点为基础进行拉长为序列,那么序列长度为224x224=50176,平方复杂度太大。
如何降低序列长度:
1、提纯出特征图作为输入,比如resnet后期的特征图就会比较小,可以作为transformer输入。
2、Stand-Alone Attention孤立自注意力,切分为局部小窗口,控制输入。
3、Axial Attention轴注意力,把高宽hw拆分成两个1维矩阵,分别做自注意力。
4、vit将图像切分为n个patch,每个patch作为一个元素进行输入,一个图片等价于一句话,一个patch等价于一个单词。

二、模型分析

在这里插入图片描述

  1. 给定一张图像(左下角),并划分成n个patch
  2. 把patch作为元素,并排成一个序列
  3. 每个patch都会通过Linear Projection of Flattened Patches线性投射层也就是一个全连接层进行处理
  4. 给patch加上位置编码,得到Patch + Position 的Embedding层token
  5. 通过Extra learnable embedding和位置编码额外加入class token(0*),通过token之间做交换信息时学习所需信息
  6. 使用DropOut/DropPath正则化处理
  7. 传入Transformer Encoder模块处理
  8. 根据embedding(0*)和MLP Head通用分类头分类
  9. 用MLP交叉熵函数进行模型训练

在这里插入图片描述

1、Embedding层

从图中看,Transformer Encoder读入的是一小块一小块这样的图片。这样做的原因是:将一个个小块图像视为token(token可以理解为NLP中的一个字或词),在Transformer中计算每个token之间的相关性。

这一点就和卷积神经网络有很大区别了。以往的CNN,以卷积 + 池化的方式不断下采样,这样理论上模型可以通过加深模型深度,达到增大感受野的目的。不过这样会有两个缺点:
实际结果中显示,CNN对边缘的响应很弱。这也非常好理解,越靠边缘的像素,因为被卷积次数少,自然在梯度更新时,贡献更少。
CNN只能和临近像素计算相关性。由于其滑窗卷积的特性,无法对非领域的像素共同计算,例如左上角的像素无法和右下角的像素联合卷积。这就导致了某些空间信息是无法利用的。同时根据MAE论文中所说的,自然图像具有冗余性,即相邻像素点代表的信息是差不多的,所以只计算领域像素无法最大化利用图像特征。

回到ViT中,仅仅把图像拆分成小块(patch)是不够的,Transformer Encoder需要的是一个向量,shape为[num_token, token_dim]。对于图片数据来说,shape为[H,W,C]是不符合要求的,所以就需要转换,要将图片数据通过这个Embedding层转换成token。

以ViT-B/16为例:假设输入图像为224x224x3,一个token原始图像shape为16x16x3,那这样就可以将图像拆分成(224/16)^2 = 196个patch,也就是196个图像块,然后将每个图像块线性映射至一维向量中,那么这个一维向量的长度即为16163=768维。将196个token叠加在一起最后维度就是[196, 768]。

同时需要注意的是,token可以添加位置编码。由于self-attention的机制,在没有字符位置的情况下,图片切割出来的patch会被打乱,所以当添加了位置编码,分类准确率将会更高。其中位置编码也分1-D、2-D、Relative,但是差别不会很大。

另外,输入tensor还需要有一个额外的class token(0*),class token(0*)不管是NLP还是图像都在使用,主要是作为图像的整体特征,它的数据格式是[1,768],方便与后面其他token的信息直接拼接,这样做是因为分类信息是在后面需要取出来单独做预测的,shape也就从[196, 768]变为[197, 768]。

2、Transformer Encoder模块

Transformer Encoder也就是堆叠encoder block几次,和常规的CNN类似,主要由几个部分组成:

  1. Layer Normalization:
    相比于Batch Normalization来说,BN是针对所有的样本,对某一个特征图计算均值和方差,然后然后对这个特征图神经元做归一化。LN是对某一个样本,计算该样本所有特征图的均值和方差,然后对这个样本做归一化。BN适用于不同mini batch数据分布差异不大的情况,而且BN需要开辟变量存每个节点的均值和方差,空间消耗略大;而且 BN适用于有mini_batch的场景。LN只需要一个样本就可以做归一化,可以避免 BN 中受 mini-batch 数据分布影响的问题,也不需要开辟空间存每个节点的均值和方差。

  2. K、Q、V:
    K=Q=V,每个都是[197,768],也就是KQV维度是197x(768/Lx),后面的输出拼接后又会还原为768的。

  3. Multi-Head Attention:
    这个结构是self-attention中的一种,上面有做详细介绍。

  4. DropOut/DropPath:
    ViT-B/16模型是使用了DropOut,但实际别人复现的代码中使用的是DropPath。两者对最后的结果影响不大,这里也不展开详细说了。

  5. MLP Block:
    由一个全连接层 + GELU激活函数 + DropOut组成,采用的是倒瓶颈结构,输入特征层经过一次全连接之后放大,通道膨胀为原来的4倍,后一个全连接层再恢复成原来的数目。所以经过MLP Block之后tensor的shape是不变的。

  6. Lx:
    进行L个堆叠

3、MLP Head模块

经过Transformer Encoder后输出tensor的shape和输入tensor的shape是一样的,以ViT-B/16为例,输入是[197, 768],输出还是[197, 768]。下游任务如果是分类模型,需要提取出对应的class token(0*)获取分类结果。Vision Transformer中说MLP是由一个全连层 + Tanh激活 + 全连接层组成。但实际使用起来一层全连接层直接做分类即可,后面如果需要得到每个类别的概率的话,需要接上一个softmax激活函数。

C、Bottleneck Transformer(BoTNet)网络混合模型

一种简单却功能强大的backbone,该架构将自注意力纳入了多种计算机视觉任务,是 CNN + Attention的结合,包括图像分类,目标检测和实例分割。该方法在实例分割和目标检测方面显著改善了基线,同时还减少了参数,从而使延迟最小化。

将卷积和自注意力进行结合,其中一大原因就是因为纯 ViT 类型的结构对于输入尺寸特别敏感,不能变动,是 224 × 224 224 就是 224 × 224 224 。然而我们的目标检测,实例分割等任务的输入可能是 1024 × 1024 1024 的大图。如果硬Train一发纯 Transformer,计算量怕机器吃不消。

BoTNet 则是将 Attention 模块融入到 CNN 原有的 backbone 中,通过且仅在ResNet中,用Multi-Head Self-Attention (MHSA)来替换3 × 3 convolution,并且不进行其他任何更改。resnet模型可以看我之前的博客

一、Multi-Head Self-Attention模块

在这里插入图片描述

这个MHSA Block是核心创新点,其中高度和宽度的相对位置编码分别为 Rh 和 Rw。,其中 q、 k、 v 分别代表查询、键和权值。十 和 X 分别代表逐元素求和和矩阵乘法,而 1x1 代表逐点卷积。蓝色的部分分别代表位置编码position encodings 和 价值映射value projection。

具体步骤:

  1. 传入输入X,X的格式应该是H × W × d ,分别表示输入特征矩阵的高宽以及单个 token 的维度
  2. 把X分别作为WQ、WK、WV
  3. 初始化两个可学习的参数向量 Rh和Rw分别表示高度和宽度不同位置的位置编码,然后将它们通过广播机制加起来,那就是二维 ( i , j ) 位置的编码为 Rhi + Rwj 的两个 d维向量相加,这与VIT的一维位置编码不同。输出r,代表位置编码。
  4. 注意现在有四个参数,分别为q、w、v、r,他们的矩阵格式都是H × W × d。将qr进行矩阵乘法得到内容位置content-position输出qrT, 将qk进行矩阵乘法得到内容-内容content-content输出qkT。
  5. 将qrT与qkT进行矩阵加法,并对得到的矩阵进行softmax归一化指数处理,处理输出的值的矩阵格式为HW×HW。
  6. 最后将输出值与权值V进行矩阵乘法,得到输出Z。

其与之前的Transformer中的MHSA有所不同:

  1. 由于处理对象不是一维的,而是类似CNN模型,所以有非常多特性与此相关。
  2. 归一化这里并没有使用Layer Norm而是采用的Batch Norm,与CNN一致。
  3. 非线性激活,BoTNet使用了三个非线性激活
  4. 左侧content-position模块引入了二维的位置编码,这是与Transformer中最大区别。

在这里插入图片描述

BotNet即将ResNet中的第4个block中的bottleneck替换为MHSA(Multi-Head Self-Attention)模块,形成新的模块,取名叫做Bottleneck Transformer (BoT) 。仅仅对ResNet-50 C5结构的更换,最终测试却在Mask R-CNN的实例分割在coco数据集上取得了44.4% Mask AP ,49.7% Box AP。在分类任务中,在 ImageNet上取得了84.7%的top-1准确性。并且比 EfficientNet快2.33倍。

既然MHSA这么强大为什么不把C2到C5的所有3X3卷积层都更换为MHSA呢?论文中提及,如果全部更换为MHSA,其计算量将会是几何甚至指数级提升,但带来的效益却远远不成正比。所以最终只修改了C5的结构,C5的Bottleneck也不一定3个全用MHSA。
在这里插入图片描述

二、Bottleneck Transformer

在 Multi-Head Self-Attention 结构前后加上 1 × 1 卷积就得到了 Bottleneck Transformer。Bottleneck Transformer 和 ViT 中的 Transformer block 其实是有亲属关系的,他们不是差异很大的结构。作者在论文中首先提到说,具有 MHSA 的 ResNet botteneck 块可以被视作具有 bottleneck 结构,其他方面具有微小差异(例如残差结构,正则化层等)的 Transformer 块。
在这里插入图片描述
最右边的是单个C5层,把上一层的输出进行收缩Contraction维度从2048缩小512(÷4)作为输入,经过MHSA模块得到H×W×512的输出,再经过扩大Expansion从512放大2048(×4)作为输出。

D、总结

Transformer、VIT与BoTNet的原理及模型结构基本的学习就到这了,对于实际使用的话可能暂时不做,因为还没有合适的机会与一定的硬件局限。原因是虽然在当时实验结果达到了SOTA,但是相比于CNN,它需要更多的数据集。在小数据集上训练出来的精度是不如CNN的,但在大数据集上ViT精度更高,需要更多的数据和更好的训练平台是我所欠缺的。存在这种差异的一个直观的解释是:ViT因为self-attention独特的机制,更多的利用token与token跨像素之间的信息,而CNN只是对领域的像素进行计算,所以相同参数的情况下,ViT获得的信息更多,在某种程度上可以看成是模型深度更深。所以小数据集上ViT是欠拟合的。所以实际开发中的做法是:基于上千万级别的大数据集上训练,得到一个预训练权重,然后再在小数据集上做迁移,虽然论文谈及vit相对不贵,贵是指训练消耗之类的意思,但这都是相对于大数据集而言的,在中小数据集层面,CNN还是相当好用的。

猜你喜欢

转载自blog.csdn.net/qq_45848817/article/details/127111460
今日推荐