屠榜语义分割!VIT-adapter模型复现
Ade20K冠军模型:VIT-adapter。Ade20K数据集上分割miou为58.0。AIstudio已知miou最高的模型
请点击此处查看本环境基本用法.
Please click here for more detailed instructions.
超越Swin v2、PvT v2等模型,ViT-Adaptiver实现ADE20K冠军60.5mIoU
Vision Transformer Adapter for Dense Predictions. Source code
1、摘要
与最近将视觉特定的归纳偏差引入Vision Transformer架构不同,ViT由于缺乏图像的先验信息,在密集预测任务上的性能较差。为了解决这个问题,本文提出了一种Vision Transformer适配器(ViT-Adapter),ViT-Adapter可以通过额外的架构引入归纳偏差来弥补ViT的缺陷并实现与视觉特定模型相当的性能。
具体来说,ViT-Adapter中的Backbone是一个普通的Transformer,可以用多模态数据进行预训练。在对下游任务进行微调时,使用特定于模态的适配器将数据和任务的先验信息引入模型,使其适用于这些任务。
作者验证了ViT-Adapter在多个下游任务上的有效性,包括目标检测、实例分割和语义分割。尤其,使用HTC++时,ViT-Adapter-L得到了60.1 和52.1 ,在COCO test-dev上,超过 Swin-L 1.4 和1.0 。对于语义分割,ViT-Adapter-L在ADE20K val上建立了一个新的mIoU 60.5%,比SwinV2-G高0.6%。
2、本文方法
如图 1 所示,与之前对大规模图像数据集(例如ImageNet)进行预训练和对不同任务进行微调的范式相比,本文的范式更加灵活。在ViT-Adapter框架中,Backbone网络是一个通用模型(例如,ViT),可以使用多模态数据和任务进行预训练。当将其应用于下游任务时,视觉专用适配器将输入数据和任务的先验信息引入到通用Backbone网络之中,使模型适用于下游任务。通过这种方式,使用ViT作为Backbone,ViT-Adapter框架实现了与专为密集预测任务设计的Transformer Backbone(如Swin Transformer)相当甚至更好的性能。
如图3所示,ViT-Adapter模型可以分为2部分。(1)第1部分是Backbone(即 ViT):它由1个Patch Embedding和L个Transformer Encoder层组成(见图3(a))。(2)第2部分是提出的ViT-Adapter:如图3(b)所示,它包含1个Spatial prior module,用于从输入图像中捕获空间特征,1个Spatial Feature injector,用于将空间先验注入到ViT中,以及1个多尺度特征提取器,用于从ViT中提取分层特征。
对于ViT,首先将输入图像输入Patch Embedding,将图像分成16×16个不重叠的Patch。在此之后,这些Patch被Flatten并投影到d维Embedding中。这里的特征分辨率降低到原始图像的1/16。最后,嵌入的Patch被和位置嵌入通过ViT的L编码器层。
对于ViT-Adapter,首先将输入图像输入到Spatial prior module中。将收集3种目标分辨率(即1/8、1/16和1/32)的d维空间特征。然后,这些特征映射被Flatten并连接起来,作为特征交互的输入。
具体来说,给定交互时间N,将ViT的Transforer编码器均匀地分割成N个Blocks,每个Block包含L/N编码器层。对于第i个Block,首先通过Spatial Feature injector将空间先验注Fsp到Block中,然后通过多尺度特征提取器从Block的输出中提取层次特征。经过N个特征交互后,获得了高质量的多尺度特征,然后将特征分割并reshape为3个目标分辨率1/8、1/16和1/32。最后,通过2×2的转置卷积对1/8尺度的特征图进行上采样,得到了1/4尺度的特征图。
通过这种方法,得到了一个与ResNet分辨率相似的特征金字塔,它可以用于各种密集的预测任务。
Spatial Prior Module
最近的工作表明具有重叠滑动窗口的卷积可以帮助Transforer更好地捕捉输入图像的局部连续性。受此启发,作者在ViT中引入了一个基于卷积的Spatial prior module,它通过一个stem和3个卷积将H×W输入图像下采样到不同的尺度。该模块旨在模拟与Patch Embedding平行的图像的局部空间上下文,以免改变ViT的原始架构。
如图3©所示,采用了1个借鉴于ResNet的标准卷积stem,它由3个卷积层和一个最大池化层组成。接下来,使用一个步长为2的3×3卷积堆栈构成了该模块的其余部分,它使通道数量增加了一倍并减小了特征图的大小。
Feature Interaction
由于柱状结构,ViT中的特征图是单尺度和低分辨率的,与金字塔结构的Transformer相比,ViT对于密集预测任务的性能是次优的。为了缓解这个问题,作者提出了2个特征交互模块,在适配器和ViT之间传递特征映射。具体来说,这2个模块分别是基于Cross-Attention的Spatial Feature Injector和Multi-Scale Feature Extractor。如前面所述,将基于ViT的Transformer编码器划分为N个相等的Blocks,并分别在每个Block之前和之后应用所提出的2个算子。
Spatial Feature Injector
Multi-Scale Feature Extractor
模型架构配置
本文为4种不同的ViT变体构建了ViT-Adapter,包括ViT-T、ViT-S、ViT-B和ViT-L。对于这些模型,ViT-Adapter的参数数分别为2.5M、5.8M、14.0M和23.7M。每种配置的细节如表1所示。
3、实验结果(ADE20K)
4、代码展示
代码位置:PaddleSeg/paddleseg/models/backbones/beit.py
配置文件位置: PaddleSeg/configs/upernet/upernetvitadapterbeit512x512.yml
核心代码
BEiTAdapter核心组成两个部分:Beit和adapter,结构如上面图3所示
class BEiTAdapter(BEiT):
def __init__(self, pretrain_size=224, conv_inplane=64, n_points=4, deform_num_heads=6,
init_values=0., cffn_ratio=0.25, deform_ratio=1.0, with_cffn=True,
interaction_indexes=None, add_vit_feature=True, with_cp=False, *args, **kwargs):
super().__init__(init_values=init_values, with_cp=with_cp, *args, **kwargs)
# self.num_classes = 80
# self.cls_token = None
self.num_block = len(self.blocks)
self.pretrain_size = (pretrain_size, pretrain_size)
self.flags = [i for i in range(-1, self.num_block, self.num_block // 4)][1:]
self.interaction_indexes = interaction_indexes
self.add_vit_feature = add_vit_feature
embed_dim = self.embed_dim
self.level_embed = add_parameter(self,paddle.zeros((3, embed_dim)))
self.spm = SpatialPriorModule(inplanes=conv_inplane, embed_dim=embed_dim, with_cp=False)
self.interactions = nn.Sequential(*[
InteractionBlockWithCls(dim=embed_dim, num_heads=deform_num_heads, n_points=n_points,
init_values=init_values, drop_path=self.drop_path_rate,
norm_layer=self.norm_layer, with_cffn=with_cffn,
cffn_ratio=cffn_ratio, deform_ratio=deform_ratio,
extra_extractor=True if i == len(interaction_indexes) - 1 else False,
with_cp=with_cp)
for i in range(len(interaction_indexes))
])
self.up = nn.Conv2DTranspose(embed_dim, embed_dim, 2, 2)
self.norm1 = nn.SyncBatchNorm(embed_dim)
self.norm2 = nn.SyncBatchNorm(embed_dim)
self.norm3 = nn.SyncBatchNorm(embed_dim)
self.norm4 = nn.SyncBatchNorm(embed_dim)
self.feat_channels = [1024, 1024, 1024, 1024]
self.up.apply(self._init_weights)
self.spm.apply(self._init_weights)
self.interactions.apply(self._init_weights)
self.apply(self._init_deform_weights)
normal_(self.level_embed)
def _init_weights(self, m):
if isinstance(m, nn.Linear):
trunc_normal_ = nn.initializer.TruncatedNormal(std=.02)
trunc_normal_(m.weight)
if isinstance(m, nn.Linear) and m.bias is not None:
zeros_(m.bias)
elif isinstance(m, nn.LayerNorm) or isinstance(m, nn.BatchNorm2D):
zeros_(m.bias)
ones_(m.weight)
elif isinstance(m, nn.Conv2D) or isinstance(m, nn.Conv2DTranspose):
fan_out = m._kernel_size[0] * m._kernel_size[1] * m._out_channels
fan_out //= m._groups
norm = nn.initializer.Normal(0,math.sqrt(2.0 / fan_out))
norm(m.weight)
if m.bias is not None:
zeros_(m.bias)
def _get_pos_embed(self, pos_embed, H, W):
pos_embed = pos_embed.reshape((
1, self.pretrain_size[0] // 16, self.pretrain_size[1] // 16, -1)).transpose((0, 3, 1, 2))
pos_embed = F.interpolate(pos_embed, size=(H, W), mode='bicubic', align_corners=False).\
reshape((1, -1, H * W)).transpose((0, 2, 1))
return pos_embed
def _init_deform_weights(self, m):
if isinstance(m, MSDeformAttn):
m._reset_parameters()
def _add_level_embed(self, c2, c3, c4):
c2 = c2 + self.level_embed[0]
c3 = c3 + self.level_embed[1]
c4 = c4 + self.level_embed[2]
return c2, c3, c4
def forward(self, x):
"""
前向传播的过程分解为BeIT和Adapter两个部分
"""
deform_inputs1, deform_inputs2 = deform_inputs(x)
# SPM forward
c1, c2, c3, c4 = self.spm(x)
c2, c3, c4 = self._add_level_embed(c2, c3, c4)
c = paddle.concat([c2, c3, c4], axis=1)
# Patch Embedding forward
x, H, W = self.patch_embed(x)
bs, n, dim = x.shape
cls = self.cls_token.expand((bs, -1, -1)) # stole cls_tokens impl from Phil Wang, thanks
if self.pos_embed is not None:
pos_embed = self._get_pos_embed(self.pos_embed, H, W)
x = x + pos_embed
x = self.pos_drop(x)
# Interaction
outs = list()
for i, layer in enumerate(self.interactions):
indexes = self.interaction_indexes[i]
x, c, cls = layer(x, c, cls, self.blocks[indexes[0]:indexes[-1] + 1],
deform_inputs1, deform_inputs2, H, W)
outs.append(x.transpose([0, 2, 1]).reshape((bs, dim, H, W)))
# Split & Reshape
c2 = c[:, 0:c2.shape[1], :]
c3 = c[:, c2.shape[1]:c2.shape[1] + c3.shape[1], :]
c4 = c[:, c2.shape[1] + c3.shape[1]:, :]
c2 = c2.transpose([0, 2, 1]).reshape([bs, dim, H * 2, W * 2])
c3 = c3.transpose([0, 2, 1]).reshape([bs, dim, H, W])
c4 = c4.transpose([0, 2, 1]).reshape([bs, dim, H // 2, W // 2])
c1 = self.up(c2) + c1
if self.add_vit_feature:
x1, x2, x3, x4 = outs
x1 = F.interpolate(x1, scale_factor=4, mode='bilinear', align_corners=False)
x2 = F.interpolate(x2, scale_factor=2, mode='bilinear', align_corners=False)
x4 = F.interpolate(x4, scale_factor=0.5, mode='bilinear', align_corners=False)
c1, c2, c3, c4 = c1 + x1, c2 + x2, c3 + x3, c4 + x4
# Final Norm
f1 = self.norm1(c1)
f2 = self.norm2(c2)
f3 = self.norm3(c3)
f4 = self.norm4(c4)
return [f1, f2, f3, f4]
5、ADE20K 效果验证
由于Paddleseg里面未提供Mask2Former代码,本项目只复现UperNet的Beit模型
#cd 到data目录
%cd /home/aistudio/data/
/home/aistudio/data
#解压数据集
!unzip -d ./ data26423/ade20k.zip
#cd 到PaddleSeg目录
%cd /home/aistudio/PaddleSeg/
/home/aistudio/PaddleSeg
#安装PaddleSeg
!pip install -r requirements.txt
!python setup.py install
#先来验证一下效果吧
#声明一下哈,一次验证需要1个小时15分钟,看结果的耐心等待
#验证的时候可以将batchsize调成大于等于2的,等于1太慢
!python val.py --config configs/upernet/upernet_vit_adapter_beit_640x640.yml \
--model_path /home/aistudio/data/data164140/vit_adapter_beit_l.pdparams \
--num_workers 4 \
--is_slide \
--crop_size 640 640 \
--stride 426 426 \
由于在单卡V100上验证需要一个多小时,为了节省时间这里向大家公开我在个人服务器四卡T4(16GB memory)上验证结果为: miou: 0.574,accuracy=0.86 。感兴趣的可以跑一下看看
#开启训练
#训练时候需要将batchsize调成1,不然会有bug
!python train.py --config configs/upernet/upernet_vit_adapter_beit_640x640.yml \
--do_eval \
--use_vdl \
--save_interval 1000 \
ave_interval 1000 \
--save_dir output
2022-08-15 23:31:14 [INFO]
------------Environment Information-------------
platform: Linux-4.15.0-140-generic-x86_64-with-debian-stretch-sid
Python: 3.7.4 (default, Aug 13 2019, 20:35:49) [GCC 7.3.0]
Paddle compiled with cuda: True
NVCC: Cuda compilation tools, release 10.1, V10.1.243
cudnn: 7.6
GPUs used: 1
CUDA_VISIBLE_DEVICES: None
GPU: ['GPU 0: Tesla V100-SXM2-32GB']
GCC: gcc (Ubuntu 7.5.0-3ubuntu1~16.04) 7.5.0
PaddleSeg: 2.6.0
PaddlePaddle: 2.3.1
OpenCV: 4.1.1
------------------------------------------------
2022-08-15 23:31:14 [INFO]
---------------Config Information---------------
batch_size: 1
iters: 40000
loss:
coef:
- 1
- 0.4
types:
- ignore_index: 255
type: CrossEntropyLoss
lr_scheduler:
end_lr: 0.0
learning_rate: 2.0e-05
power: 0.9
type: PolynomialDecay
warmup_iters: 1500
warmup_start_lr: 1.0e-06
model:
backbone:
cffn_ratio: 0.25
conv_inplane: 64
deform_num_heads: 16
deform_ratio: 0.5
depth: 24
drop_path_rate: 0.3
embed_dim: 1024
img_size: 640
init_values: 1.0e-06
interaction_indexes:
- - 0
- 5
- - 6
- 11
- - 12
- 17
- - 18
- 23
mlp_ratio: 4
n_points: 4
num_heads: 16
patch_size: 16
pretrained: /home/aistudio/data/data164140/vit_adapter_beit_l.pdparams
qkv_bias: true
type: beit_adapter
use_abs_pos_emb: false
use_rel_pos_bias: true
with_cp: false
backbone_indices:
- 0
- 1
- 2
- 3
channels: 1024
dropout_prob: 0.1
enable_auxiliary_loss: true
num_classes: 150
type: UPerNet
optimizer:
beta1: 0.9
beta2: 0.999
type: AdamW
weight_decay: 0.05
train_dataset:
dataset_root: /home/aistudio/data/ADEChallengeData2016/
mode: train
transforms:
- max_scale_factor: 2.0
min_scale_factor: 0.5
scale_step_size: 0.25
type: ResizeStepScaling
- crop_size:
- 640
- 640
type: RandomPaddingCrop
- type: RandomHorizontalFlip
- brightness_range: 0.4
contrast_range: 0.4
saturation_range: 0.4
type: RandomDistort
- type: Normalize
type: ADE20K
val_dataset:
dataset_root: /home/aistudio/data/ADEChallengeData2016/
mode: val
transforms:
- keep_ratio: true
target_size:
- 2048
- 640
type: Resize
- size_divisor: 32
type: ResizeToMultiple
- type: RandomHorizontalFlip
- type: Normalize
type: ADE20K
------------------------------------------------
W0815 23:31:14.885622 293 gpu_resources.cc:61] Please NOTE: device: 0, GPU Compute Capability: 7.0, Driver API Version: 11.2, Runtime API Version: 10.1
W0815 23:31:14.885679 293 gpu_resources.cc:91] device: 0, cuDNN Version: 7.6.
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/fluid/dygraph/math_op_patch.py:278: UserWarning: The dtype of left and right variables are not the same, left dtype is paddle.float32, but right dtype is paddle.int64, the right dtype will convert to paddle.float32
format(lhs_dtype, rhs_dtype, lhs_dtype))
/opt/conda/envs/python35-paddle120-env/lib/python3.7/site-packages/paddle/nn/layer/norm.py:654: UserWarning: When training, we now always track global mean and variance.
"When training, we now always track global mean and variance.")
2022-08-15 23:31:32 [INFO] [TRAIN] epoch: 1, iter: 10/40000, loss: 7.6269, lr: 0.000001, batch_cost: 1.4596, reader_cost: 0.04923, ips: 0.6851 samples/sec | ETA 16:12:48
2022-08-15 23:31:44 [INFO] [TRAIN] epoch: 1, iter: 20/40000, loss: 8.3714, lr: 0.000001, batch_cost: 1.2583, reader_cost: 0.00017, ips: 0.7947 samples/sec | ETA 13:58:25
2022-08-15 23:31:57 [INFO] [TRAIN] epoch: 1, iter: 30/40000, loss: 7.7384, lr: 0.000001, batch_cost: 1.2583, reader_cost: 0.00015, ips: 0.7947 samples/sec | ETA 13:58:13
2022-08-15 23:32:09 [INFO] [TRAIN] epoch: 1, iter: 40/40000, loss: 7.3995, lr: 0.000001, batch_cost: 1.2545, reader_cost: 0.00016, ips: 0.7971 samples/sec | ETA 13:55:30
^C
6、权重转换
如果你想快速获得VIT-adapter权重,本项目提供pytorch转Paddle代码,在 /home/aistudio/conver_weight.py
具体用法如下:
-
首先 cd PaddleSeg
-
接着 git clone https://github.com/czczup/ViT-Adapter
-
将VIT-adapter改名为Adapter(因为原文件中有“-”,python文件无法识别)
-
运行pip install -r requirements.txt和python setup.py install 安装PaddleSeg
-
cd Adapter/segmentation/
-
按照VIT-adapter中准备环境的代码准备环境
-
cp /home/aistudio/conver_weight.py ./
-
下载pytorch权重并运行python conver_weight.py
7、模型效果
可以看到single scale的验证,VIT-adapter可以达到58.0的miou,目前AIstudio上在ADE20K上最高miou
8、总结
1、本文从图像先验信息的角度,设计一个新的Adapter模块,将图像的先验知识引入VIT,实现在ADE20K最先进的新能。
2、缺点:代码验证时候太耗时,也就是推理速度慢,这是VIT通病,希望未来可以改进。
参考文献
分割冠军 | 超越Swin v2、PvT v2等模型,ViT-Adaptiver实现ADE20K冠军60.5mIoU
此文章为搬运
原项目链接
更多推荐
所有评论(0)