PaddleDetection算法分析(14)

2023-11-11

2021SC@SDUSC

三、SSD训练过程:

源码如下

def vgg(cfg, i, batch_norm=False):
'''
该代码参考vgg官网的代码
'''
    layers = []
    in_channels = i
    for v in cfg:
        # 正常的 max_pooling
        if v == 'M':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2)]

        # ceil_mode = True, 上采样使得 channel 75-->38
        elif v == 'C':
            layers += [nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=True)]
        else:
            conv2d = nn.Conv2d(in_channels, v, kernel_size=3, padding=1)
            if batch_norm:
                layers += [conv2d, nn.BatchNorm2d(v), nn.ReLU(inplace=True)]
            else:
                layers += [conv2d, nn.ReLU(inplace=True)]
            # update in_channels
            in_channels = v

    # max_pooling (3,3,1,1)        
    pool5 = nn.MaxPool2d(kernel_size=3, stride=1, padding=1)
    # 新添加的网络层 1024x3x3
    conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)

    # 新添加的网络层 1024x1x1
    conv7 = nn.Conv2d(1024, 1024, kernel_size=1)

    # 结合到整体网络中
    layers += [pool5, conv6,
               nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True)]
    return layers

# 代码测试
if __name__ == "__main__":
    base = {
    '300': [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'C', 512, 512, 512, 'M',
            512, 512, 512],
    '512': [],
    }
    vgg = nn.Sequential(*vgg(base['300'], 3))
    x = torch.randn(1,3,300,300)
    print(vgg(x).shape)  #(1, 1024, 19, 19)


jaccard overlap 计算示意图(其实就是IOU,叫法不同而已):

 


图12 jaccard overlap
然后看一张训练流程图,比较清晰明了:

 


图13
(1)每一个 prior box 经过Jaccard系数计算和真实框的相似度。
(2)阈值只有大于 0.5 的才可以列为候选名单;假设选择出来的是N个匹配度高于百分之五十的框。
(3)我们令 i 表示第 i 个默认框,j 表示第 j 个真实框,p表示第p个类。那么 表示 第 i 个 prior box 匹配到 第 j 个 ground truth box ,并且这个ground truth box的 类别是p,若不匹配的话,则=0 。
(4)总的目标损失函数(objective loss function)为 localization loss(loc) 与 confidence loss(conf) 的加权求和。

损失函数 Loss计算:

总体目标损失函数定位损失(loc)和置信度损失(conf)的加权和:

 

        对于SSD,虽然paper中指出采用了所谓的“multibox loss”,但是可以看到与常见的 Object Detection模型的目标函数相同,SSD算法的目标函数分为两部分:计算相应的default box与目标类别的confidence loss以及相应的location loss(位置回归)。其中N是匹配到GT(Ground Truth)的prior box数量,如果N=0,则将损失设为0;而 α 参数用于调整confidence loss和location loss之间的比例,默认 α=1。

SSD中的confidence loss是是在多类别置信度(c)上的softmax loss,公式如下:

 

      其中 i 指代搜索框序号,j 指代真实框序号,p 指代类别序号,p=0 表示背景。其中中取1表示第 i 个prior box匹配到第 j 个GT box,而这个GT box的类别为 p 。 表示第i个搜索框对应类别p的预测概率。此处有一点需要关注,公式前半部分是正样本(Pos)的损失,即分类为某个类别的损失(不包括背景),后半部分是负样本(Neg)的损失,也就是类别为背景的损失。

而location loss(位置回归)是典型的smooth L1 loss:

 

其中, 为预测框, 为 ground truth。  为补偿(regress to offsets)后的默认框  的中心, 为默认框的宽和高

更详细的解释看一看下图:

 

1、Matching strategy(匹配策略):

在训练时,ground truth boxes 与 default boxe(就是prior boxes) 按照如下方式进行配对:

