目标检测算法(2)SPP-net
本文是使用深度学习进行目标检测系列的第二篇,主要介绍SPP-net:Spatial Pyramid Pooling in Deep ConvolutionalNetworks for Visual Recognition,即空间金字塔池化网络,用以解决卷积神经网络中固定输入大小的问题。
一、算法动机及尝试解决的问题
1. 传统的卷积神经网络的输入通常是一个固定大小(比如\(224x224\)的图像,因此当我们任意输入一张图像时需要对其进行缩放,作者认为这种手动的缩放可能会降低识别精度;
2. 在目标识别方面,使用深度神经网络对每个候选区域(如RCNN)抽取特征的时候,都需要重复的丢进网络里,即每来一个候选区域都进行warp(上文中RCNN用的方法,可以看成对候选区域进行缩放)操作得到相同的输入,放进CNN里抽取新的特征,这样导致计算量非常大:对于一张原始图像的候选区域有接近2000个,无疑开销很大。
3. 作者认为在卷积神经网络中卷积层并不需要固定大小的输入,而在全连接阶段需要保证输入具有固定的大小。这一点比较比较好理解,因为卷积层仅仅对图像进行局部连接,不管输入怎么能进行卷积操作,只是让特征图输出的大小和输入有关系;但是全连接层就不一样了,如果输入大小不固定肯定会出现矩阵维数不匹配的情况。

图1 传统的“crop”和“warp”方法与SPP的做法进行对比
为了展示卷积滤波器对于不同尺寸图像的作用情况,作者做了一个实验,使用AlexNet可视化第五个卷积层中某些滤波器得到的特征图的语义特征,如图2所示,图中(a)是Pascal VOC2007中的两张图像,(b)是某些滤波器得到的特征图,蓝色的箭头表示特征图中激活值比较强烈的区域以及对应的原始图像中的区域;(c)是使用相同的滤波器在ImageNet的图像中的响应情况,绿色框表示滤波器强烈的区域对应的感受野,这里的实验并没有输入同样大小的图像尺寸,但是可以看出这些滤波器依然能够反映出语义内容,比如左图的两个滤波器分别对车窗上方或者类似的区域、车胎附近圆形的或者类似的区域有强烈的反应;右图则对衣服的腋下或者类似的区域、盒子拐角处或者类似的区域有强烈的反应。

图2 特征图可视化
基于以上几点,作者设计了一个SPP层从最后的卷积层中提取特征,并统一处理大小使其适配全连接层的输入。
二、SPP具体做法
1.Spatial Pyramid Pooling层
如第一部分所说,CNN中卷积层能够接受任意尺寸大小的输入,但是全连接层不可以,因此作者提出在CNN的最后一个卷积层后接入一个SPP(Spatial Pyramid Pooling)层代替我们平常使用的Max pooling层,SPP最主要的作用是接受任意尺寸的特征图,然后把特征图的像素按比例转化为一些固定数量的bin(可以),然后在这些bins里面进行池化。具体可以参见图3:

图3 SPP层示意
从图中可以发现,SPP用了三种不同方式来进行pooling,即对每张输入的特征图分别分成16个bins、4个bins和1个bins,然后再对每个bin里做池化,把这三种池化后的特征组合在一起就拼接成了一个新向量。有意思的是这里的1个bins恰好是某些paper中提到的“global pooling”层,能够起到降维、防止过拟合、提升精度等等作用。SPP层进行多尺度提取特征的方式其实借鉴了一些传统,比如SIFT;同时SPP本身也借鉴了BOW(Bag of Words,图像词袋模型)、SPM(Spatial Pyramid Matching)方法,这些其实很多多年前使用到的传统的特征提取或者匹配方法。
2.SPP用于目标检测
原始的RCNN进行检测时间开销的最大瓶颈在于特征提取阶段:对selective search抽取的约2000个候选框都需要重复的丢进整个网络;相比较而言,SPP对于整张图像在特征抽取阶段只需要做一次,即完整的图像先丢进网络,然后在特征图层面对selective search选取的候选区域使用SPP层进行池化,获取固定大小的维数,然后再进行全连接的计算,如图4所示,需要注意的是图4和图3非常像,实际上作者同时介绍了SPP在分类和目标检测中的应用,图3的示意更适用于分类,即对整张图像进行SPP池化获取统一的输出维度丢进全连接层;而图4更适用于目标检测,即在特征图层面对某个候选区域进行SPP池化,也就是图中的这个“window”。

图4 SPP层用于目标检测示意
可以看出SPP进行目标检测时需要进行原始图像中候选区域的位置和特征图中候选区域位置的一个映射关系。为简化计算过程,简单来说,对于某一层大小为\(p\)的滤波器,进行\(\left \lfloor \frac{p}{2} \right \rfloor\)(符号的意思是进行向下取整)的填充,那么对于特征图中响应中心坐标\((x{}',y{}')\),其对应原始图像中的坐标\((x,y)=(Sx{}',Sy{}')\),其中\(S\)为前面那些层的stride步伐的乘积。而对于给定的图像中的区域,获取特征图响应的左上角坐标为\(x{}'=\left \lfloor \frac{x}{s} \right \rfloor+1\),右下角坐标为\(x{}'=\left \lceil \frac{x}{s} \right \rceil-1\),而在padding不是\(\left \lfloor \frac{p}{2} \right \rfloor\)的情况下需要添加关于\(x\)的偏移量。
3.SPP用于目标检测的具体过程
SPP在基于RCNN的基础上改进进行目标检测,具体如下:
(1)使用“fast”模式的selective search对每张图像生成2000左右的候选区域;
(2)对每个候选区域利用SPP进行4个级别bins的池化,分别是\(1\times1\)、\(2\times2\)、\(3\times3\)及\(6\times6\)的总共50个bins进行池化,如此对于最后一个特征图的256个卷积核可以得到\(256\times50\)的特征表示;
(3)把第二步中得到的特征接到全连接层中,然后对全连接层的输出使用二分类的SVM进行分类。
在训练SVM过程中,SVM的正类样本是真实的物体,而负类样本定义为和正类样本的IOU比最高不超过30%并且和其他的负类不超过70%的样本,和RCNN类似,SPP也选择使用hard negative mining模式的SVM进行训练,整个用于20个类训练SVM的时间小于1个小时;在测试阶段使用训练好的SVM为候选区域打分,最后使用阈值为0.3的NMS进行过滤。
3.网络训练
在训练网络的过程中,分为前面的特征图的预训练和后接入的全连接层的微调,对于预训练部分作者提到了使用多尺度输入的训练方法,即resize原始图像成为不同尺度的输入\(min(w,h)=s\inS={480,576,688,864,1200}\),然后得到第五个卷积层的特征图,接着进行特征融合再进行SPP池化;另外一种更好的方式是选择候选区域大小最接近\(240\times240\)的那张图像进行输入并进行SPP提取特征。
为简化训练过程,微调仅针对全连接层。在第五个卷积层之后接入两个全连接层,最后再接入一个全连接层进行分类,类别数为21,即20+1,1是背景;对于最后一个全连接层使用标准差为0.01的高斯分布初始化参数,学习率由\(1e-4\)浮动到\(1e-5\);在微调阶段的正类样本定义为那些和真实的目标区域IOU比为\([0.5,1)\)的样本,负类为\([0.1,0.5)\)的样本,在每轮的mini-batch包含25%的正类样本;最后类似于RCNN也使用了bounding box回归进行偏差修正。最后作者给出了在VOC2007上的实验结果,如图5所示,其中sc表示作者使用的多尺度的训练方式,下图是作者在SPP的预训练模型上进行训练得到的结果(即作者先使用了SPP进行分类,然后拿分类的网络模型来进行检测微调)。可以看出SPP相比较RCNN最大的特点是训练速度的巨大提升。


图5 VOC上SPP和RCNN实验比较
另外作者还针对试验中的其他对比方法进行了时间复杂度的分析,这里不再细说,参见原始paper。
三、总结
SPP用于目标检测实际是在RCNN的基础上进行改进的,可以看出主要的目的是在时间上的巨大提升,但是从本质来看算法的精度并没有什么提升。需要注意的是SPP同样可以用于分类,作者花了很大篇幅讨论分类的SPP方法,考虑到本文是目标检测系列所以没有介绍到,下一篇主要介绍一个比较大的改进方法fast-rcnn。
目标检测算法(2)SPP-net的更多相关文章
- 深度学习笔记之目标检测算法系列(包括RCNN、Fast RCNN、Faster RCNN和SSD)
不多说,直接上干货! 本文一系列目标检测算法:RCNN, Fast RCNN, Faster RCNN代表当下目标检测的前沿水平,在github都给出了基于Caffe的源码. • RCNN RCN ...
- (四)目标检测算法之Fast R-CNN
系列博客链接: (一)目标检测概述 https://www.cnblogs.com/kongweisi/p/10894415.html (二)目标检测算法之R-CNN https://www.cnbl ...
- (三)目标检测算法之SPPNet
今天准备再更新一篇博客,加油呀~~~ 系列博客链接: (一)目标检测概述 https://www.cnblogs.com/kongweisi/p/10894415.html (二)目标检测算法之R-C ...
- 基于模糊Choquet积分的目标检测算法
本文根据论文:Fuzzy Integral for Moving Object Detection-FUZZ-IEEE_2008的内容及自己的理解而成,如果想了解更多细节,请参考原文.在背景建模中,我 ...
- 目标检测算法YOLO算法介绍
YOLO算法(You Only Look Once) 比如你输入图像是100x100,然后在图像上放一个网络,为了方便讲述,此处使用3x3网格,实际实现时会用更精细的网格(如19x19).基本思想是, ...
- FAIR开源Detectron:整合全部顶尖目标检测算法
昨天,Facebook AI 研究院(FAIR)开源了 Detectron,业内最佳水平的目标检测平台. 昨天,Facebook AI 研究院(FAIR)开源了 Detectron,业内最佳水平的目标 ...
- AI SSD目标检测算法
Single Shot multibox Detector,简称SSD,是一种目标检测算法. Single Shot意味着SSD属于one stage方法,multibox表示多框预测. CNN 多尺 ...
- 第二十九节,目标检测算法之R-CNN算法详解
Girshick, Ross, et al. “Rich feature hierarchies for accurate object detection and semantic segmenta ...
- 目标检测算法之R-CNN算法详解
R-CNN全称为Region-CNN,它可以说是第一个成功地将深度学习应用到目标检测上的算法.后面提到的Fast R-CNN.Faster R-CNN全部都是建立在R-CNN的基础上的. 传统目标检测 ...
- 目标检测算法SSD之训练自己的数据集
目标检测算法SSD之训练自己的数据集 prerequesties 预备知识/前提条件 下载和配置了最新SSD代码 git clone https://github.com/weiliu89/caffe ...
随机推荐
- Struts2各个功能详解(2)-输入校验和拦截器
前面知道了struts2的架构图和struts2的自动封装表单参数和数据类型自动转换,今天来学struts2的第三第四个东西,输入校验和拦截器. 一:输入校验 客户端校验进行基本校验,如检验非空字段 ...
- 手把手教学在Springboot中搭建使用Guava cache,包教包会,不会我输一包辣条给你
guava cache使用简介 概述 缓存是日常开发中经常应用到的一种技术手段,合理的利用缓存可以极大的改善应用程序的性能. Guava官方对Cache的描述连接 缓存在各种各样的用例中非常有用.例 ...
- docker run 与docker start的区别
docker run相当于执行了两步操作:将镜像放入容器中(docker create),然后将容器启动,使之变成运行时容器(docker start). 而docker start的作用是,重新启动 ...
- python3 requestsGET请求传参
GET方式传参方式一: import requests url = 'http://www.baidu.com/s?page=2' # 使用?携带参数 r = requests.get(url) pr ...
- js如何实现重载
所谓重载,就是一组相同的函数名,有不同个数的参数,在使用时调用一个函数名,传入不同参数,根据你的参数个数,来决定使用不同的函数!但是我们知道js中是没有重载的,因为后定义的函数会覆盖前面的同名函数,但 ...
- 递归,re,time,random
递归函数 1.在函数中调用自己 2.超过递归的最大深度报错,递归的最大深度:998大概 3.递归的缺点:占内存 4.优点:代码简单 import sys sys.setrecursionlimit(2 ...
- nuget安装本地nupkg文件
打开visual studio,菜单选择‘工具’->‘选项’ 然后 接下来,选择‘程序包源’,把‘包括预发行版’打钩,然后安装需要的包到工程即可,如下图:
- 【aardio】是否取消三个按键的对话框
import win; var id = win.msgbox("三个按钮","标题",0x3/*_MB_YESNOCANCEL*/) 参考标准库函数: nam ...
- Eclipse 中 Maven 项目默认JDK版本为1.5 的解决方法
在 Eclipse 中 Maven project 的默认 JDK 版本是 1.5, 如果不在 settings.xml 或者 pom.xml 中显示的指出 JDK 版本,每次 右键项目--> ...
- python3 第二十九章 - 内置函数之tuple相关
Python元组包含了以下内置函数 序号 方法及描述 实例 1 len(tuple)计算元组元素个数. >>> tuple1 = ('Google', 'Baidu', 'Taoba ...