ssd(Single Shot MultiBox Detector)解读之(一)原理解析

代码来源:https://github.com/amdegroot/ssd.pytorch

SSD简介:

ssd有ssd300和ssd512,一般我们都是用ssd300,意思是输入SSD网络的图片的尺寸是300x300的。

(一)SSD的网络结构:

SSD的网络结构绝不是简单的VGG16网络,如下图:

图1

它是由VGG16的网络改造而成的,具体步骤如下:

1.先把传统的VGG16网络去掉卷积层之后的池化层和全连接层,再加入2个卷积层:(使得得到的特征图是1024通道的)

图二

2.再在网络的最后加上额外的卷积层(extra_layers):

扫描二维码关注公众号,回复: 9513616 查看本文章

传统的VGG网络卷积后的特征图的通道数最大是512。而加上extra_layers后,就使得经过VGG卷积层后的特征图的通道数能达到1024。

那具体extra_layers加了哪些卷积层呢?如下图共加了额外的8个卷积层:

这样做的原因:

正常的VGG16 输入300x300的图片,最终输出的是512x19x19的特征图。而修改过的VGG16则可以输出1024x19x19的特征图。加上extra_layers之后,则最后输出256x1x1的特征图。图二的结构详细分解如下:

图三

3.回归框的卷积层和预测类别的卷积层。

上图三可以看出,特征图有6条横着的线

由SSD的网络结构可以看出,SSD使用6个不同特征图检测不同尺度的目标。低层预测小目标,高层预测大目标。如下图:

每条线都各自代表着2个卷积层,一个用来预测框的位置(中心坐标+长宽),另一个用来预测框的分类。

而每个特征图预测多少个框呢?首先要说明的 一点是,特征图的每个像素都要画k个框,至于k是多少,不同框的k值是不同的,当然这是人为设置的超参数,但是在ssd300里,是已经固定了的,六个特征图分别对应的k值是[4,6,6,6,4,4]。

可能有人要问了,为什么是用6个特征图来回归,分类呢?为什么不是3个4个?

作者在论文中通过实验验证了,采用多个特征图做检测能够大大提高检测精度,从上面的表格可以看出,采用6个特征图检测的时候,mAP为74.3%,如果只采用conv7做检测,mAP只有62.4%。

好了,那么一共预测多少个框呢?

从图一可以看出,六个特征图的大小分别是:38x38,19x19,10x10,5x5,3x3,1x1。每个特征图的k值是[4,6,6,6,4,4]。所以一共预测的框的数目是:

(38*38*4 + 19*19*6 +10*10*6+5*5*6 +3*3*4 + 1*1*4)= 8732。

之前说了,每条横线其实是对应着2个卷积层,一个是用来回归的(暂且叫他回归卷积层),一个是用来分类的(暂且叫分类卷积层)

我们看看这两个卷积层出来的特征图是什么样子的,以第一个特征图(尺寸为38x38)的为例:

回归卷积:

显而易见,38x38是特征图尺寸。而4x4是什么意思呢,第一个4是第一个特征图的K值,代表这个特征图每个像素要画4个框,第二个4是表示框的中心点坐标(x,y)和长宽(h,w)。因此没个像素对应16个值。

分类卷积:

(num_class是一个数据集的类别个数)

综上所言:SSD网络通过6个特征图各自进行回归卷积和分类卷积得到:

最后一步,就是各自把回归卷积图和分类卷积图都整个起来。但是问题来了,我们可以看到,由于他们的尺寸不一样(有的38x38,有的19x19)所以不能直接叠在一起,必须要做个处理。我们看到每个回归/分类出来的特征图是3维的(eg:38x38x16),有深度学习经验的朋友都知道,我们实际上送入网络训练的数据是四维的,因为还有一维是表示batchsize的,以第一个回归卷积 图为例,它维度应该是[1,16,38,38],我们把它转成[1,-1](-1其实16x38x38的值),那么四维的数据就变成两维的了,由于batchsize的位置都是1,是相同的,所以6个回归/分类卷积图可以直接叠加,把6个整合成一个。最后的回归卷积维度是[1,34928],最后的分类卷积维度是[1,num_class*8732]。有人可能问了,为什么回归卷积维度是[1,34928]呢,因为ssd一共会生成8732个框嘛,对于回归卷积,每个框有4个参数,用来确定框的位置,所以是8732x4 = 34928。