第一个原则:从ground truth box出发,寻找与每一个ground truth box有最大的jaccard overlap的default box,这样就能保证每一个groundtruth box一定与一个default box对应起来(所谓的jaccard overlap就是IOU,如图12)。 反之,若一个prior box没有与任何ground truth进行匹配,那么该prior box只能与背景匹配,就是负样本。一个图片中ground truth是非常少的, 而default box却很多,如果仅按第一个原则匹配,很多default box会是负样本,正负样本极其不平衡,所以需要第二个原则。
第二个原则:从default box出发,对剩余的还没有配对的default box与任意一个ground truth box尝试配对,只要两者之间的jaccard overlap大于阈值(一般是0.5),那么该default box也与这个ground truth进行匹配。这意味着某个ground truth可能与多个Prior box匹配,这是可以的。但是反过来却不可以,因为一个prior box只能匹配一个ground truth,如果多个ground truth与某个prior box的 IOU 大于阈值,那么default box只与IOU最大的那个Prior box进行匹配。注意:第二个原则一定在第一个原则之后进行,仔细考虑一下这种情况,如果某个ground truth所对应最大 IOU小于阈值,并且所匹配的Prior box却与另外一个ground truth的 IOU大于阈值,那么该Prior box应该匹配谁,答案应该是前者,首先要确保某个ground truth一定有一个Prior box与之匹配。但是,这种情况我觉得基本上是不存在的。由于Prior box很多,某个ground truth的最大 IOU 肯定大于阈值,所以可能只实施第二个原则既可以了。
显然配对到GT的default box就是positive,没有配对到GT的default box就是negative。只有正样本才会参与loss的计算。

图14 先验框匹配示意图


      图14为一个匹配示意图,其中绿色的GT是ground truth,红色为Prior box,FP表示负样本,TP表示正样本。

 

2、Hard negative mining:

       值得注意的是,一般情况下negative default boxes数量>>positive default boxes数量,直接训练会导致网络过于重视负样本,从而loss不稳定。为了保证正负样本尽量平衡,SSD在训练时采用了hard negative mining,即依据confidience loss对default box进行排序,挑选其中confidience loss高的box进行训练,将正负样本的比例控制在positive:negative=1:3。显而易见,用来训练网络的负样本为提取的负样本的子集,那么,我们当然选择负样本中容易被分错类的困难负样本来进行网络训练这样会取得更好的效果。有下面一种说法:SSD采用了hard negative mining,就是对负样本进行抽样,抽样时按照置信度误差(预测背景的置信度越小,误差越大)进行降序排列,选取误差的较大的top-k作为训练的负样本,以保证正负样本比例接近1:3。--自己还没有仔细验证。以后搞明白后补充。下面提供的是正负样本都做难例子挖掘。

具体过程如下:

正负样本区分:(通过定位信息(iou)初步划分,而后通过loss把hard example留下,loss越大越hard)

(2.1) 正样本获得

      已经确定 default box,结合 ground truth,下一步要将 default box 匹配到 ground truth 上,根据上面两个原则,从 groudtruth box 出发给每个 groudtruth box 找到了最近(IOU最大)的 default box 放入候选正样本集。然后再从 default box 出发为 default box 集中寻找与 groundtruth box 满足 IOU>0.5 的的default box放入候选正样本集。

(2.2) 负样本获得(这是一个难例挖掘的过程)

       在生成 prior boxes 之后,会产生很多个符合 ground truth box 的 positive boxes(候选正样本集),但同时,不符合 ground truth boxes 也很多,而且这个 negative boxes(候选负样本集),远多于 positive boxes。这会造成 negative boxes、positive boxes 之间的不均衡。训练时难以收敛。

(2.3)难例挖掘

      将每一个GT上对应prior boxes的分类loss 进行排序。

      对于候选正样本集:选择loss最高的m个 prior box 与候选正样本集匹配 (box 索引同时存在于这两个集合里则匹配成功),匹配不成功则从候选正样本集中删除这个正样本(因为这个正样本loss太低,易被识别,所以不在难例里,已经很接近 ground truth box 了,不需要再训练);

       对于候选负样本集:选择loss最高的m个prior box 与候选负样本集匹配,匹配成功的则留下来作为最后的负样本,不成功剔除出候选负样本集,因为他们loss不够大,易被识别为背景,训练起来没难度没提升空间。

