ViT攻陷检测,CNN还有多久被弃用?

机器学习算法工程师

共 10834字,需浏览 22分钟

 ·

2022-07-09 12:09

点蓝色字关注“机器学习算法工程师

设为星标,干货直达!

ViTDet是Meta AI团队(kaiming团队)在MAE之后提出的基于原生ViT模型作为骨干网络的检测模型。在最早的论文中,作者初步研究了以ViT作为骨干网络的检测模型所面临的挑战(架构的不兼容,训练速度慢以及显存占用大等问题),并给出了具体的解决方案,最重要的是发现基于MAE的预训练模型展现了较强的下游任务迁移能力,效果大大超过随机初始化和有监督预训练模型。而最新的论文对上述工作做了进一步的拓展和优化,给出了性能更好的ViTDet,目前代码已经开源在detectron2的,这篇文章将主要结合第二篇论文和代码解读ViTDet。

模型设计

ViTDet选用Mask R-CNN架构作为主要研究对象,这里采用了优化版本,具体的改进主要包括以下几点:

  • RPN采用2个隐含的卷积层(默认是1个);
  • ROI heads的box head由原来的2个全连接层变为4个卷积层+1个全连接层;
  • ROI heads的box head和mask head的卷积层之间均采用LayerNorm(最早的版本是采用BatchNorm,但往往需要SyncBN,而LN则不受batch size的影响)。
model.roi_heads.box_head.conv_norm = model.roi_heads.mask_head.conv_norm = "LN"

# 2conv in RPN:
model.proposal_generator.head.conv_dims = [-1-1]

# 4conv1fc box head
model.roi_heads.box_head.conv_dims = [256256256256]
model.roi_heads.box_head.fc_dims = [1024]

