zoukankan      html  css  js  c++  java
  • 目标检测小网络

    目标检测小网络

    一. Anchor-based

    1.1 网络结构

    当前一般采用

    • backbone:shufflenetV2、mobilenetV2/3(V3比较难调试)、Ghostnet、SandGlass
    • FPN:PAN、BiFPN,这部分对检测提升很大(实际使用得进行裁剪压缩,原始版本不适合小模型),追求极致性能的网络可以去除(比如人脸检测超小模型,这类目标特征明显且背景不是很复杂的情况)
    • Head:RFB、SSH,如果不加FPN结构,Head必须做一番手脚,如果存在FPN,简单使用几个卷积即可
    • 输出:(这部分一般包含在Head内部,最近遇到这个问题单独提出来),可以使用cls+reg共享一个卷积,也可以单独卷积(每层之间也可以共享或单独),小模型一般每层不共享(共享效果差,有朋友已实测),cls和reg之间随意选择(共享最好做一些trick,最好增加FPN,不共享可以增加RFB等操作)

    小模块一般采用:

    • 模块卷积一般使用Depthwise结构,小卷积一般使用 (1 imes1) 卷积(很少使用 (3 imes3) 卷积)
    • backbone的输出通道尽可能的大(笔者尝试 (chennels=[24, 48, 96]) 的输出效果很差),最基础的保证backbone的输出大于FPN的输出
    • 小模型一般在 (stride=[8,16,32,64]) 进行采样,(stride=4) 没见过有人在小模型上使用
    • 关于BatchNormalize操作,小网络一般使用BN即可,大网络使用GN效果较好(也可以直接使用torch自带的sync-BN)

    loss的使用:

    • 正负样本采用 (3:1) ,loss直接采用SSD,刚开始可以使用此方法,交叉熵的loss一般在1.0以下(具体多少适合你的网络看结果),如果在0.9附近无法下降,实测效果较差
    • Focal-Loss、GHM、TopK,笔者测试在单目标检测中使用较好,误检很少但难以训练
    • 目前使用GIOU、DIOU作为回归较多
    • FocalLoss+GIOU实测效果较好

    1.2 数据和anchor

    • 使用mmdetection进行训练,一定要注意目标的大小,匹配过小(未匹配等)会导致出现Nan出现(查找问题比较困难,之前还以为LR等问题)

    • 数据增强不是越多越好,比如人脸检测不需要上下Flip、人脸检测不需要遮挡问题(情况极少),数据增强过多会导致小模型不收敛,建议先进行基础操作(color-transform + random-crop + resize),之后根据提升进行特定数据增强。

    • 数据和网络尽量保持等比例,笔者数据 (1280 imes720) ,网络输入 (256 imes256) ,padding之后再进行输入明显效果好

    • 小目标过多,为了不丢弃数据,在增强策略先放大然后进行crop,或者直接crop目标区域(尽量不让目标缩小再进网络),笔者测试效果较好

    • anchor在每一层上一定大于stride(原始的RetinaNet中anchor比stride大4倍),小模型一般超过 ( imes1.25) 以上,大模型 ( imes2) 以上

    • 之前有朋友建议两层之间的anchor大小有交集(开源项目没见过这种操作),实际测试提高了召回率同时也增加了误检,看个人取舍

    • 关于感受野和anchor的关系,这部分前两年说的较多,现在论文基本没见过了

    1.3 一系列问题

    • loss出现Nan
      • 首先排查数据问题,一般是未匹配(目标太小,超出边界等)
      • 尽量使用预训练模型(如果没有,先训练小批量数据得到预训练模型,之后再大数据上再训练)
      • 减少学习率和batchsize等操作
    • 小目标检测较差
      • 查看anchor最小检测的尺寸(当正样本IOU=0.5,意味着最小检测尺寸是最小anchor的一般半,但实际上我们粗略认为最小目标等于最小anchor,因为考虑到anchor和目标匹配的问题(比如两个anchor之间存在一个目标))
      • 增大stride,上面我们说到小模型一般stride不小于8,过小的stride对网络来说负担很大(只能增大网络获得trade-off)
      • 多尺度训练,在实际的输入上下浮动即可(笔者将当前概率设为0.6,上下两个尺度设为0.2),实现方式两种:mmdet里面直接padding,yolov4直接resize操作,笔者仅使用了后者
      • mosic数据增强
      • 网络结构,比如SSH针对小人脸检测较好
      • anchor匹配的时候给予小目标更大权重(笔者猜测,未尝试)
    • 误检较多
      • 语义无关的情况,可以扣mask打背景(比如杯子、苹果等检测),当然人脸检测肯定不行
      • 增加样本,针对性的训练
      • 多尺度训练,参见上文,实测有效
      • 改变loss,针对困难样本的训练

    1.4 具体案例

    • MobilenetV3+SSD+FPN
    • libface、utralface(实测对柔性检测较差,对人脸检测很好)
    • Yolov3/4/5剪枝
    • efficientnet缩小版

    这里以目前最流行的人脸检测器之一为例:

    Model model file size(MB)
    libfacedetection v1(caffe) 2.58
    libfacedetection v2(caffe) 3.34
    Official Retinaface-Mobilenet-0.25 (Mxnet) 1.68
    version-slim 1.04
    version-RFB 1.11
    Model Easy Set Medium Set Hard Set
    libfacedetection v1(caffe) 0.65 0.5 0.233
    libfacedetection v2(caffe) 0.714 0.585 0.306
    Retinaface-Mobilenet-0.25 (Mxnet) 0.745 0.553 0.232
    version-slim 0.77 0.671 0.395
    version-RFB 0.787 0.698 0.438

    从上面两个官方给出的表格,速度快的同时精度也高

    • backbone使用shufflenet改良版本,其中增加RFB用于扩大感受野
    • 中间层使用SSD的multi-feature
    • head使用层不共享且cls与reg之间也不共享的卷DW卷积
    • feature在(stride=[8,16,32,64])上进行检测,anchor设置([[10, 16, 24], [32, 48], [64, 96], [128, 192, 256]]),由于人脸基本呈现方形,所以这里anchor都是(1:1)
    • loss直接使用SSD策略,交叉熵+smoothL1+正负样本按比例挖掘
    • 数据增强使用正常操作(color+random-crop等),未使用最新的mosic等
    • train策略包含很多种,一般采用SGD+Warmup+Cosin

    二. Anchor-free

    2.1 具体案例

    注释: anchor-free之前流行的都是大网络,比如centerNet、FCOS、ATSS等,因为小网络很难训练centerness(网络有人测试),基本没见到小网络效果好的版本。自从GFL-V1论文出来以后,使得loss训练较为容易,然后NanoDet问世了。

    这里直接以目前最流程的anchor-free小网络为例

    Model Resolution COCO mAP Latency(ARM 4xCore) FLOPS Params Model Size(ncnn bin)
    NanoDet-m 320*320 20.6 10.23ms 0.72B 0.95M 1.8mb
    NanoDet-m 416*416 21.7 16.44ms 1.2B 0.95M 1.8mb
    YoloV3-Tiny 416*416 16.6 37.6ms 5.62B 8.86M 33.7mb
    YoloV4-Tiny 416*416 21.7 32.81ms 6.96B 6.06M 23.0mb
    • backbone使用shuffenetV2(原封不动)
    • FPN使用PAN简化版,直接双线性插值之后add即可
    • head层之间不共享,cls与reg之间进行共享卷积
    • loss使用GFL-V1版本
    • 数据增强常规操作(未使用random-crop,未使用mosaic)
    • train直接使用SGD+Warmup+LinerStep

    2.2 改进策略

    • 数据增强

    原版NanoDet仅使用简单操作,针对自己数据集进行特定数据增强,实测效果很大

    • 训练多尺度

    有效改善误检和漏检(建议使用预训练模型,直接使用容易崩)

    • 最近GFL-V2出来了,尝试将trick加入Nanodet之中

    笔者稍微修改了一下trick,目的两点:1)尽量不修改Nanodet结构。2)更容易训练。3)效果尽可能好。

    直接使用GFL-V2很难训练,而且误检率较高,NanoDet作者给出的原因是共享的cls+reg对分布不敏感,不适用共享的卷积效果可以提升。笔者猜测原因:1)共享卷积已经学到部分分布信息。2)小网络最后阶段直接使用分布去指导质量分数很难收敛。

    未加入GFL-V2,实测效果未提升反而下降

    # 层定义
    self.reg_conf = nn.ModuleList([nn.Sequential(nn.Conv2d(4 * 8, 32, 1),
                                                         nn.LeakyReLU(negative_slope=0.1, inplace=True),
                                                         nn.Conv2d(32, 1, 1), nn.Sigmoid()) for _ in self.anchor_strides])
    self.reg_cls_com = nn.ModuleList([nn.Conv2d(2, 1, 1) for _ in self.anchor_strides]) 
    
    # 前向传播
    def forward_single(self, x, cls_convs, reg_convs, gfl_cls, gfl_reg, reg_conf, reg_cls_com):
            cls_feat = x
            reg_feat = x
            for cls_conv in cls_convs:
                cls_feat = cls_conv(cls_feat)
            for reg_conv in reg_convs:
                reg_feat = reg_conv(reg_feat)
            if self.share_cls_reg:
                feat = gfl_cls(cls_feat)
                cls_score, bbox_pred = torch.split(feat, [self.cls_out_channels, 4 * (self.reg_max + 1)], dim=1)
            else:
                cls_score = gfl_cls(cls_feat)
                bbox_pred = gfl_reg(reg_feat)
    
            B,C,H,W = bbox_pred.shape
            prob = F.softmax(bbox_pred.reshape(B, 4, self.reg_max+1, H*W), dim=2)
            quality_score = reg_conf(prob.reshape(B, C, H, W))
            cls_score = cls_score * quality_score
            
            #cls_score = torch.cat([cls_score, quality_score],dim=1)
            #cls_score = reg_cls_com(cls_score)
    
            if torch.onnx.is_in_onnx_export():
                cls_score = torch.sigmoid(cls_score).reshape(1, self.num_classes, -1).permute(0, 2, 1)
                bbox_pred = bbox_pred.reshape(1, (self.reg_max+1)*4, -1).permute(0, 2, 1)
            return cls_score, bbox_pred
           
    
    • 改变网络结构
    • [ ] backbone优化(GhostNet、如果使用mobilenetV2可以增加CSPNet进行通道压缩)
    • [ ] FPN优化(DUpsample进行上采样)
    • [x] head优化(cls和reg不共享卷积,如果使用共享卷积可以在最后增加1*1卷积进行优化)
    • [x] 使用类似二阶段网络,将当前网络作为一阶段网络,二阶段网络使用一阶段的结果输入,直接分类(背景,目标1,目标2....),如果追求更精确可以在二阶段加回归(这种情况得有负值,因为一阶段输出会有截断情况,即使扩大检测范围也不可避免截断)
    • 注意点
    • 小网络的backbone至关重要远远大于后面neck和head比重。实测:基于NanoDet模型,shufflenetV2做主干提取S=4,8,16,32,64,其中在maxpooling后面接两个block模块然后再提取S=4层,PAN上采样使用反卷积,下采样使用maxpooling,中间穿插1*1卷积。计算量达到440MB,但是和原始NanoDet320MB对比效果差很多,后面试验发现backbone信息丢失过多,后面如果增加计算量都无法补充。提取层数过多,backbone尽量别别使用maxpooling。

    当然都是建立在尽量减少计算量的基础上进行优化,做到trade-off

  • 相关阅读:
    Java——enum与int的转换——转载
    Java——JScrollPane设置透明——转载
    Java——JFrame与JButton添加背景
    Java——模态对话框
    u-boot_2010.6 nandflash驱动彻底分析
    linux 常用命令整理----权限管理
    linux 常用命令整理----链接文件
    linux 常用命令整理----文件操作
    linux 常用命令整理----目录操作
    linux 进程运行状态
  • 原文地址:https://www.cnblogs.com/wjy-lulu/p/14124058.html
Copyright © 2011-2022 走看看