(2.4)举例:假设在这 8732 个 default box 里,经过 FindMatches 后得到候选正样本 P 个,候选负样本那就有 8732−P个。将 prior box 的 prediction loss 按照从大到小顺序排列后选择最高的 M个 prior box。如果这 P 个候选正样本里有 a 个 box 不在这 M 个 prior box 里,则将这 a个 box 从候选正样本集中踢出去。如果这 8732−P个候选负样本集中有 b个在这 M 个 prior box,则将这b个候选负样本作为正式负样本。即删除易识别的正样本,同时留下典型的负样本,组成1:3的prior boxes样本集合。SSD 算法中通过这种方式来保证 positives、negatives 的比例。

(2.5)Hard example mining

       example mining 是选择出特定样本来计算损失函数;从实际问题出发 hard example 应该就是指定位较困难或分类较困难或者两者都困难的候选框。SSD 的 caffe 中支持 negative mining 和 hard example mining,当 share_location 参数为 true 时,只支持 negative mining。

       Hard negative example 或 Hard positive example 的定义需要首先确定某个候选框是 negative example 还是 positive example。比如 SSD 中将与任意 gt_bbox 的 IOU 超过给定阈值 overlap_threshold(SSD 默认为 0.5)的当作正样本,即前景类别为正样本,背景类别为负样本。比如,极端的例子,当图像中没有 gt_bbox 时,那么所有的 default bboxes 都是 negative example。

      SSD 中 negative mining 只计算分类损失而不计算定位损失,而 hard example mining 对分类损失和定位损失都进行计算。

SSD 的 negative mining 的过程为:

1)生成default bboxes,每个检测器对应特征图生成的default boxes数目为n*n*6或n*n*4;

2)匹配default boxes,将每个 default box 与 ground truth 匹配,保证每个ground truth 都能对应多个default boxes,避免漏检;

3)衡量default boxes,当第 i 个 default box 被匹配到第 j 个 gt_bbox,那么计算其属于背景类别的 softmax loss 或 cross entropy loss 值;


softmax分类器

4)筛选default boxes, 计算完所有default boxes 的分类 loss后,按照 loss 排序,选择 loss 较大且与任意 gt_bbox 之间的 iou 小于 阈值neg_overlap 的样本中的前 3*num_positive 个负样本(保证留下的负样本“够坏”,同时保证1:3的正负比例)。

      而后,这正负比为1:3的部分default boxes就是筛选全体default box后剩下的prior boxes,用这些prior box作为参考,对所有预测框其进行分类和回归,进行反向传播更新网络参数,即训练。

3、Data augmentation(数据增强):

 


图15 数据增强

 

数据增强,即每一张训练图像,随机的进行如下几种选择:

      1、使用原始的图像

      2、采样一个 patch,与物体之间最小的 jaccard overlap 为:0.1,0.3,0.5,0.7 或 0.9

      3、随机的采样一个 patch,采样的 patch 是原始图像大小比例是[0.1,1],aspect ratio在 1/2与2之间。当 groundtruth box 的 中心(center)在采样的patch中时,保留重叠部分。在这些采样步骤之后,每一个采样的patch被resize到固定的大小,并且以0.5的概率随机的 水平翻转(horizontally flipped)。

           主要采用的技术有水平翻转(horizontal flip),随机裁剪加颜色扭曲(random crop & color distortion),随机采集块域(Randomly sample a patch)(获取小目标训练样本)
       如上图所示,SSD算法使用了多种数据增强的方法,包括水平翻转(horizontal flip),随机裁剪(random crop)、颜色扭曲(color distortion 或者对比度调整),随机采集块域(Randomly sample a patch------目的———获取小目标训练样本)等。论文明确指出,数据增强可以明显的提高算法的性能。主要的目的是为了使得该算法对输入的不同大小和不同形状的目标具有更好的鲁棒性。直观的理解是通过这个数据增强操作可以增加训练样本的个数,同时构造出更多的不同形状和大小的目标,将其输入到网络中,可以使得网络学习到更加鲁棒的特征。

      其实Matching strategy,Hard negative mining,Data augmentation,都是为了加快网络收敛而设计的。尤其是Data augmentation,翻来覆去的randomly crop,保证每一个prior box都获得充分训练而已。不过当数据达到一定量的时候,不建议再进行Data augmentation,毕竟”真”的数据比“假”数据还是要好很多。