对于这个优化版本,采用较强的数据增强(large scale jittering,LSJ)和训练时长(100 epcohs),输入的图片大小为1024x1024,其中LSJ是谷歌在论文中提出的,如下图所示,相比标准的scale jittering,LSJ的resize range更大(0.1~2.0)。采用ViT作为Mask R-CNN的骨干网络,首先是要解决的就是特征金字塔的问题。对于采用金字塔结构的CNN来说,可以通过提取它的1/4,1/8,1/16和1/32特征送入FPN来构建特征金字塔;但ViT采用同质架构,这使得ViT只能得到一种尺度(1/16)的特征。为了解决这个问题,论文提出了一种简单的方法来从ViT中构建特征金字塔,如下图右所示:ViT的最后一层特征的大小是1/16尺度(这里ViT的patch size=16x16,论文中所有ViT模型均是如此),然后直接通过strides={2, 1, 1/2, 1/4}的卷积来产生多尺度的特征:1/32,1/16,1/8和1/4。具体地,stride=2时采用stride=2的2x2 maxpooling;stride=1时不进行任何操作即采用identify;stride=1/2时采用stride=2的2x2反卷积;而stride=1/4时采用2个连续的stride=2的2x2反卷积,两个反卷积之间增加LN+GeLU。代码实现如下所示:

        self.stages = []
        use_bias = norm == ""
        for idx, scale in enumerate(scale_factors):
            out_dim = dim
            if scale == 4.0:
                layers = [
                    nn.ConvTranspose2d(dim, dim // 2, kernel_size=2, stride=2),
                    get_norm(norm, dim // 2),
                    nn.GELU(),
                    nn.ConvTranspose2d(dim // 2, dim // 4, kernel_size=2, stride=2),
                ]
                out_dim = dim // 4
            elif scale == 2.0:
                layers = [nn.ConvTranspose2d(dim, dim // 2, kernel_size=2, stride=2)]
                out_dim = dim // 2
            elif scale == 1.0:
                layers = []
            elif scale == 0.5:
                layers = [nn.MaxPool2d(kernel_size=2, stride=2)]
            else:
                raise NotImplementedError(f"scale_factor={scale} is not supported yet.")

            layers.extend(
                [
                    Conv2d(
                        out_dim,
                        out_channels,
                        kernel_size=1,
                        bias=use_bias,
                        norm=get_norm(norm, out_channels),
                    ),
                    Conv2d(
                        out_channels,
                        out_channels,
                        kernel_size=3,
                        padding=1,
                        bias=use_bias,
                        norm=get_norm(norm, out_channels),
                    ),
                ]
            )
            layers = nn.Sequential(*layers)

            stage = int(math.log2(strides[idx]))
            self.add_module(f"simfp_{stage}", layers)
            self.stages.append(layers)

直接对最后一层的1/16特征进行4个不同的操作之后,就可以得到4个不同尺度的特征,然后每个尺度特征再经过1x1 conv + LN + 3x3 conv来转换到同一特征维度(这里采用256),从而完成特征金字塔的构建。可以看到,与层级的CNN+FPN相比,这种简单的方式不需要自上而下的结构以及横向连接,更简单了。论文也提出了其它的一些构建方式,如下图中的(a)和(b),其中图(a)是论文的第一个版本所采用的方案,它是完成模仿层级CNN+FPN这种方式:直接将ViT的transformer blocks均分为4个部分,分别用1/4,1/2,3/4和4/4位置处得到的特征来得到1/4,1/8,1/16和1/32尺度的特征(通过上采样和下采样),然后送入FPN。而图(b)是进一步简化了图(a),这里直接用最后一层输出通过下采样或者上采样来得到4个尺度特征,然后送入FPN。而图(c)就进一步做了简化,直接去掉了FPN,这也就是最后所采用的简化方式。

论文也对几种方式做了对比实验,如下表所示,可以看到采用特征金字塔效果是要明显优于单尺度模型的(直接用ViT的最后的1/16特征进行检测,这其实Faster R-CNN论文最早采用的方式,但是RPN放置了多尺度的anchors)。而采用最简单的方式效果并不比带FPN的(a)和(b)方式差,这说明FPN对ViT并不起效,这不难理解,FPN是为层级的CNN所设计,而ViT采用同质结构,所有层的特征分辨率是一样的,并没有必要再利用中间的特征来构建特征金字塔了。ViT用于检测模型的第二个挑战是计算效率问题,ViT中self-attention的计算量和图像大小的平方成正比,而检测模型往往需要较大的图像分辨率(224x224 -> 1024x1024),这会使得模型计算量爆炸,不仅导致训练速度变慢,而且显存消耗非常大。论文采用的优化思路是将ViT采用的global attention换成局部的window attention,这里的window size和ViT预训练的特征图大小设置为一样:14x14(ViT预训练的图像大小是224x224,此时特征图大小就为224/16=14),这样做的好处可以直接采用重新设计预训练而直接采用原生ViT的预训练权重。采用window attention虽然大大降低了模型的计算量,但是各个windows之间就缺少了信息交流,一种解决方案是像swin transformer那样采用shifted window,不过论文采用了更简单的方法:将ViT的blocks均分成4个部分,然后每个部分的最后一个block上采用一些特定的传播策略来实现跨windows间的信息交互。这里共考虑两种策略:

  • Global propagation:每个部分的最后一个block不再采用window attention,而是采用原始的global attention;
  • Convolutional propagation:每个部分的最后加上一个residual conv block,它包括1个或者多个卷积层(比如采用1x1 conv + 3x3 conv + 1x1 conv的bottleneck结构)和一个shortcut,如果我们将这个block的最一个conv层初始化为0,那么这个block的初始状态就是一个identify,这意味着不会影响预训练模型的初始状态。

由于global attention具有全局性,所以Global propagation是可以实现跨windows间的信息传递;虽然卷积是局部操作,但是它也却能联通相邻的windows边缘像素,通过后面的window attention就可以实现所有像素的连接。其中window attention + Global propagation结构示意图如下所示(这里采用的是 FPN 4-stage,第一个论文版本中的图):

下表为不同方案的对比效果,其中none指的是只采用window attention,此时效果是最差的;而在window attention的基础上采用Global propagation(4 global)或者Convolutional propagation(4 conv, bottleneck)均可以得到较好的结果,而且训练显存和测试时间增加较少。如果所有的blocks均采用global attention(24 global,即最原始的ViT)虽然可以取得更好的结果,但是训练显存和测试时间均大幅度增加,对于ViT-L模型需要49GB的显存,如果不进行显存优化,单卡的A100也无法训练一张图像。除此之外,论文还有更详细的对比实验,如下表所示:(a)中和shifted window做了对比,可以看到并不比global propagation和conv propagation更有效;(b)中对比了不同conv block类型,差别并不是特别明显;(c)对了global propagation中的global attention的位置,均匀地放置或者放置最后4个block均可以取得较好的结果,但是在最前4个block效果就差一些,因为在后面的windows间就缺乏信息传递了;(c)对比了global attention数量对模型效果的影响。除了结构上的改进,预训练策略对ViTDet性能有较大的影响,如下表所示,随机初始化效果要比有监督预训练模型要好,而采用无监督MAE预训练模型可以大幅度提升效果第一个版本论文给出了不同预训练策略下不同epoch下的性能曲线,可以看到虽然有监督预训练模型收敛速度比随机初始化快,但是也出现了更早的收敛,当训练时长较长时,随机初始化反而能得到更好的性能(heavy的数据增强+较长的训练时长往往不需要预训练模型)。相比之下,MAE预训练模型表现了更好的收敛和性能。

对比实验

论文中主要有两个主要的对比实验,第一个就是ViTDet和其它基于层级backbone的检测模型对比,这里选择了两个backbone:Swin和MViTv2,它们均采用和CNN一样的金字塔结构,检测的neck采用FPN。这里的检测模型采用两个架构:Mask R-CNN和Cascade Mask RCNN。Swin和MViTv2均使用了relative position bias,所以为了公平对比,也在ViT中增加了relative position bias(只是finetune时增加),这里的策略和MViTv2相同(和Swin略有不同)。对比结果如下所示,可以看到对于较小的模型ViT-B,它能和同量级的Swin-B和MViTv2-B取得相似的性能,但是对于更大的模型ViT-L和ViT-H,其效果要更好一点。下图给出了AP和模型参数量,FLOPs和测试时长的关系图,可以更明显地看出ViTDet的优势:另外,论文还补充了基于one-stage的检测模型RetinaNet的对比,和Mask R- CNN模型的趋势一致。

第二个对比是和其它SOTA模型的对比,这里做了两个改进,一是采用soft-nms,二是将输入图像大小从1024增加到1280。对比结果如下表所示,其中基于ViT-H的ViTDet采用mutli-scale测试能达到61.3的box AP,稍差于现在的SOTA模型DINO(63.3)。

image.png

小结

ViTDet这个工作系统地探讨了如何将ViT更好地应用在下游检测任务,它不直接对改变原生ViT的预训练过程,而是在适应下游任务上做适当地改进,并实现了和层级ViT模型类似甚至更好的性能,而且也证明了MAE预训练对性能的提升所起到的巨大作用。


推荐阅读

深入理解生成模型VAE

DropBlock的原理和实现

SOTA模型Swin Transformer是如何炼成的!

有码有颜!你要的生成模型VQ-VAE来了!

集成YYDS!让你的模型更快更准!

辅助模块加速收敛,精度大幅提升!移动端实时的NanoDet-Plus来了!

SimMIM:一种更简单的MIM方法

SSD的torchvision版本实现详解


机器学习算法工程师


                                    一个用心的公众号


浏览 199
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报