Transformer 编码器 由交替的 多头自注意力层 (MSA) 和 多层感知机块 (MLP) 构成。在每个块前应用 层归一化 (Layer Norm),在每个块后应用 残差连接 (Residual Connection)。
一个 Transformer Encoder Block 就包含一个 MSA 和一个 FFN,二者都有 跳跃连接 和 层归一化 操作构成 MSA Block 和 MLP Block。
图像本身大小是imgsize*imgsize,现在想要切成patchsize*patchsize。
现在图像的大小是(batchsize channelsize imgsize imgsize),
设为(20, 3, 256, 256),设patch_size = 32。设置中间层大小是dim=1024,所以:
1、Patch Embeddings:切块。
切的块数为w=(image_size / patch_size),h=(image_size / patch_size),横向切成w个,纵向切成h个,总体个数为w*h=num
a. 转换为(batchsize, num,patchsize*patchsize*channelsize)
即将第2维度变换为块的个数,将图像切块后展平
b.得到w*h个数据,每个数据的大小是patchsize*patchsize*channelsize,由于每个数据的大小太大,经过一个线性变换,将每个输入的大小处理为中间层大小dim
切块后,得到patch_embedding数据,(batchsize,num,dim)
2、Patch Embeddings:可学习的分类向量,加入可学习的嵌入向量作为分类向量预测结果。Position Embeddings:位置编码保留块之间的位置信息,直接加入进入x + self.pos_embed(扰动不变性,打乱顺序不会改变结果)
3、transformer:得到的(batchsize,num+1,dim)进行attention操作:
可以参考源代码知道attention的操作过程:
# MHA
class Attention(nn.Module):
def __init__(self, dim, num_heads=8, qkv_bias=False, qk_scale=None, attn_drop=0., proj_drop=0.):
super().__init__()
self.num_heads = num_heads
head_dim = dim // num_heads
self.scale = qk_scale or head_dim ** -0.5
self.qkv = nn.Linear(dim, dim * 3, bias=qkv_bias)
self.attn_drop = nn.Dropout(attn_drop)
self.proj = nn.Linear(dim, dim)
# 附带 dropout
self.proj_drop = nn.Dropout(proj_drop)
def forward(self, x):
B, N, C = x.shape
qkv = self.qkv(x).reshape(B, N, 3, self.num_heads, C // self.num_heads).permute(2, 0, 3, 1, 4)
q, k, v = qkv[0], qkv[1], qkv[2] # make torchscript happy (cannot use tensor as tuple)
attn = (q @ k.transpose(-2, -1)) * self.scale
attn = attn.softmax(dim=-1)
attn = self.attn_drop(attn)
x = (attn @ v).transpose(1, 2).reshape(B, N, C)
x = self.proj(x)
x = self.proj_drop(x)
return x
即可知,attention操作的步骤是先通过线性层使维度数*3,即大小为(batchsize,num+1,dim)变成(batchsize,num+1,dim*3),分别取出每一个dim作为q、k、v。再分割出numhead的数量大小为:(batchsize,numhead,num+1,dim/numhead),k*q后乘以scale,再经过softmax后,乘v,最后得到的结果大小为:(batchsize,numhead,num+1,dim/numhead),reshape后得到(batchsize,num+1,dim)尺寸的结果即为输出。
a.深度depth=transformer块的使用个数,每个里面都包括以下的操作:
先把x进行norm归一化,再做kqv操作,得到的output效果加x=y
y再经过一个norm归一化,得到的结果经过线性变换,得到新的output,再与y相加,output+y=dst
b.把得到的dst作为x重新输入,经过depth次,得到最后的out
每经过一个块,大小都不变,
最终的结果仍然是(batchsize,num+1,dim)
4、第二维的数据mean或直接取类别向量操作,得到(batchsize,dim)
5、经过norm正则化+线性输出,得到(batchsize,classnum)
参考: