目标检测算法——SSD:Single Shot MultiBox Detector,是一篇非常经典的目标检测算法,十分值得阅读和进行代码复现,其论文地址是:https://arxiv.org/abs/1512.02325


一、前言

1.1 什么是SSD

从论文的题目《SSD:Single Shot MultiBox Detector》可以看出,single shot表明是one_stage检测算法,即不需要类似faster R-CNN中的RPN等区域推荐算法,一步就能得到预测坐标和类别,实现真正的end-to-end训练;multibox表示是多框预测,即SSD算法借鉴了faster R-CNN中的锚点框思想,对每个先验锚点框进行预测,判断其类别和目标的预测框。

1.2 为什么提出SSD

在SSD算法提出之前,R-CNN系列的目标检测算法,其准确率很高,但是这些算法需要消耗大量计算资源,特别是对于嵌入式设备或者终端设备,其算力无法满足此类算法,造成了无法进行实时目标检测。

目标检测的检测速度通常使用FPS进行衡量,即1秒能处理多少帧。Faster R-CNN的检测速度只有7FPS,虽然已经比以前的算法快很多了,但远远还达不到实时检测的效果。虽然后续对faster R-CNN做了很多改进来提高FPS,但这些增益都是以牺牲大量精度为前提。

因此,急需一种速度快且精度不低的目标检测算法。

1.3 如何平衡速度与精度

如下图所示,下图是R-CNN系列,YOLO和SSD的性能对比图(Ref.《目标检测算法之SSD》),可以看出SSD在速度和mAP上都有较大的提升。

那么,SSD能实现速度与精度的平衡,是通过以下方式来实现的:

a) 改变网络结构,并使用多尺度融合;

b) 精心设计先验锚点框,和锚点框匹配策略;

c) 使用多个tricks来提高精度,如用于平衡正负样本数量的难例挖掘(hard negative mining)和数据增强。


二、网络结构

如图1所示,是SSD的网络结构。在论文中,图片的输入尺寸为300*300*3,使用VGG16作为主干网络,同时,做出了以下修改:

  1. 将原本VGG16的FC6和FC7换成卷积层Conv6和Conv7,并依次加入新的层:Conv8_2,Conv9_2,Conv10_2,Conv11_2。具体而言,在Conv7层的特征图为19*19*1024,经过1*1*256和3*3*512-s2的卷积操作后,得到Conv8_2的特征图,其尺寸为10*10*512,依次类推。
  2. 为了实现多尺度融合,需要将不同层的特征图提取出来进行判断。在论文中,作者使用Conv4_3、Conv7、Conv8_2、Conv9_2、Conv10_2和Conv11_2的特征图来进行多尺度融合。如图2所示,每层特征图会分别经过3*3的卷积,得到2个tensor,分别用于进行坐标预测和类别置信度预测。其中,用于坐标预测的通道数是(num_anchor*4),num_anchor表示该特征图每个位置对应的锚点框数量,4表示(x_min,y_min,x_max,y_max);用于类别置信度预测的通道数是(num_anchor*num_classes),num_classes表示类别的数量(包含背景),对于VOC来说,num_classes=21,20个类别加上1个背景。另外,论文中会对Conv4_3层的特征图使用L2归一化后,再进行3*3的卷积,这样做的目的是,防止此层特征图的值过大,利于收敛。

对于需要融合的特征图,假设此特征图的尺寸是w*h,那么,对于每个位置(x,y),会预先生成N个锚点框(具体锚点框的细节,下面会叙述),因此,每张特征图会生成w*h*N个锚点框。SSD通过对每个锚点框进行位置回归和类别预测,并通过NMS非极大值抑制得到最终的检测结果。

SSD算法会生成一系列预测框(bounding boxes)和每个预测框的得分,然后通过NMS非极大值抑制得到最终的检测结果。如下图所示,是SSD的网络结构。

图1 SSD的网络结构

图2 特征图的处理

三、锚点框

SSD的锚点框借鉴了faster R-CNN的锚点框思想,但不同的是,在SSD中,每个特征图对应的锚点框均不相同,即锚点框会根据特征图的尺寸发生变化。例如,Conv4_3的锚点框和Conv7的锚点框的尺寸是不一样的。假定使用m张特征图进行预测判断,每张特征图的锚点框大小,可以通过下式进行计算:

$$s_k=s_{min}+\frac{s_{max}-s_{min}}{m-1}(k-1),k\in [1,m]$$

其中,$s_{min}=0.2$和$s_{max}=0.9$,表示Conv4_3特征图的锚点框的尺寸为0.2,Conv11_2特征图的锚点框尺寸为0.9。既然有了锚点框的大小,可以理解为面积,接下来就需要为锚点框设置不同的宽高比。作者设置了5种宽高比,分别是$a_r={1,2,3,1/2,1/3}$,因此,可以计算得到宽度$w_k^a=s_k\sqrt{a_r}$,高度为$h_k^a=s_k/\sqrt{a_r}$。对于宽高比为1的情况,额外增加一个锚点框,其尺寸为${s_k}'=\sqrt{s_ks_{k+1}}$。所以,一般而言,第i层特征图的(x,y)位置,具有6个锚点框。而第一层特征图和最后两层层特征图,每个位置只设置4个锚点框。因此,图1中的8732个锚点框是这样计算得到的,$38*38*4+19*19*6+10*10*6+5*5*6+3*3*4+1*1*4=8732$。

通过对不同特征图设置不同的锚点框,有利于检测不同尺寸的物体,大特征图可检测小物体,小特征图可以检测大物体。如图3所示,(a)表示带GT框的图像;(b)表示在8*8的特征图中,每个位置使用6个不同尺寸的锚点框,当某个锚点框与GT框的IOU大于阈值时,将其设置成正样本,该位置下其他锚点框为负样本;(c)表示4*4特征图下,红色虚线框用于预测狗的情况,会输出loc和conf两个tensor,loc表示相对于锚点框的偏移量,conf表示每个类别的置信度。

图3 锚点框匹配

当设定了锚点框后,就需要制定其匹配规则,即制定哪些锚点框用于回归GT框和预测类别。首先,为每个GT框匹配一个与其IOU最高的先验锚点框,保证了每个GT框都有对应的锚点框,来预测GT框;其次,当GT框与先验锚点框的IOU大于阈值(0.5)时,也指定该锚点框用来预测该GT框。当然,若锚点框A与多个GT框的IOU都大于阈值,则该锚点框A选择与其IOU最大的GT框。

图4是锚点框与GT框的匹配示意图,为了方便理解,将锚点框映射回原图尺寸,与GT框进行匹配。

图4 锚点框与GT框的匹配

四、其余策略

  • SSD的损失函数继承了R-CNN系列的损失函数,如下所示,由位置损失和置信度损失组成,位置损失使用了smooth1,置信度损失使用多类别交叉熵:

$$L(x,c,l,g)=\frac{1}{N}(L_{conf}(x,c)+\alpha L_{loc}(x,l,g))L(x,c,l,g)=\frac{1}{N}(L_{conf}(x,c)+\alpha L_{loc}(x,l,g))$$

  • 此外,SSD可以理解成对图片进行密集采样,得到8732个patch,然后对这些patch进行预测和回归。因此,会发现,大部分锚点框都会匹配上背景,也就是被设置成负样本。因此,会造成正负样本之间的不平衡。对于此情况,SSD使用了hard negative mining策略来缓解这一锚段。在SSD中,并没有使用所有的负样本,而是将这些匹配上背景的样本根据置信度损失进行降序排列,取出置信度损失进行排序,将损失较大的样本认为是难例(hard negative),需要模型重点学习。选取损失最大的前N个样本作为负样本,正样本与负样本的比例控制在1:3左右,对于那些没有选上的样本,label设置成-1,不参与训练当中。
  • 为了扩大感受野,加快推理速度,还使用了空洞卷积。
  • SSD中还采用了数据增强的策略,如对原图进行色域变换、扩增、采样的操作,具体可以参考这篇文章。

五、实验结果

(1)VOC测试结果

下表是SSD在VOC的实验结果图。与Fast R-CNN和Faster R-CNN进行对比,分别使用了300*300和 512*512的图片作为输入。在07+12+COCO数据集上来看,SSD300比Faster R-CNN的mAP提高了0.8%,SSD512提高了2.8%。此外,SSD的定位误差更小,因为SSD是直接回归目标的形状和进行分类,将定位和分类合成了一步。但是,对于相似目标,SSD容易产生混淆,可能是因为对不同种类的目标共享了位置。SSD还容易预测框尺寸的干扰,即在小目标上其性能比大目标要差。作者认为这可能是由于在浅层的时候,小目标物体包含的信息不多。当增加了分辨率的时候,这种情况得到了较好的改善。

(2)模型分析

为了了解SSD中各组成对结果的影响程度,作者使用SSD300进行了控制变量实验,结果如下图所示。

  • 数据增强:在R-CNN系列中,采用的是原图或者对原图进行翻转等变换。而SSD中,使用了更多的策略,包括扩增、采样等。可以看出,使用数据增强的SSD,mAP提高了8.8%。但作者认为,同样的数据增强策略,对R-CNN系列可能会失效,因为在进入分类头的时候,使用了特征池化。
  • 锚点框的多样性:在SSD中,对特征图的每个位置使用了6个不同形状的锚点框,每层特征图的锚点框也均不一致。当移除锚点框后,mAP都出现了不同比例的下降。使用不同尺寸的锚点框,使网络能更加简单对锚点框进行回归。但是不是锚点框越多越好呢?锚点框越多,推理速度也就越慢。这中间应该会有折中。
  • 空洞卷积:在本实验中,使用的是带空洞卷积版本的VGG16。如果使用完全版本的VGG16,即保留pool5和对fc6/fc7不使用下采样,增加conv5_3进行特征融合。这样的话,能得到相同精度的结果,但速度却慢了20%。
  • 多尺度融合:SSD的主要贡献在于在不同分辨率的特征层中使用了不同尺寸的锚点框,进行多尺度融合。为了比较这一做法的影响,作者去除某些用于特征融合的层,实验的结果如下表所示。为了保证一致性,锚点框的数量保持接近8732。可以看出,当特征层越来越少的时候,mAP也会随之下降,从74.3下降到62.4。

(3)推理时间

下表是SSD的推理时间对比图。可以看出,SSD中精度和速度上做到了比较好的平衡。


SSD是一种很优秀的one-stage框架,对后面很多目标检测算法有着深远的影响。读完论文,发现还是对SSD的了解不够深入,接下来,会对其源码进行分析。