4、Atrous Algothrim(获得更加密集的得分映射)

def vggs():  
    '''
    调用torchvision.models里面的vgg,
    修改对应的网络层,同样可以得到目标的backbone。
    '''
    vgg16 = models.vgg16()
    vggs = vgg16.features
    vggs[16] = nn.MaxPool2d(2, 2, 0, 1, ceil_mode=True)
    vggs[-1] = nn.MaxPool2d(3, 1, 1, 1, ceil_mode=False)
    conv6 = nn.Conv2d(512, 1024, kernel_size=3, padding=6, dilation=6)
    conv7 = nn.Conv2d(1024, 1024, kernel_size=1)
    '''
    方法一:
    '''
    #vggs= nn.Sequential(feature, conv6, nn.ReLU(inplace=True), conv7, nn.ReLU(inplace=True))

    '''
    方法二:
    '''
    vggs.add_module('31',conv6)
    vggs.add_module('32',nn.ReLU(inplace=True))
    vggs.add_module('33',conv7)
    vggs.add_module('34',nn.ReLU(inplace=True))
    #print(vggs)
    x = torch.randn(1,3,300,300)
    print(vggs(x).shape)

    return vgg


Caption

图16 Atrous Algothrim
       作用:既想利用已经训练好的模型进行fine-tuning,又想改变网络结构得到更加dense的score map。这个解决办法就是采用Hole算法。如上图(a) (b)所示,在以往的卷积或者pooling中,一个filter中相邻的权重作用在feature map上的位置都是物理上连续的。如上图(c)所示,为了保证感受野不发生变化,某一层的stride由2变为1以后,后面的层需要采用hole算法,具体来讲就是将连续的连接关系是根据hole size大小变成skip连接的(图(c)为了显示方便直接画在本层上了)。不要被(c)中的padding为2吓着了,其实2个padding不会同时和一个filter相连。 pool4的stride由2变为1,则紧接着的conv5_1, conv5_2和conv5_3中hole size为2。接着pool5由2变为1, 则后面的fc6中hole size为4。 
     Atrous Algothrim理解2:
如上图所示,Atrous Algothrim可以在提高feature map大小的同时提高接收场的大小,即可以获得更加密集的score map。

5、NMS(非极大值抑制)

       在SSD算法中,NMS至关重要,因为多个feature map 最后会产生大量的BB,然而在这些BB中存在着大量的错误的、重叠的、不准确的BB,这不仅造成了巨大的计算量,如果处理不好会影响算法的性能。仅仅依赖于IOU(即预测的BB和GT的BB之间的重合率)是不现实的,IOU值设置的太大,可能就会丢失一部分检测的目标,即会出现大量的漏检情况;IOU值设置的太小,则会出现大量的重叠检测,会大大影响检测器的性能,因此IOU的选取也是一个经验活,常用的是0.65,建议使用论文中作者使用的IOU值,因为这些值一般都是最优值。即在IOU处理掉大部分的BB之后,仍然会存在大量的错误的、重叠的、不准确的BB,这就需要NMS进行迭代优化。

四、SSD性能评估


1、模块性能评估


 


表1 模块性能评估
观察上图可以得到如下的结论:
       数据增强方法在SSD算法中起到了关键性的作用,使得mAP从65.5变化到71.6,主要的原因可能是数据增强增加了样本的个数,使得模型可以获得更多不一样的样本,即提高了样本的多样性,使得其具有更好的鲁棒性,从而找到更接近GT的BB。
    [1/2,2]和[1/3, 3]box可以在一定程度上提升算法的性能,主要的原因可能是这两种box可以在一定程度上增加较大和较小的BB,可以更加准确的检测到较大和较小的目标,而且VOC数据集上面的目标一般都比较大。当然,更多的比例可以进一步提升算法的性能。
       atrous算法可以轻微提升算法性能,但是其主要的作用是用来提速,论文中表明它可以提速20%。主要的原因可能是虽然该算法可以获得更大的feature map和接收场,但是由于SSD本身利用了多个feature map来获取BB,BB的多样性已经足够,由于feature map扩大而多得到的BB可能是一些重复的,并没有起到提升检测性能的作用。

