Vision Transformer(ViT)解读
Vision Transformer
Transformer原本是用在NLP上的模型,直到Vision Transformer的出现,transformer开始了在视觉领域的应用。 论文:
Split Image into Patches
Vision Transformer(以下简称ViT)要求将图片划分为大小相同的Patches 在上面的划分中,patches没有重叠。当然patches也可以有重叠。划分的patches越多计算量越大 在划分的过程中,需要指定两个超参数:patch size、stride
# patch embedding的代码 import torch from torch import nn class PatchEmbedding(nn.Module): def __init__(self,patch_size=16,img_size=224,in_channel=3,embedd_dim=768) self.patch_size=(patch_size,patch_size) self.img_size=(img_size.img_size) self.patch_embedd=nn.Conv2d(in_channel,embedd_dim,kernel_size=patch_size,stride=patch_size) def forword(self,x) B,C,H,W=x.shape # b,c,fh,hw x=self.patch_embedd(x) # b,c,gh,gw x=x.flatten(2).transpose(1,2) # b,gh*gw,c return x
Vectorization
接下来的是向量化,即将张量拉伸成向量 如果每一个patches都是d1xd2xd3的张量,那拉伸后的张量为d1d2d3x1
线性变换
设图片被划分成了n个向量,记作x1…xn。 首先用全连接层对向量x作线性变换,z1=Wx1+b。注意:此处的全连接层不使用激活函数,因此这里的全连接层只是个线性函数。W,b参数需要学习得到 这里的全连接层都共用一套参数,即W和b相同
位置编码
还需要对每个patches做位置编码,因为图片被划分为n块,那么位置就是1-n之间的整数 然后将得到的位置编码的向量加到z向量上 为什么要用position encoding? 如下图所示,如果将patch打乱,此时如果不进行位置编码,那么在transformer看来这两张图就是一样的,最后得到的输出也一样,这显然不合理。 我们需要transformer知道这两张图不一样,所以我们要对patch进行编码 编码之后,若我们在进行patch位置的变换,这时候transformer的输出就不一样了。实验证明,若不加位置编码,最后的结果会掉3个百分点。
# positional_embedding class PositionalEmbedding1D(nn.Module): def __init__(self,seq_len,dim): super.__init__() self.pos_embedding=nn.Parameter(torch.zeros(1,seq_len,dim)) def forward(self,x): return x+self.pos_embedding
Transformer Encoder Network
加入位置编码后,z向量便即包含n个小块的内容信息,又包含了位置信息。此外,我们用[CLS]代表分类,对这个符号作embedding,得到z0。把z0-zn输入到多头注意力层,紧接着接上全连接层,以多头注意力层和全连接层连接在一起并多次叠加就是Tranformer的Encoder部分的网络,当然,想要累积多少层都可以。
输出
将c0输入softmax分类器,分类器输出向量p,向量p表示分类的结果,p的大小是类别的数量,如果有1000个类别,那么p就是1000维的向量。 参考论文:
参考视频: