关于后端:基于EasyCV复现ViTDet单层特征超越FPN

1次阅读

共计 6638 个字符,预计需要花费 17 分钟才能阅读完成。

简介:ViTDet 其实是恺明团队 MAE 和 ViT-based Mask R-CNN 两个工作的连续。MAE 提出了 ViT 的无监督训练方法,而 ViT-based Mask R-CNN 给出了用 ViT 作为 backbone 的 Mask R-CNN 的训练技巧,并证实了 MAE 预训练对上游检测工作的重要性。而 ViTDet 进一步改良了一些设计,证实了 ViT 作为 backone 的检测模型能够匹敌基于 FPN 的 backbone(如 SwinT 和 MViT)检测模型。
作者:伝迹、谦言、临在

欢送应用咱们最近开源的 EasyCV,次要聚焦于最新的 Vision Transformer 模型,以及相干的上游 CV 工作

开源地址:https://github.com/alibaba/Ea…

ViTDet 其实是恺明团队 MAE 和 ViT-based Mask R-CNN 两个工作的连续。MAE 提出了 ViT 的无监督训练方法,而 ViT-based Mask R-CNN 给出了用 ViT 作为 backbone 的 Mask R-CNN 的训练技巧,并证实了 MAE 预训练对上游检测工作的重要性。而 ViTDet 进一步改良了一些设计,证实了 ViT 作为 backone 的检测模型能够匹敌基于 FPN 的 backbone(如 SwinT 和 MViT)检测模型。

ViT 作为检测模型的 backbone 须要解决两个问题:

如何晋升计算效率?
如何失去多尺度特色?
ViT-based Mask R-CNN 给出了初步的解决方案,ViTDet 在此基础上,对如何失去多尺度特色做了进一步的改良。

如何晋升计算效率
ViT 采纳的 global self-attention 和图像输出大小(HW) 的平方成正比,对于检测模型,其输出分辨率往往较大,此时用 ViT 作为 backbone 在计算量和内存耗费上都是十分惊人的,比方输出尺寸为 1024×1024,采纳 ViT- B 训练 Mask R-CNN 单 batch 就须要耗费约 20-30GB 显存。为了解决这个问题,ViT-based Mask R-CNN 将 ViT 分成 4 个 stage,每个 stage 的前几个 block 采纳 windowed self-attention,最初一个 block 采纳 global self-attention,比拟 table 3 (2)和 (3) 显著升高显存耗费和训练工夫,而且成果只有轻微降落。

1655194119128_D0845D08-D6E4-4e3e-B827-760A5AF12CAF.png

ViTDet 进一步钻研了如何做 window 的信息聚合,除了采纳 4 个 global self-attention 以外,还能够采纳 4 个 residual block。如下表 (a) 所示,采纳 4 个 conv blocks 成果是最好的,并且 basic block 成果最好 (b)。另外表(c) 和表 (d) 表明每个 stage 的最初一个 block 应用信息聚合,速度和精度的均衡是最好的。

1655194176204_D84D3CB8-3361-48a4-971F-F44E7FAC0D6A.png

Backbone
依据 ViT-based Mask R-CNN 论文 table 4 (94)的后果,用预训练过的 pos embed 加上 BEiT 提出的 relative position bias 成果最好,其中将 pos embed 迁徙到上游工作须要对 pos embed 的进行 resize 操作。

最开始实现了一版共享的 relational position bias,精度上不去,感觉是打开方式不对,起初参照 ViTAE 的不共享 relational paosition bias,能放慢收敛速度,代码如下。

def calc_rel_pos_spatial(

attn,
q,
q_shape,
k_shape,
rel_pos_h,
rel_pos_w,

):

"""Spatial Relative Positional Embeddings."""
sp_idx = 0
q_h, q_w = q_shape
k_h, k_w = k_shape

# Scale up rel pos if shapes for q and k are different.
q_h_ratio = max(k_h / q_h, 1.0)
k_h_ratio = max(q_h / k_h, 1.0)
dist_h = (torch.arange(q_h)[:, None] * q_h_ratio -
    torch.arange(k_h)[None, :] * k_h_ratio)
dist_h += (k_h - 1) * k_h_ratio
q_w_ratio = max(k_w / q_w, 1.0)
k_w_ratio = max(q_w / k_w, 1.0)
dist_w = (torch.arange(q_w)[:, None] * q_w_ratio -
    torch.arange(k_w)[None, :] * k_w_ratio)
dist_w += (k_w - 1) * k_w_ratio

Rh = rel_pos_h[dist_h.long()]
Rw = rel_pos_w[dist_w.long()]

B, n_head, q_N, dim = q.shape