SSD学习笔记的更多相关文章

  1. 深度学习笔记(十三)YOLO V3 (Tensorflow)

    [代码剖析]   推荐阅读! SSD 学习笔记 之前看了一遍 YOLO V3 的论文,写的挺有意思的,尴尬的是,我这鱼的记忆,看完就忘了  于是只能借助于代码,再看一遍细节了. 源码目录总览 tens ...

  2. 深度学习笔记(七)SSD 论文阅读笔记简化

    一. 算法概述 本文提出的SSD算法是一种直接预测目标类别和bounding box的多目标检测算法.与faster rcnn相比,该算法没有生成 proposal 的过程,这就极大提高了检测速度.针 ...

  3. 深度学习笔记(七)SSD 论文阅读笔记

    一. 算法概述 本文提出的SSD算法是一种直接预测目标类别和bounding box的多目标检测算法.与faster rcnn相比,该算法没有生成 proposal 的过程,这就极大提高了检测速度.针 ...

  4. [学习笔记] SSD代码笔记 + EifficientNet backbone 练习

    SSD代码笔记 + EifficientNet backbone 练习 ssd代码完全ok了,然后用最近性能和速度都非常牛的Eifficient Net做backbone设计了自己的TinySSD网络 ...

  5. Java学习笔记(04)

    Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...

  6. 学习笔记:The Log(我所读过的最好的一篇分布式技术文章)

    前言 这是一篇学习笔记. 学习的材料来自Jay Kreps的一篇讲Log的博文. 原文很长,但是我坚持看完了,收获颇多,也深深为Jay哥的技术能力.架构能力和对于分布式系统的理解之深刻所折服.同时也因 ...

  7. Oracle User Management FAQ翻译及学习笔记

    转载 最近了解到AME 的东西,很迫切,先转载一篇 [@more@] Oracle User Management FAQ翻译及学习笔记 写在前面 本文主要是翻译的英文版的Oracle User Ma ...

  8. 学习笔记:The Log(我所读过的最好的一篇分布式技术文章)

    前言 这是一篇学习笔记. 学习的材料来自Jay Kreps的一篇讲Log的博文. 原文非常长.可是我坚持看完了,收获颇多,也深深为Jay哥的技术能力.架构能力和对于分布式系统的理解之深刻所折服.同一时 ...

  9. OpenCV 学习笔记 07 目标检测与识别

    目标检测与识别是计算机视觉中最常见的挑战之一.属于高级主题. 本章节将扩展目标检测的概念,首先探讨人脸识别技术,然后将该技术应用到显示生活中的各种目标检测. 1 目标检测与识别技术 为了与OpenCV ...

随机推荐

  1. Linux 通道

    简单地说,一个通道接受一个工具软件的输出,然后把那个输出输入到其它工具软件.使用UNIX/Linux的词汇,这个通道接受了一个过程的标准输出,并把这个标准的输出作为另一个过程的标准输入.如果你没有重新 ...

  2. easy dragging script

    下面的ahk脚本提供了windows下alt dragging的能力: ; Easy Window Dragging -- KDE style (requires XP/2k/NT) -- by Jo ...

  3. 从Docker在Linux和Windows下的区别简单理解Docker的层次结构

    上篇文章我们成功在Windows下安装了Docker,输出了一个简单的Hello World程序.本文中我们将利用Docker已有的云端镜像training/webapp来发布一个简单Python的W ...

  4. openstack核心组件--keystone(1)

    一.keystone介绍 keystone 是OpenStack的组件之一,用于为OpenStack家族中的其它组件成员提供统一的认证服务,包括身份验证.令牌的发放和校验.服务列表.用户权限的定义等等 ...

  5. Spring学习之==>入门知识

    一.Spring是什么? Spring 是一种轻量级的.非侵入式的 Java/JavaEE 应用框架.Spring 使用的是基本的 JavaBean 来完成以前只可能由EJB完成的事情.然而,Spri ...

  6. IDEA下启动tomcat非常慢

    笔者遇到的原因是在setclasspath.bat里面添加了参数 set JAVA_OPTS="-XX:-UseSplitVerifier -noverify -Djava.net.pref ...

  7. MySQL使用order by field()自定义排序

    MySQL的自定义排序和Oracle相比,要简单得多. 假设在表v_education的列schoolRecord中,有以下字段:'小学','初中','高中','专科','本科','硕士','博士'. ...

  8. 使用gRPC打造服务间通信基础设施

    一.什么是RPC rpc(远程过程调用)是一个古老而新颖的名词,他几乎与http协议同时或更早诞生,也是互联网数据传输过程中非常重要的传输机制. 利用这种传输机制,不同进程(或服务)间像调用本地进程中 ...

  9. 直方图匹配原理与python、matlab实现

    直方图匹配本质上是让两幅图像的累积直方图尽量相似,累积直方图相似了,直方图也就相似了. 把原图像img的直方图匹配到参考图像ref的直方图,包括以下几个步骤: 1. 求出原图像img的累积直方图img ...

  10. flask 之(三) --- 筛选|分页|过滤

    筛选 查询数据筛选语法:类名.query.筛选符 .all( ):获取结果集:.count( ):获取查询到的对象数量 类名.query.filter(类名.属性.运算符('xxx')).all() ...