一:VIT
整体流程:
- 2D卷积进行patch_embed
- 加入一维的类别编码
- 进行位置编码,完成这一套流程变成了[B, N, C]
- 输入进encorder的block模块中
- block中进行了multi-attention,mlp,drop,shortcut等操作,此时输出的还是[B, N, C]
- 最后只提取[:,0]输入进Head层,经过两层fc,最终网络输出为[B, 1, num_classes]
- 后面就是softmax,交叉熵损失,完成任务!
二:Swim-trans
整体流程:
- 2D卷积进行patch_embed,变形为[B Ph*Pw C],然后再进入一个[hidden_dim, hidden_dim]的fc层
- 进行位置编码 nn.Parameter(torch.zeros(1, num_patches, embed_dim))
- 下面进入多个basicLayer层中,每个Layer层主要由多对SwinTransformerBlock层组成
- 对输出的[B L C]变形为[B C L],然后平均池化,变为[B C 1],最后flatten(1),最后输出结果[B, C]
Block中的处理流程:
- 将[B Ph*Pw C]变为[B, H, W, C]
- 偶数Block层进行W-MSA,奇数层SW-MSA,这里主要对奇数层讲解
- 进行torch.roll操作,整合分散窗口
- 进行window_partition,[B, H, W, C]变为[nW*B, window_size, window_size, C]
- 再变形为[nWB, window_sizewindow_size, C]输入进self.attn,对每个窗口进行自注意力运算,注意!!对于SW,需要对attention矩阵加入mask掩码,这样才是对每个分裂的小窗口真正的注意力运算。其中还有一处细节,就是对于每个窗口都加入了位置编码。最后输出[nWB, window_sizewindow_size, C]
- 对输出还原成[nW*B, window_size, window_size, C],然后进行window_reverse,还原成[B H’ W’ C]
- 如果是SW层,需要进行torch.roll,再进行特征图还原
- 最后变形为[B Ph*Pw C],进行MLP、shortcut等操作并输出
Layer中的处理流程:
- 经过多层Block后,将[B Ph*Pw C]输入下采样层
- 将[B Ph*Pw C]变形为[B, H, W, C],然后下采样
- 下采样方式是间隔着取出四个特征层,然后对通道层进行拼接,成为[B, H//2, W//2, 4*C]
- 变形为[B, H//2*W//2, 4×C]输入进fc层,缩减C通道维度为2C
- 最后输出结果[B, H//2*W//2, 2C]
三:DETR
整体流程:
- 对原图[B C H W]进行几层resnet50,取最后一层,并通过1×1卷积层将通道数变为hidden_dim,生成src特征图
- 通过nn.embedding设位置编码pos_embed,提前存[50, hidden_dim]组备用,这种方法和VIT、Swim-Trans的有差别,原因就是这里允许不同大小的输入图像。将src和pos_embed输入进transformer中
- transformer模块中, 将src和pos_embed先变形为[H*W B hidden_dim],然后先输入Encoder层,再出入Decoder层中。注意!!设置一个tgt,和预先设置的query_pos的大小相同( tgt = torch.zeros_like(query_embed)),query_embed = nn.Embedding(num_queries, hidden_dim),一般num_queries=100,代指最多100个预测框
Encoder中的处理流程:
- Encoder中包含多层encoderLayer层
- Layer层主要做自注意力运算。Q、K的生成和以往不同,没有再创建Q、K生成矩阵,而是直接对src加上pos_embed,作为q、k(q = k = self.with_pos_embed(src, pos)),而v = src
- 接下来,直接调用了nn.MultiheadAttention进行self-atention计算,生成了新src2,后面就是常规的mlp、shortcut、dropout等
- 经过多层Layer后,norm()后得到Encoder最终输出memory ,大小为[H*W B hidden_dim]
Decoder中的处理流程
- Decoder中包括多层DncoderLayer
- Layer层主要用来不断更新tgt,从刚开始的[0, 0, …, 0]变为具有一定含义的新特征。做法就是先对tgt自注意力,q = k = self.with_pos_embed(tgt, query_pos),v=tgt,然后nn.MultiheadAttention进行self-atention计算,生成了新的tgt。接着,进行交叉注意力,(tgt + query_embed)作为q,而K和V都来自memory+ pos_embed和memory,最后进行基本的mlp、dropout、norm操作,最后输出tgt,形状为[num_queries B hidden_dim]
- Decoder在经过一系列的layer后,会将每次的layer输出的临时tgt存储,便于后期对每一层都计算loss,最终输出hs为
[layer_num,num_queries ,B,hidden_dim]
经过了Encoder-Decoder后,对输出的hs进行self.class_embed和self.bbox_embed,将通道数变为指定维度,用于后面计算损失。将hs[-1]取出作为最终预测值。最后对preds和tagets进行匈牙利匹配,找出哪儿几个query是负责预测的,然后才能计算损失。