最后SSD在输出两个卷积特征时,再做了一次维度转换,例如[1,34928]的回归卷积转换成[1,8732,4]。这样就更直观了,8732表示框的总个数,4则是框的为位置信息个数。而分类卷积则是[1,8732,num_class]。综上所述SSD300网络输出的是维度为[1,8732,4]和[1,8732,num_class]的特征图。

(二)训练过程

我们知道SSD网络输出什么之后,有没有疑问,那这个输出是跟什么label一起送到损失函数里的呢?

我们看一张图:

这是一张训练数据的Ground True,里面有两个框,每个框有4个位置信息,那么这张图片的维度可以写成[1,2,4],咦,天啊~你ssd输出的边框回归信息维度已经是[1,8732,4]了,你边框个数对不上啊,你怎么进行训练啊。。。

所以,我们得出一个结论:label的Ground True并非真正输入损失函数的label。

那真正与ssd的输出一起输入损失函数的label是什么呢?我们一步步来看。。。

1. default box(也叫先验框priors)

default box就是所谓在特征图上画的框,在六个特征图上画框,一共画8732个框。特征图的每个像素画4或6个框(取决于是哪个特征图):

画框是在六个特征图框上画的,但是我们画的框最终目的是要和数据集Ground True中的框作匹配的,那在六个特征图上的画是怎么映射到原图大小的Ground True上呢?

在各个特征图上画的框,一定会做一个归一化,即长宽除以当前特征图的长宽,框的中心点也会除特征图的边长。到时候归一化后的框大小 只要乘原图的长宽,就得到该特征图上的框在原图上的映射。因此~在越大的特征图上画的框映射在原图上就越小,在越小的特征图上画的框映射在原图上就越大。这样做的好处是比较大的特征图来用来检测相对较小的目标,而小的特征图负责检测大目标。

六个特征图,各个特征图的每个像素点画的框数是[4,6,6,6,4,4],即第一个特征图每个像素画4个框,第二个特征图每个像素画6个框,如此类推。

那default box的大小尺度怎么确定呢?这里论文里有公式说明计算方式,但是代码里就直接以参数的形式写出来。这里就讲讲论文里是怎么推default box的大小尺度吧。

=====选看,因为代码中并没有计算过程,是直接使用结果作为参数============================================

要确定框的大小尺寸,首先要确定两个参数,一个是min_size,一个是max_size,框的长宽都由这两个参数组成。

min_size = 300 * Sk (300是图片输入的尺寸)

在论文中,计算Sk的公式如下:

S_min = 0.2,S_max = 0.88m=5(因为有6个特征图,而第一个特征图的min_size作者指定为30),就可以算出[60, 111, 162, 213, 264],至于30和315应该是作者自己设置的。

所以,可以得到,六个特征图的min_size 和 max_size如下:

可以看到 max_size就是min_size下一个元素,所以只要计算出min_size,max_size也出来了。max_size的最后一个值是315,是额外加上去的。

==================================================================

有了min_size 和 max_size,我们还需要长宽比,一般选取长宽比为:

宽:

高:

在这种情况下,特征图每个像素理论上来说都会有5个框(因为a_r有5个元素),每个特征图会有一个a_r = 1且尺度为s_k的先验框,除此之外,还会额外设置一个尺度为:

且 a_r=1的先验框。这样每个特征图都设置了两个长宽比为1但大小不同的正方形先验框。所以理论上特征图每个像素理论上来说都会有6个框。但在实现时,SSD的Conv4_3,Conv10_2和Conv11_2层仅使用4个先验框,它们不使用长宽比为3,1/3 的先验框。由于每个框会有中心坐标(2个值)和长宽(2个值)所以,SSD300一共要画

个边界框,那既然画出的框的值共是8732个,自然网络预测时,也要预测8732个值。

2.为什么要画框?(即为什么要有default box)

首先要明白一个叫感受野的概念:

