艾巴生活网

您现在的位置是:主页>科技 >内容

科技

SDF算法_详细讲解SDD算法的原理

2023-10-25 20:32:02科技帅气的蚂蚁
序近年来,目标检测取得了重要进展。主流算法主要分为两种(参考精炼ET): (1)两阶段法,如R-CNN算法,其主要思想是通过选择性搜索或CNN网络

SDF算法_详细讲解SDD算法的原理

近年来,目标检测取得了重要进展。主流算法主要分为两种(参考精炼ET): (1)两阶段法,如R-CNN算法,其主要思想是通过选择性搜索或CNN网络(RPN)生成一系列稀疏候选帧,然后对这些候选帧进行分类回归。两步法的优点是精度高;(2)一阶段法,如Yolo和SSD,主要是在图片的不同位置,用不同的尺度和长宽比进行均匀采样,然后用CNN提取特征,直接分类回归。整个过程只需要一步,所以它的优点是速度快,但是均匀密集采样的一个重要缺点是很难训练,主要是因为正样本和负样本(背景)极度不平衡(见Focal)不同算法的性能如图1所示,我们可以看到两种方法在精度和速度上的差异。

图1不同检测算法的性能比较

本文对SSD算法进行了阐述。它的全英文名字叫Single shot MultiBox Detector,名字不错。单拍表示SSD算法属于一阶段法,多框表示SSD是多帧预测。在上一篇文章中,我们已经谈到了Yolo算法。从图1可以看出,SSD算法在精度和速度上都比Yolo好很多(SSD512除外)。图2显示了不同算法的基本框架图。对于更快的R-CNN,先通过CNN获取候选帧,然后进行分类回归,而Yolo和SSD可以一步完成检测。相比Yolo,SSD采用CNN直接检测,而不是像Yolo那样全连接层后检测。其实用卷积直接检测只是SSD和Yolo的区别之一,还有另外两个重要的变化。首先,SSD提取不同尺度的特征图进行检测,大尺度特征图(正面特征图)可用于检测小物体,小尺度特征图(背面特征图)可用于检测大物体;第二,SSD采用不同比例和纵横比的先验盒(在更快的R-CNN中称为Anchors)。Yolo算法的缺点是难以检测小目标,定位不准确,但这些重要的改进使SSD在一定程度上克服了这些缺点。下面我们详细讲解SDD算法的原理,最后给出如何用TensorFlow实现SSD算法。

图2不同算法的基本框架图设计概念

SSD和Yolo一样,使用CNN网络进行检测,但它使用的是多尺度特征图,其基本架构如图3所示。固态硬盘的核心设计理念总结如下:

图3 SSD基本框架

(1)利用多尺度特征图进行检测。

所谓多比例尺,就是用不同大小的特征图。一般CNN网络前面的特征图比较大,然后会逐渐采用stride=2或者pool的卷积来缩小特征图的大小。如图3所示,相对较大的特征图和相对较小的特征图都用于检测。这样做的好处是,较大的特征图用于检测相对较小的目标,而较小的特征图负责检测较大的目标。如图4所示,一张88的特征地图可以分成更多的单元,但每个单元的先验帧尺度相对较小。

图4不同尺度的特征图

(2)采用卷积进行检测。

与Yolo的全连接层不同,SSD直接利用卷积从不同的特征图中提取检测结果。对于具有形状的特征图,只需要这样一个相对较小的卷积核就可以得到检测值。

(3)设置先验框

在Yolo中,每个单元预测多个包围盒,但都是相对于单元本身的(正方块),但真实目标的形状是多变的,Yolo需要在训练过程中适应目标的形状。SSD借鉴了更快R-CNN中主播的思路。每个单元设置不同比例或长宽比的先验帧,预测包围盒基于这些先验帧,在一定程度上降低了训练难度。一般来说,每个单元都会设置多个先验帧,它们的尺度和长宽比都不一样。如图5所示,您可以看到每个单元使用四个不同的先前帧。图中,猫和狗用最适合它们形状的先验帧进行训练,先验帧的匹配原理后面会详细说明。

图5先前的固态硬盘盒