2、SSD加速的原因


表2 SSD的BB个数
       如上图所示,当Faster-rcnn的输入分辨率为1000x600时,产生的BB是6000个;当SSD300的输入分辨率为300x300时,产生的BB是8372个;当SSD512的输入分辨率为512x512时,产生的BB是24564个,大家像一个情况,当SSD的分辨率也是1000x600时,会产生多少个BB呢?这个数字可能会很大!但是它却说自己比Faster-rcnn和YOLO等算法快很多,我们来分析分析原因。
    原因1:首先SSD是一个单阶段网络,只需要一个阶段就可以输出结果;而Faster-rcnn是一个双阶段网络,尽管Faster-rcnn的BB少很多,但是其需要大量的前向和反向推理(训练阶段),而且需要交替的训练两个网络;
    原因2:Faster-rcnn中不仅需要训练RPN,而且需要训练Fast-rcnn,而SSD其实相当于一个优化了的RPN网络,不需要进行后面的检测,仅仅前向推理就会花费很多时间;
    原因3:YOLO网络虽然比SSD网络看起来简单,但是YOLO网络中含有大量的全连接层,和FC层相比,CONV层具有更少的参数;同时YOLO获得候选BB的操作比较费时;
    原因4:SSD算法中,调整了VGG网络的架构,将其中的FC层替换为CONV层,这一点会大大的提升速度,因为VGG中的FC层都需要大量的运算,有大量的参数,需要进行前向推理;
    原因5:使用了atrous算法,具体的提速原理还不清楚,不过论文中明确提出该算法能够提速20%。
    原因6:SSD设置了输入图片的大小,它会将不同大小的图片裁剪为300x300,或者512x512,和Faster-rcnn相比,在输入上就会少很多的计算,不要说后面的啦,不快就怪啦!!!


3、训练结果图

       训练迭代了130K次,学习率为0.001(出现跳跃是因为之前没有加入VGG16的checkpoint),可以发现在100K次之后基本没有太大变化趋于收敛状态,最后第130K次时候的loss=3.4。


Caption
    其中用于softmax分类的cross_entrpy和localization的loss也基本收敛以及正负样本个数 如下变化:


Caption
    训练后SSD300在VOC2007的mAP为62%,论文中为68%。

五、SSD网络结构优劣分析


优点:       

       SSD算法的优点应该很明显:运行速度可以和YOLO媲美,检测精度可以和Faster RCNN媲美。SSD对不同横纵比的object的检测都有效,这是因为算法对于每个feature map cell都使用多种横纵比的default boxes,这也是本文算法的核心。最后本文也强调了增加数据集的作用,包括随机裁剪,旋转,对比度调整等等。

缺点:

       1、需要人工设置prior box的min_size,max_size和aspect_ratio值。网络中prior box的基础大小和形状不能直接通过学习获得,而是需要手工设置。而网络中每一层feature使用的prior box大小和形状恰好都不一样,导致调试过程非常依赖经验。(相比之下,YOLO2使用聚类找出大部分的anchor box形状,这个思想能直接套在SSD上)

       2、虽然采用了pyramdial feature hierarchy的思路,但是对小目标的recall依然一般,并没有达到碾压Faster RCNN的级别。作者认为,这是由于SSD使用conv4_3低级feature去检测小目标,而低级特征卷积层数少,存在特征提取不充分的问题。所以增加输入图像的尺寸对于小的object的检测有帮助。另外增加数据集(此处主要是指裁剪)对于小的object的检测也有帮助,原因在于随机裁剪后的图像相当于“放大”原图像,所以这样的裁剪操作不仅增加了图像数量,也放大了图像。
 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PaddleDetection算法分析(14) 的相关文章

随机推荐