简介: 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/EasyCV

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需要解决两个问题:

  1. 如何提升计算效率?
  2. 如何得到多尺度特征?

ViT-based Mask R-CNN给出了初步的解决方案,ViTDet在此基础上,对如何得到多尺度特征做了进一步的改进。

如何提升计算效率

ViT采用的global self-attention和图像输入大小(HW)的平方成正比,对于检测模型,其输入分辨率往往较大,此时用ViT作为backbone在计算量和内存消耗上都是非常惊人的,比如输入尺寸为1024x1024,采用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)显著降低显存消耗和训练时间,而且效果只有轻微下降。

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

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都是14x14,但是在输入分辨率为1024x1024的情况下,先经过一个patch_embed,就变成了64x64的分辨率,64是不能整除14的,

这里有两种处理方式:

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

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

两种都试了一下,发现第二种不会掉点,而第一种可能会导致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)

如何得到多尺度特征

ViT模型是同质结构,如果采用的patch size为16x16,那么最终就得到一种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。

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

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

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所示。

和其他层次化的backbone相比,ViTDet也取得了最好的效果,如table 5所示。

效果图

最终复现的基于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-cn-zhangjiakou.aliyuncs.com/data/small_coco_demo/small_coco_demo.tar.gz && 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

模型细节来源:

  1. ViT-based Mask RCNN https://arxiv.org/abs/2111.11429
  2. ViTDet https://arxiv.org/abs/2203.16527

代码实现:

https://github.com/alibaba/EasyCV/blob/master/easycv/models/backbones/vitdet.py

https://github.com/tuofeilunhifi/EasyCV/blob/master/easycv/models/detection/vitdet/sfp.py

EasyCV往期分享

原文链接:http://click.aliyun.com/m/1000346408/

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