SSD的检测值也和Yolo不一样。对于每个单元的每个先前帧,它输出一组独立的检测值,对应于一个边界帧,该边界帧主要分为两部分。第一部分是每个类别的置信度或得分。值得注意的是,SSD将背景作为一个特殊的类别。如果有10类检测目标,SSD实际上需要预测10个置信度值,其中第一个置信度指的是没有目标或者属于背景的得分。后面我们说到一个类别的置信度的时候,请记住它包含了背景这个特殊的类别,也就是真正的检测类别只有10个。在预测过程中,置信度最高的类别就是包围盒所属的类别。特别地,当第一置信度值最高时,这意味着边界框不包含目标。第二部分是包围盒的位置,包含四个值,分别表示包围盒的中心坐标和宽度、高度。但真正的预测值其实只是边界框相对于先验框的转换值(论文说是偏移,但认为变换更合适,见R-CNN)。先前框的位置由指示,并且其对应的边界框是lbd$的转换值:

传统上,我们称这个过程为包围盒的编码。预测的时候需要把这个过程反过来,也就是编码,从预测值中得到包围盒的真实位置:

但是SSD的Caffe源代码实现中有个窍门,就是设置方差超参数来调整检测值,通过bool参数variance_encoded_in_target来控制两种模式。为真时,表示预测值中包含方差,就是上面的情况。但如果是假的(大部分都用这种方法,训练比较容易?),需要手动设置超参数方差来缩放的四个值,边界框需要这样解码:

综上所述,对于一个大小的特征图,共有个单元,每个单元设置的先验帧数记为,所以每个单元需要一个预测值总数,所有单元需要一个预测值总数。因为SSD使用卷积进行检测,所以需要一个卷积核来完成这个特征图的检测过程。

网络结构

SSD采用VGG16作为基本模型,然后在VGG16的基础上增加一个卷积层,获得更多的特征图进行检测。固态硬盘的网络结构如图5所示。SSD型号在上面,Yolo型号在下面。可以清楚地看到,SSD使用多尺度特征图进行检测。模型的输入图片大小为(也可以是和以前的网络结构没有区别,只是在最后加了一个卷积层,本文不做讨论)。

图5固态硬盘网络结构

VGG16作为基本型号。首先,在ILSVRC CLS-LOC数据集上对VGG16进行预训练。然后借鉴DeepLab-LargeFOV,将VGG16的全连通层fc6和fc7分别转换为卷积层conv6和conv7,池层pool5由原来的stride=2改为stride=1(估计是不想缩小特征图的大小)。为了应对这种变化,采用了阿特鲁算法。实际上,conv6采用了扩展卷积或膨胀conv,在不增加参数和模型复杂度的情况下,指数级扩展卷积的视野,并使用膨胀率这一参数来表示膨胀的大小,如下图6所示。(a)它是一个普通的卷积,它的视野是,(b)它是当膨胀率为2时,视野变成,(c)当膨胀率为4时。Conv6采用大小为但稀释率=6的扩展卷积。

图6扩展卷积

然后去除漏失层和fc8层,增加一系列卷积层对检测数据集进行精细化处理。

其中,VGG16中的Conv4_3层将作为检测的第一个特征图。conv4_3层的特征图大小为,但是这一层的范数比较高,所以后面加了一个L2归一化层(见ParseNet),保证和后面的检测层差别不是很大。这一层与批标准化层不同,只是标准化通道维度中的每个像素。批量归一化层在[batch_size,width,height]三个维度上进行归一化。归一化后,通常设置可训练的缩放变量,这可以通过使用TF容易地实现:

# l2norm(非bacth norm,空间归一化)def l2norm(x,scale,trainable=True,scope=' L2 normalization '):n _ channels=x . get _ shape()。as _ list()[-1]L2 _ norm=TF . nn . L2 _ normalize(x,[3],=1e-12)with TF . variable _ scope(scope):gamma=TF . get _ variable(' gamma 'shape=[n_channels,],dtype=tf.float32,initializer=TF . constant _ initializer(scale),trainable=trainable)返回l2_norm * gamma