r_q = q[:, :, sp_idx:].reshape(B, n_head, q_h, q_w, dim)
rel_h = torch.einsum('byhwc,hkc->byhwk', r_q, Rh)
rel_w = torch.einsum('byhwc,wkc->byhwk', r_q, Rw)

attn[:, :, sp_idx:, sp_idx:] = (attn[:, :, sp_idx:, sp_idx:].view(B, -1, q_h, q_w, k_h, k_w) +
    rel_h[:, :, :, :, :, None] + rel_w[:, :, :, :, None, :]).view(B, -1, q_h * q_w, k_h * k_w)

return



将 ViT 作为 ViTDet 的预训练须要对 foward 过程进行革新,通过 window_partition 和 window_reverse 两个操作,对输出 feature 重复进行切 window 和还原,这样子能够充分利用 ViT 的预训练模型,同时进步检测的计算效率,论文中形容如上。

ViT-based Mask R-CNN 和 ViTDet 提到的 window size 都是 14×14,然而在输出分辨率为 1024×1024 的状况下,先通过一个 patch_embed,就变成了 64×64 的分辨率,64 是不能整除 14 的,

这里有两种解决形式:

1. 在 patch_embed 之后加一个插值变成 56×56,从 ViT 输入的时候再插值回 64×64。

2. 在 patch_embed 之后 pad 成 70×70,复原成原图的时候裁剪成 64×64。

两种都试了一下,发现第二种不会掉点,而第一种可能会导致 position embedding 的不对齐,代码如下。

x = F.pad(x, (0, 0, pad_l, pad_r, pad_t, pad_b))
, Hp, Wp, = x.shape


if pad_r > 0 or pad_b > 0:

x = x[:, :H, :W, :].contiguous()

x = x.view(B_, H * W, C)
如何失去多尺度特色
1655194231646_DBB0E60B-20A2-4e20-86BD-30025F6B1A05.png

ViT 模型是同质构造,如果采纳的 patch size 为 16×16,那么最终就失去一种 1 /16 的尺度特色。然而罕用的检测模型往往须要多尺度特色,大多数 CNN 和金字塔 ViT 都能够适应这种输入,比方 ResNet 从不同 stage 提取 1 /4,1/8,1/16 和 1 /32 的特色,并送入 FPN 进一步交融失去多尺度特色。ViT-based Mask R-CNN 借鉴了 XCiT 的解决方案,将 ViT 的 transformer blocks 均分成 4 个局部,而后从 d /4,2d/4,3d/ 4 和 d 的输入别离提取 1 /4,1/8,1/16 和 1 /32 的特色(别离采纳 2 个 stride= 2 的反卷积,一个 stride= 2 的反卷积,identity,stride= 2 的 max pooling),而后送入 FPN。

1655194274852_7AC78726-4DC8-4fd4-8BB7-4A9BB2528158.png

而 ViTDet 进一步简化了这种策略,间接用最初的 1 /16 特色通过上采样 (stride= 2 的反卷积) 或者下采样 (stride= 2 的 max pooling) 失去 4 个尺度的特色,而且也不再用 FPN 来进一步交融特色,如上图 c 所示。

比拟 table 1 (a)(b)(c)这种设计不仅简略,而且成果是最好的。

1655194318232_766581BC-F4FA-4d10-B0BC-ACECE4D67454.png

Simple feature pyramid

为了不便起见,简写为 SFP。SFP 先用 ViT 的最初一层构建出多尺度特色,而后别离接 1 个 1x1conv 做通道数 reduce,再接一个 3x3conv,论文中的形容如上。

论文中说在 conv 之后应用 layernorm,那么就须要一直的进行 reshape 操作,实现起来会比较复杂冗余。为了实现更加简洁洁净,复现采纳了 groupnorm 等价 layernorm 的形式(只有把 group 数设置成 1 就能够了)。

依照 ViTDet 论文中的说法,应该是只有 4 层尺度特色,然而规范的 FPN 个别是 5 层,不分明具体实现的时候是用的几层,本实现默认应用 5 层。

Mask RCNN

论文中对于 mask rcnn 的批改如上,总结一下:

rpn head 2conv + LN

roi head 4conv + 1fc,BN 替换成 LN

mask head BN 替换成 LN

数据加强

也就是说训练的时候,采纳 large scale jitter,而后 padding 成 1024;推理的时候放弃长宽比最长边不超过 1024,而后 padding 成 1024。

超参数

预训练默认应用 mae_vit-base-p16-1600e,应用 AdamW 优化器,并且用 step-wise lr,bs64,warmup 250 iter,lr 1e-4,weight decay 0.1,ViT- B 的 drop_path_rate 设置成 0.1。

ViTDet 文章中说是 layer-wise lr decay 能够涨点 0.3 左右,然而我的实现导致最开始收敛很慢,感觉不肯定无效。本实现默认不应用 layer-wise lr decay。

