目标检测SSD算法训练过程通俗详解

参考论文: http://static.googleusercontent.com/media/research.google.com/zh-CN//pubs/archive/44872.pdf

参考代码: https://github.com/amdegroot/ssd.pytorch

SSD作为one-stage的目标检测算法,与Faster-RCNN这类的two-stage算法相比,可以在一个神经网络中实现端到端的训练,而不用事先通过RPN网络选出候选框,再用另一个网络做分类和回归。

因此在我看来,SSD主要包括两个核心部分:第一是SSD模型结构,包括他的输入输出,中间的layer等等,由于SSD是one-stage算法,如果对模型结构了解就算成功了一半;第二是SSD的Loss,要实现端到端训练,合理的Loss是必不可少的,而这里的MultiBoxLoss比较复杂,因此这一块可以作为第二个核心部分。

那么就基于这两个核心部分,依次谈一下我看论文和跑代码后一些粗浅的理解。

1. SSD模型结构

论文中的SSD的模型图如下所示:
在这里插入图片描述
从图中可以看出,SSD模型主要三个部分(不要看最后的NMS):

  1. 预训练好的VGG16模型(图中虚线立方体内),去除掉最后用于分类的fully connected层(关于中间pool5的stride和conv4_3后的L2 Norm这种细节可以先忽略);
  2. 接在VGG16后面的Extra Feature Layer,即图中VGG后面的各种卷积层;
  3. 模型的输出部分MultiBox Layer,即图中六个黑色箭头指向的Layer,这一层用于得到模型的输出(图中方框里的文字不用管)。

在VGG16网络中,没有被修改的Layer可直接拿来预训练的参数使用。这里的VGG16将后面的Classifier砍掉,此时的最后一层为Conv5_3(图中未标出)。值得注意的是,VGG中的Conv4_3特征图需要拿出来,输入到模型最后的MultiBox Layer。

Extra Layer包括若干个卷积层block,在每一个block最后的卷积层处,将kernal的stride设定为2(其余stride为1),这样就会得到长宽缩小到一半的小特征图。经过几个这样的block,就可以得到不同尺度的feature map。图中将Conv7, Conv8_2, Conv9_2, Conv10_2, Pool11这五个不同尺度特征图拿出来,与之前VGG网络中的特征图Conv4_3,一并送到模型的MultiBox Layer搞一些事情。

模型的输出部分可以称为MultiBox Layer,其目的是根据前面得到的六张Feature Map,生成一系列的候选Box。假设特征图的尺寸为 m ∗ n m*n mn,数据集中的类别有c类(包括背景类),box的位置信息为(x,y,w,h)的四元组,那么一个box对应的参数有(c+4)个。我们知道,特征图中每一个像素称为一个cell,一个cell上面可以根据不同的ratio选取若干个box(与Faster RCNN中anchor的选取类似,ratio和先验框尺度的选取可以参照上述论文),这里假设一个cell能产生k个box。因此,这一张Feature map选出的box的个数为mnk,所有的参数总量为mnk*(c+4)。

关于k的选取,从前到后六张特征图依次取4,6,6,6,4,4。因此训练阶段一张输入image可以得到 38 ∗ 38 ∗ 4 + 19 ∗ 19 ∗ 6 + 10 ∗ 10 ∗ 6 + 5 ∗ 5 ∗ 6 + 3 ∗ 3 ∗ 4 + 1 ∗ 1 ∗ 4 = 8732 38*38*4+19*19*6+10*10*6+5*5*6+3*3*4+1*1*4=8732 38384+19196+10106+556+334+114=8732 个box,每一个box对应一个四元组位置信息loc,和一个c元组的置信度conf。

那么在网络中怎么通过特征图来得到loc和conf呢?这里我看大多教程里面都没有提及到。这里举第一个feature map,即 19 ∗ 19 ∗ 1024 19*19*1024 19191024的特征图为例。要生成loc四元组信息,只需要准备一个in_channel=1024,out_channel= 6 ∗ 4 6*4 64(6表示每一个cell对应6个box,上面设定好的;4表示位置信息四元组有4个参数)的卷积层。经过这样一个卷积层后, 19 ∗ 19 ∗ 1024 19*19*1024 19191024的特征图变为 19 ∗ 19 ∗ 6 ∗ 4 19*19*6*4 191964,此时你会发现, 19 ∗ 19 19*19 1919是cell的个数, 19 ∗ 19 ∗ 6 19*19*6 19196是这张特征图选出来box的数目,最后再乘的4就是位置信息四元组。conf与loc同理,只需要将卷积层的out_channel改为 6 ∗ c 6*c 6c即可。其他的特征图也都大同小异。

因此,SSD网络的输入是一张 300 ∗ 300 300*300 300300的图像,输出是8732个4元组位置loc和8732个c元组类别置信度conf。同时可以根据feature map的大小,长宽比例ratio以及cell所对应feature map中的位置,得到每个box在原图像上的位置信息,并将超过边界的部分裁减掉。

有了这个输出以后,就可以算损失函数,利用梯度下降调整模型参数了。

2. SSD的损失函数

SSD模型输出得到了8732个box,但是在训练中并没有使用这全部8732个box的信息。而是首先做了一个match操作,筛选出一部分box进行后续的训练。

筛选的原则是什么呢?对于正例的寻找:首先对于每一个ground truth,找出和他IoU最大的box作为正例。但是仅仅这样会导致正例很少而负例过多,因此还需要对和GT的IoU大于某个阈值的box,也将他们标注为正例。对于负例的选取:按照预测背景的置信度从大到小进行排序,排名高的box用来充当负例,负例的个数一般为正例的3倍,即hard negative mining。

值得注意的是,经过match以后得到的位置信息loc,已经不再是原来真正的位置,而是经过编码后的loc(思路与RCNN一致,篇幅所限不做展开了,如果真不理解也不用太在乎,就想象他还是位置信息就好)。所以GT的loc信息也是需要进行编码,这样box做回归才能保证坐标的一致性。

损失函数的样子如下:
在这里插入图片描述
可以看出损失函数包含两个部分:

第一项计算box在各个类别上的置信度,显然是一个分类问题。这里采用交叉熵损失函数,正例和负例均需要进行计算。

第二项是比较当前选定的正例box与GT之间的位置差异,是一个回归问题,目的是另正例box尽可能地与GT接近,最好达到重合。值得注意的是,为保证坐标的一致性,这里GT的loc也是通过编码后的loc,因此采用Smooth F1的损失函数衡量两个编码loc之间的差别。负例这里不做运算,因为没有GT与他对应。

经过交叉验证表明, α \alpha α取1的时候效果最好。

总结

关于SSD的训练过程大概就这样了,本人小白,难免有些疏漏和不妥之处,本文的目的就是想要从大体上拎出SSD的训练过程,可能细节方面有些没有那么详细。

关于SSD的训练,我认为就是将一张图像喂入网络,得到8732个box,每个box对应loc和conf。通过match原则对box进行筛选,选出1:3的正负例box,计算与GT的loss(分类和回归两部分),梯度下降调整参数即可。

SSD与yolo1相比,由于他的多尺度feature map的选取,在小目标的检测上有着较大的优势;相比于Faster RCNN这类two-stage算法,他的检测速度更快。

如有不妥之处或哪里讲得不清楚,还望交流指正。

  • 7
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值