从后面新添加的卷积层中提取Conv7、Conv8_2、Conv9_2、Conv10_2和Conv11_2作为用于检测的特征图。加上Conv4_3层,共提取了6个特征图,大小分别为,但不同特征图设置的先验帧数不同(同一特征图中各单元设置的先验帧数相同,此处数字指1。先验框的设置包括两个方面:比例(或大小)和长宽比。对于先验框的尺度,遵循线性增加的规律:随着特征图尺寸的减小,先验框的尺度线性增加:

指的是特征图的个数,但那是因为第一层(Conv4_3层)是单独设置的,表示的是先验帧大小与画面的比值,而和表示比值的最小值和最大值,纸取0.2和0.9。对于第一个要素图,其前一个框的比例尺一般设置为,所以比例尺为。对于后面的特征图,按照上面的公式线性增加先验帧比例尺,但是比例尺比例尺先扩大100倍,增长步长为,这样每个特征图的比例尺除以100,再乘以图片大小,就可以得到每个特征图的比例尺。这个计算方法参考了SSD的Caffe源码。综上所述,可以得到每个特征图的先验帧尺度。对于长宽比,一般选择。对于特定的长宽比,前一帧的宽度和高度按照以下公式计算(后者指的是前一帧的实际比例,而不是比例):

默认情况下,每个要素地图都将有一个比例为的先验框,此外,还将设置一个比例为和的先验框,以便每个要素地图都有两个长宽比为1但大小不同的正方形先验框。注意,最后的特征地图需要参考虚拟地图来计算。因此,每个特征图总共具有四个先前帧,但是在实施中,在层Conv4_3、Conv10_2和Conv11_2中仅使用四个先前帧,并且它们不使用具有纵横比的先前帧。每个单元格的先验框的中心点分布在每个单元格的中心,也就是特征图的大小在哪里。

得到特征图后,需要对特征图进行卷积才能得到检测结果。图7示出了一个尺寸的特征图的检测过程。其中Priorbox是前一个框,生成规则已经在前面介绍过了。检测值由类别置信度和包围盒位置两部分组成,各由一次卷积完成。设特征图中使用的先验帧个数为,则类别置信度所需的卷积核个数为,边界框位置所需的卷积核个数为。由于每个先验框会预测一个边界框,SSD300可以预测总共一个边界框,这是一个相当庞大的数字,所以SSD本质上是密集采样。

图7基于卷积获得检测结果的训练过程。

(1)先验帧匹配在训练过程中,首先需要确定训练图片中的地面真实(真实目标)与哪个先验帧匹配,匹配的先验帧对应的边界框将负责对其进行预测。在Yolo中,哪个单元格是地面真值的中心,这个单元格中IOU最大的包围盒负责预测。但是在SSD中就完全不同了,SSD优先帧和地面真实主要有两个匹配原则。首先,对于图片中的每一个地真相,找到IOU最大的前一帧,前一帧与之匹配,从而保证每一个地真相都必须匹配一个前一帧。通常情况下,与地面真值相匹配的先验盒称为正样本(实际上应该是与先验盒相对应的预测盒,但之所以这么叫是因为一一对应)。相反,如果一个先验框不匹配任何地面真值,那么这个先验框只能匹配背景,这是一个负样本。一个画面里的地面真实很少,但是有很多先验框架。如果只按照第一个原则匹配,很多先验帧会是负样本,正负样本极不平衡,所以需要第二个原则。第二个原则是,对于剩余的未匹配的先前帧,如果某个基本事实的值大于某个阈值(通常为0.5),则先前帧也与该基本事实匹配。这意味着某个地面实况可能匹配多个先验框,这是可以的。但反过来,它不能,因为一个先验框只能匹配一个地面真相。如果多个基本事实和一个在先框大于阈值,则在先框仅匹配具有最大IOU的基本事实。第二个原则必须在第一个原则之后进行。仔细考虑这种情况。如果某个地面真值的最大尺寸大于阈值,并且匹配的先验框大于另一个地面真值的阈值,那么先验框应该匹配谁?答案应该是前者。首先,确保某个基础事实必须有一个先验框与之匹配。但是,我觉得这种情况基本不存在。因为有很多先验框,某个地面真值的最大值肯定大于阈值,所以只实现第二个原则可能就够了。这里的TensorFlow版本只实现了第二个原则,但是这里的Pytorch原则都实现了。图8为匹配示意图,其中绿色GT为地面真值,红色为先验框,FP代表负样本,TP代表正样本。

图8先前盒子匹配的示意图

虽然一个地面真值可以匹配多个先验帧,但是地面真值的相对先验帧还是太少,所以相对于正样本会有很多负样本。为了尽可能保证正负样本的平衡,SSD采用硬负挖掘,即对负样本进行采样,按照置信度误差降序排列采样(预测背景的置信度越小,误差越大),选择误差较大的top-k作为负样本进行训练,以保证正负样本的比例接近1:3。

(2)损失函数的训练样本确定,然后就是损失函数。损失函数被定义为位置误差(loc)和置信损失(conf)的加权和:

其中是前一个盒子的阳性样本数。这里有一个指示参数,指示第一个先验框匹配第一个地面真值,地面真值的类别为。是类别置信度的预测值。是前一个框对应的边界框的位置预测值,而是地面真值的位置参数。对于位置误差,采用平滑L1损失,定义如下:

由于的存在,位置误差仅针对阳性样本进行计算。值得注意的是,首先要对地面真值进行编码,因为预测值也是编码值。如果variance _ encoded _ in _ target=true,则编码时应添加方差:

对于置信误差,它采用softmax损失:

通过交叉验证将权重系数设置为1。

(3)数据放大

SSD的性能可以通过数据放大来提高。使用的主要技术有水平翻转、随机裁剪颜色失真和随机采样补丁,如下图所示:

图9数据放大方案

其他的训练细节,比如学习率的选择,都可以在论文中找到,这里就不赘述了。

预测过程

预测过程相对简单。对于每个预测帧,首先根据类别置信度确定其类别(置信度最大的一个)和置信度值,过滤掉属于背景的预测帧。然后根据置信度阈值(如0.5),过滤掉阈值较低的预测帧。对剩余的预测帧进行解码,根据前一帧得到其真实位置参数(解码后通常需要剪辑,防止预测帧超出画面)。解码后一般需要按照置信度降序排序,然后只保留top-k(如400)个预测帧。最后,使用NMS算法滤除重叠较大的预测帧。最后剩下的预测框就是检测结果。

性能赋值

首先从整体上看SSD在VOC2007、VOC2012和COCO数据集上的表现,如表1所示。相比之下,SSD512的性能会更好。*表明采用图像扩展数据增强技术可以提高SSD对小目标的检测效果,从而提高性能。

表1不同数据集上的SSD性能

SSD与其他检测算法(VOC2007数据集)的比较结果如表2所示。基本上可以看出SSD和更快的R-CNN有一样的准确率,和Yolo有一样快的检测速度。

表2 SSD与其他检测算法的比较结果(在VOC2007数据集中)

文章还对SSD的每一招都做了比较详细的分析。表3显示了不同技巧组合对SSD性能的影响,从中可以得出以下结论:

数据放大技术很重要,大大提高了地图。

通过使用具有不同纵横比的先前帧可以获得更好的结果;

表3不同技巧组合对SSD性能的影响

同样,使用多尺度特征图进行检测也是非常重要的,这可以从表4中看出:

表4多尺度特征图对SSD在TensorFlow上实现的影响

SSD已经在很多开源的框架中实现了。这里SSD的推理过程是基于TensorFlow版balancap实现的。这里实现的是SSD300,和论文里的不一样。首先,定义SSD的参数:

自我。SSD _ params=SSD params(img _ shape=(300,300),#输入图片大小num_classes=21,#类别数背景no_annotation_label=21,feat_layers=['block4 '' block7 '' block8 '' block9 '' block10 '' block11'],#要进行检测的特征图name feat_shapes=[(38,38),(19,19),(10,10),(5,5),(3,3),(1,1)],#特征图大小anchor_size_bounds=[0.15,0.90],#特征图尺度范围anchor _ size=[(21 . 45.), (45. 99.), (99. 153.), (153. 207.), (207. 261.), (261. 315.)], # 不同特征图的先验框尺度(第一个值是s_k,第2个值是s_k 1) anchor_ratios=[[2,5],[2,5,3,1。/3], [2,5, 3, 1./3], [2,5, 3, 1./3], [2,5], [2,5]], # 特征图先验框所采用的长宽比(每个特征图都有2个正方形先验框)anchor_steps=[8,16,32,64,100,300],#特征图的单元大小anchor_offset=0.5,#偏移值,确定先验框中心规格化=[20,-1,-1,-1],# l2范数prior_scaling=[0.1,0.1,0.2,0.2] #方差)

然后构建整个网络,注意对于步幅=2的卷积神经不要使用法国南部(法国南部领地的缩写)自带的填充='相同,而是手动垫,这是为了与咖啡一致:

def _ build _ net(self):' ' '构造(同solid-statedisk)固态(磁)盘网' ' ' ' self.end_points={} #记录检测层输出自我._ images=TF。占位符(TF。float 32,shape=[None,self.ssd_params.img_shape[0],self.ssd_params.img_shape[1],3])带TF。variable _ scope(' SSD _ 300 _ vgg '):#原始vgg层# block 1 net=conv 2d(self ._images,64,3,scope='conv1_1') net=conv2d(net,64,3,scope=' con v1 _ 2 ')self。end _ points[' block 1 ']=net net=max _ pool 2d(net,2,scope=' pool 1 ')# block 2 net=conv 2d(net,128,3,scope='conv2_1') net=conv2d(net,128,3,scope=' con v2 _ 2 ')self。end _ points[' block 2 ']=net net scope=' con v4 _ 1 ')net=conv 2d(net,512,3,scope='conv4_2') net=conv2d(net,512,3,scope=' con v4 _ 3 ')self。end _ points[' block 4 ']=net=max _ pool 2d(net,2,scope=' pool 4 ')# block 5 net=conv 2d(net,512,3,scope='conv5_1') net=conv2d(net,512,3,scope=' con V5 _ 2 ')is _ training=self。is _ training)# block 7 net=conv 2d(net,1024,1,scope=' con V7 ')自我。end _ points[' block 7 ']=net # block 8 net=conv 2d(net,256,1,scope=' con V8 _ 1x 1 ')net=conv 2d(pad2d(net,1),512,3,stride=2,scope='conv8_3x3 'padding=' valid ')self。end _ points[' block 8 ']=net # block 9 net=conv 1,scope=' con v11 _ 1x 1 ')net=conv2d(net,256,3,scope='conv11_3x3 'padding=' valid ')self。end _ points[' block 11 ']=net #类和位置预测=[] logits=[] locations=[] for i,layer in enumerate(self。SSD _ params。feat _ layers):cls,loc=SSD _ multi box _ layer(self。end _ points[layer],self . SSD _ params . num _ class,self.ssd_params.anchor

对于特征图的检测,这里单独定义了一个组合层ssd_multibox_layer,其主要是对特征图进行两次卷积,分别得到类别置信度与边界框位置:

#多框层:从检测图层def ssd_multibox_layer(x,num_classes,sizes,ratios,normalization=-1,scope=' multi box '):pre _ shape=x . get _ shape().as _ list()[1:-1]pre _ shape=[-1]pre _ shape with TF。variable _ scope(scope):# L2范数if归一化0:x=L2范数(x,归一化)print(x)# anchors n _ anchors=len(size)len(ratios)# location pred=conv 2d(x,n_anchors*4,3,activation=None,scope=' conv _ loc ')loc _ pred=TF。shape(loc _ pred,pre_shape [n_anchors,4]) # class

对于先验框,可以基于numpy生成,定义在ssd_anchors.py文件中,结合先验框与检测值,对边界框进行过滤与解码:

班级,分数,bbox=自己. bboxes_select(预测,位置)

这里将得到过滤得到的边界框,其中班级,分数,邮箱分别表示类别,置信度值以及边界框位置。

基于训练好的权重文件在https://pan.baidu.com/s/1snhuTsT下载,这里对(同固态硬盘)固态(磁)盘进行测试:

ssd_net=SSD()类,分数,bbox es=SSD _ net。检测()图像=SSD _ net。images()sess=TF .session()#还原SSD模型。ckpt _文件名='/SSD _检查点/SSD _ vgg _ 300 _权重。ckpt ' sess。运行(TF。global _ variables _ initializer())saver=TF。火车。saver()saver。restore(sess,ckpt_filename) img=cv2.imread(./demo/狗。jpg ')img=cv2。CVT颜色(img,cv2 .COLOR _ bgr 2 RGB)img _预处理=预处理_图像(img)#预处理图片,主要是归一化和resizerclasses,rscores,rbboxes=sess.run([classes,scores,bboxes],feed _ dict={ images:img _预处理})r classes,rscores,Rb boxes=process _ bbox es(r classes,rscores,rbboxes) #处理预测框,包括剪辑,排序,NMS PLT _ bbox(img,rclasses,rscores,rbboxes绘制检测结果

详细的代码放在https://GitHub。com/xiaohu 2015/深度学习_教程/tree/master/对象检测/SSD上了,然后看一下一个自然图片的检测效果:

如果你想实现(同固态硬盘)固态(磁)盘的火车过程,你可以参考附录里面的咖啡,张量流以及Pytorch实现。

小结

(同固态硬盘)固态(磁)盘在你只活一次的基础上主要改进了三点:多尺度特征图,利用卷积进行检测,设置先验框。这使得(同固态硬盘)固态(磁)盘在准确度上比你只活一次更好,而且对于小目标检测效果也相对好一点。由于很多实现细节都包含在源码里面,文中有描述不准或者错误的地方在所难免,欢迎交流指正。