复现 ViTDet 的过程中,让我惊叹的除了单尺度构建多尺度特色精度超过 FPN 之外,还有一点是从 ViT -> SFP -> RPN Head -> RoI Head -> Mask Head 的一整套流程中居然没有应用一个 BN,所有的 norm 都用 LN 替换掉了,这不是齐全跟 NLP 对齐了。

预训练比照试验
另外 ViTDet 还对有监督预训练和无监督预训练 MAE 做了比照试验,能够看到 MAE 能够大幅度晋升 AP,尤其是 ViT-L,甚至超过了 IN-21k 有监督训练成果,如 table 4 所示。

1655194371229_19A12870-323D-4236-A8E3-9126B8DB785B.png

和其余层次化的 backbone 相比,ViTDet 也获得了最好的成果,如 table 5 所示。

1655194413596_0017BC41-58F7-4acd-9663-E30BAD22FB7D.png

效果图
最终复现的基于 ViT-Base 的 ViTDet_MaskRCNN 精度为 50.6,比论文低 0.6,可能还有一点点小细节没有思考到的。

model

base

cur

detials

box_AP

mask_AP

lr

epoch

RunTime(hours)

bs(total=imgs/gpu x gpu_nums x cumulative_iters)

comments

ViTDet

E0

50.6

45.0

step

100

59

8node8bs=64

Tutorial
接下来,咱们将通过一个理论的例子介绍如何基于 EasyCV 进行 ViTDet 算法的训练,也能够在该链接查看具体步骤。

一、装置依赖包
如果是在本地开发环境运行,能够参考该链接装置环境。若应用 PAI-DSW 进行试验则无需装置相干依赖,在 PAI-DSW docker 中已内置相干环境。

二、数据筹备
你能够下载 COCO2017 数据,也能够应用咱们提供了示例 COCO 数据

wget http://pai-vision-data-hz.oss… && tar -zxf small_coco_demo.tar.gz

mkdir -p data/ && mv small_coco_demo data/coco
data/coco 格局如下:

data/coco/
├── annotations
│ ├── instances_train2017.json
│ └── instances_val2017.json
├── train2017
│ ├── 000000005802.jpg
│ ├── 000000060623.jpg
│ ├── 000000086408.jpg
│ ├── 000000118113.jpg
│ ├── 000000184613.jpg
│ ├── 000000193271.jpg
│ ├── 000000222564.jpg
│ …
│ └── 000000574769.jpg
└── val2017

├── 000000006818.jpg
├── 000000017627.jpg
├── 000000037777.jpg
├── 000000087038.jpg
├── 000000174482.jpg
├── 000000181666.jpg
├── 000000184791.jpg
├── 000000252219.jpg
     ...
└── 000000522713.jpg

三、模型训练和评估
以 vitdet-base 为示例。在 EasyCV 中,应用配置文件的模式来实现对模型参数、数据输出及增广形式、训练策略的配置,仅通过批改配置文件中的参数设置,就能够实现试验配置进行训练。能够间接下载示例配置文件。

查看 easycv 装置地位

查看 easycv 装置地位

import easycv
print(easycv.__file__)

export PYTHONPATH=$PYTHONPATH:root/EasyCV
执行训练命令

单机 8 卡:
CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python -m torch.distributed.launch –nproc_per_node=8 –master_port=29500 tools/train.py configs/detection/vitdet/vitdet_100e.py –work_dir easycv/vitdet –launcher pytorch –fp16
8 机 8 卡:
cp EasyCV/tools/launch.py ./ && cp EasyCV/tools/train.py ./ &&python -m launch –nproc_per_node=8 train configs/detection/vitdet_dlc/vitdet_100e.py –work_dir easycv/vitdet_100e –launcher pytorch –fp16
执行评估命令

CUDA_VISIBLE_DEVICES=0,1,2,3,4,5,6,7 python -m torch.distributed.launch –nproc_per_node=8 –master_port=29500 tools/train.py configs/detection/vitdet/vitdet_100e.py –work_dir easycv/vitdet –launcher pytorch –fp16 –eval
Reference
模型细节起源:

ViT-based Mask RCNN https://arxiv.org/abs/2111.11429
ViTDet https://arxiv.org/abs/2203.16527
代码实现:

https://github.com/alibaba/Ea…

https://github.com/tuofeilunh…

EasyCV 往期分享
MAE 自监督算法介绍和基于 EasyCV 的复现
EasyCV 开源|开箱即用的视觉自监督 +Transformer 算法库
原文链接:http://click.aliyun.com/m/100…

本文为阿里云原创内容,未经容许不得转载。

正文完
 0