基于EasyCV复现ViTDet:单层特征超越FPN的更多相关文章

  1. 第十六节、基于ORB的特征检测和特征匹配

    之前我们已经介绍了SIFT算法,以及SURF算法,但是由于计算速度较慢的原因.人们提出了使用ORB来替代SIFT和SURF.与前两者相比,ORB有更快的速度.ORB在2011年才首次发布.在前面小节中 ...

  2. Distinctive Image Features from Scale-Invariant Keypoints(SIFT) 基于尺度不变关键点的特征描述子——2004年

    Abstract摘要本文提出了一种从图像中提取特征不变性的方法,该方法可用于在对象或场景的不同视图之间进行可靠的匹配(适用场景和任务).这些特征对图像的尺度和旋转不变性,并且在很大范围的仿射失真.3d ...

  3. 万张PubFig人脸数据实现基于python+OpenCV的人脸特征定位程序(1)

    在最近刷今日头条以及其他媒体软件时,经常会发现一些AI换脸的视频,于是我想,可不可以自己实现一个可以进行人脸识别的软件程序.我的具体流程是先配合python网络爬虫先进行万张PubFig人脸公共图片的 ...

  4. js面向(基于)对象编程-三大特征

    ①抽象 js提供以下几种控制方法和属性的访问权限: (1)公开级别:对外公开 (2)私有级别:类本身可以访问,不对外公开 案例如下所示: function Person(name,age,sal){ ...

  5. 目标检测中特征融合技术(YOLO v4)(上)

    目标检测中特征融合技术(YOLO v4)(上) 论文链接:https://arxiv.org/abs/1612.03144 Feature Pyramid Networks for Object De ...

  6. Kaggle "Microsoft Malware Classification Challenge"——就是沙箱恶意文件识别,有 Opcode n-gram特征 ASM文件图像纹理特征 还有基于图聚类方法

    使用图聚类方法:Malware Classification using Graph Clustering 见 https://github.com/rahulp0491/Malware-Classi ...

  7. 常见特征金字塔网络FPN及变体

    好久没有写文章了(对不起我在划水),最近在看北京的租房(真真贵呀). 预告一下,最近无事,根据个人多年的证券操作策略和自己的浅显的AI时间序列的算法知识,还有自己Javascript的现学现卖,在微信 ...

  8. 论文阅读笔记三十三:Feature Pyramid Networks for Object Detection(FPN CVPR 2017)

    论文源址:https://arxiv.org/abs/1612.03144 代码:https://github.com/jwyang/fpn.pytorch 摘要 特征金字塔是用于不同尺寸目标检测中的 ...

  9. BRIEF特征简介

    引言 该文是由EPFL的Calonder在ECCV2010上提出了一种可以快速计算且表达方式为二进制编码的描述子.主要思路就是在特征点附近随机选取若干点对,将这些点对的灰度值的大小,组合成一个二进制串 ...

  10. 『计算机视觉』Mask-RCNN_推断网络其四:FPN和ROIAlign的耦合

    一.模块概述 上节的最后,我们进行了如下操作获取了有限的proposal, # [IMAGES_PER_GPU, num_rois, (y1, x1, y2, x2)] # IMAGES_PER_GP ...

随机推荐

  1. pfx文件导出pem和私钥,更换网站域名证书

    openssl 路径: C:\Program Files\OpenSSL-Win64\bin -- 导出pem证书openssl pkcs12 -in C:\BackUp\Lightning\cert ...

  2. Java/Kotlin 实现控制台输出日志保存到文件

    原文:Java/Kotlin 实现控制台输出日志保存到文件 | Stars-One的杂货小窝 之前开发的几款软件,用户用着的过程中,偶尔会存在报错问题,想保留一份日志出来,之后可由用户发过来,进行问题 ...

  3. day11-面向对象02

    面向对象02 7.继承 继承的本质是对某一批类的抽象,从而实现对现实世界更好地建模 extends的意思是"扩展".子类是父类的扩展. Java类中只有单继承,没有多继承!(一个儿 ...

  4. AOSP源码编译—交换空间扩容

    编译AOSP源码的时候会出现提示如下: 意思是需要16G左右的内存(实际上编译会超过16G),而我们之前安装Ubuntu的时候只分配了8G,编 译一定会失败!此时需要添加虚拟内存(swap交换空间) ...

  5. 3DCAT为华东师大设计学院打造元宇宙数字虚拟学院

    6月11日,华东师范大学设计学院在chi K11美术馆举办了一场别开生面的 2023 年本科毕业设计暨项目实践教学现场演示展.其中,元宇宙数字虚拟学院(一期)的现场发布会引起了现场震撼,吸引了众多观众 ...

  6. python基础七(函数名称空间及作用域、函数对象、函数嵌套、闭包函数、装饰器)

    一 名称空间(namespaces):存放名字的地方,是对栈区的划分. 有了名称空间之后,就可以在栈区中存放相同的名字,详细的名称空间.分三种1.1 内建名称空间存放的名字:存放的python解释器内 ...

  7. 记录--P0事故预警

    这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 背景 某一天,前端小余同学和后端别问我小哥在做登录业务接口对接,出于业务的特殊性和安全性的考虑,她和后端小哥约定"user&qu ...

  8. 使用graphviz图形化展示路径(决策树用到此库)

    问题:当出现错误 graphviz.backend.execute.ExecutableNotFound: failed to execute WindowsPath('dot'), make sur ...

  9. 再见了 Pages

    再见 Pages 之前一直用 GitHub Pages + Hexo 写博客,但是这段时间又出现了无法访问的问题,非常闹心,于是想把博客迁移到博客园,继续简简单单地写东西 挺感激 Pages ,这个博 ...

  10. 关于GDPR体系文件介绍,介绍GDPR体系文件的内容和意义

    随着数字化时代的到来,个人数据保护成为了一个日益受到关注的问题.欧盟于2018年5月25日颁布了"通用数据保护条例"(GDPR),旨在加强对欧洲公民个人数据的保护.GDPR对企业和 ...