影响某个神经元输出的输入区域就是理论感受野,也就是我们平时说的感受野,但该输入区域的每个像素点对输出的重要性不同,越靠近中心的像素点影响越大,呈高斯分布,也就是说只有中间的一小部分区域对最后的输出有重要的影响,这个中间的一小部分区域就是有效感受野

下图中:

左边黑色的区域就是理论感受野,中间呈高斯分布的白色点云区域就是有效感受野。

右边内红色圈部分对应着有效感受野,我们的default box最好能匹配到有效感受野。

SSD在6个特征图上使用2组3x3的卷积核分别做分类和boundingbox回归。我们知道每个特征图上每个像素点对应一个理论感受野,所以SSD相当于对原图中所有的理论感受野作分类和回归,由于有效感受野在理论感受野中有重要的影响,其他区域的影响可以忽略,所以这里我们认为SSD是对有效感受野作分类和回归,那么问题来了,既然是对所有的有效感受野做分类和回归,那每个有效感受野的分类的label和回归的label是如何确定的呢?default box就是用来干这个的。
简单来说就是:

K层的特征图的上的一个像素,对应着其前一层的特征图的多个像素,这就是感受野:

(红色框为Ground True框)

按照SSD的做法,画出来的8732个框,全部都要有对应的一个GroundTrue框。

(1).这个过程叫 match

把8732个框都要对应一个GroundTrue框

(2).encode:

接着就到encode过程,作用:

(对回归值的处理):

是算出default box 和这个default box对应的GroundTrue框的偏置值(offset)。偏置值包括default box的中心坐标和GroundTrue框的中心坐标的偏置值,和default box边长和GroundTrue框的边长的偏置值。得到的偏置值再与网络的输出(预测回归值)送入smooth_L1_loss函数,得到回归损失值loss_l。所以 SSD网络输出的回归值是偏置值(SSD网络 一共输出5个值,4个是回归值,一个是类别值),真正检测时,SSD的输出需要通过decode生成归一化的边框值,再乘图片的长和宽,才会形成图片的边框值。

(对分类置信度的处理):

把与GroundTrue框的IOU阈值少于0.5的default box的label设置成背景类(即0)。用conf_t来记录8732个框的类别。

(3)硬负挖掘法Hard Negative Mining(用来定义正样本和负样本的 一种方法):

把与GroundTrue框的IOU大于阈值(0.5)的default box作为正样本,把少于阈值的作为负样本。由于正样本与负样本比,正样本太少了(因为大部分default box都碰不到GroundTrue框的),会造成数据的不平衡,进而影响检测的精度。所以Hard Negative Mining规定正样本:负样本=1:3。(设正样本数为n)。所以在负样本中,挑选(对背景)损失大的3n个负样本作为真正的负样本。

得到正样本和负样本后,以序号为框的标识,再conf_t中抽出这些样本对应的类别作为 分类损失函数cross_entropy的label。再从SSD网络出来的类别值中,找出对应框序号的类别值,作为分类损失函数cross_entropy的预测输入,最后就可以得到分类损失值loss_c。两个损失值相加,就得到这次训练的损失值loss = loss_l + loss_c。

总结 一下:

1.SSD网络不是直接输出预测框的准确值,而是输出一个相对于default box的偏置值(也可以叫变化值),用default box结合这个偏置值才是最终预测框的值,当然最后要乘上输入图片的边长,才能把这个框映射到输入图片上去。

2.其实SSD主干网络并不复杂,复杂的是他的损失函数Multibox_loss的设计。

3.SSD的一个缺点就是 default的画法,例如default box 的长宽比不能通过学习所得,要按照不同数据集的特性人工设定不同的长宽比。

4.SSD虽然是用了多尺度的方法,但是对小物体的检测效果依旧不好。

5.可能有人问,为什么要画default box框,为什么不同直接输入 Ground True上的框作为label来训练预测框的时?因为这样做的话,训练数据量不够。SSD不仅要输出边框的回归值,还要输出边框的类别值,不仅输出数据多,而且还是多分类问题,但靠一张图的几个Ground True边框是很难的。

发布了270 篇原创文章 · 获赞 408 · 访问量 76万+

猜你喜欢

转载自blog.csdn.net/u014453898/article/details/102534578