SSD总结

  • -------------Z  F J

1 直观感受

SSD是端对端的一步走的运行方式,这个方式类似于YOLO,而不同于Faster RCNN,所以速度上是类似于YOLO的速度,而高于Faster RCNN的速度,这个比较高的速度,实时性很强,可以应用到很多的场合。精度方面,SSD是采用不同的特征层进行检测(多尺度),因此就可以容纳很多不同现状、不同大小的问题的轮廓,所以在小物体的检查上面也是比YOLO的效果优异很多。整体精度已经是接近甚至超过Faster RCNN。所以是一个速度和精度的结合。

2 网络构成

2.1 整体结构

图1.网络结构(论文原图)

SSD(论文链接:https://arxiv.org/abs/1512.02325)的整体网络结构如图1所示,SSD是以高质量的图像分类架构为基础(例如:VGG、googlenet、alexnet等,都是在分类层之前阶段,主要是使用其特征提取功能),而搭建起来的。这里模型的作者选择的基础网络是VGG16,结构如图2,在这个基础上,将fc6和fc7转换为卷积层,将pool5从2×2-s2更改为3×3-s1,但是对pool的改变会引起感受野的改变,为了不让感受野发生变化,就使用了空洞卷积的操作(atrous algorithm)。另外删除了VGG的所有的dropout层和fc8层。在上面的网络后面,加上conv8_2,conv9_2,conv10_2,pool11这些层作为后续检测的提取特征层(另2个提取的特征层是conv4_3,conv7)。上述的外加的4个特征层,对应这结构图中的后面4层。实际上图中是省略了conv8_1等的层,这些层是1*1卷积产生的,用来降维。

注:空洞卷积(atrous algorithm)可以使得感受野变大。atrous相关博客:

https://blog.csdn.net/weixin_41274801/article/details/82960771

http://www.cnblogs.com/jianyingzhou/p/5386222.html

图2.VGG16结构

2.2 检测架构

图3.默认框示意图(论文原图)

每个feature map(特征层)会划分为M*N的原始框(feature maps),每个小格对应有不同长宽比的默认框(default box),每个特征层的每个原始框产生6个默认框(第一个特征层除外,是产生3个)。这样,不同的特征层代表了不同的尺度上的检测,加上不同的长宽比(aspect ratio),可以代表很多不同的形状和不同大小的物体的外接矩形。因此对大小物体的检测都会有比较好的效果,这个是相对于YOLO的优势之一。如图3所示,狗和猫分别对应于不同层的默认框,默认框加上4个偏移值(offsets),可对应到所预测的结果框。

2.2.1 默认框的生成

以feature map上每个点的中点为中心(offset=0.5),生成一系列同心的默认框(然后中心点的坐标会乘以step,相当于从feature map位置映射回原图位置)。在每个特征图上,default box的大小(scale)计算如下:

s就是scale值,其中,最底层特征图的 scale 值为 Smin=0.2,最高层的为Smax=0.95。可得到各层对应的默认框的大小。

default box的aspect ratios 有:{1, 2, 3,1/2,1/3},对于 aspect ratio = 1,额外增加一个default box,该box的尺度为 。每一个default box,中心点就是原始框的中心,宽度、高度计算如下:

在特征图上不同的尺度、不同的长宽比,包含了物体的不同尺寸、形状。如图3,狗的ground truth box与4*4feature map 中的红色 box 吻合,猫的ground truth box于8*8的feature map中的蓝色框吻合,都作为正样本,然后其余的 boxes 都作为负样本。

2.2.2 默认框选取

有了很多默认框(用于作为predictions boxes)之后,需要从若干个默认框选出正样本默认框(positive boxes)和负样本默认框(negative boxes)进行训练。选取正样本主要是通过默认框和ground truth box的重合程度(IOU)来匹配。匹配原则主要有两点。首先,对于图片中每个ground truth,找到与其IOU最大的默认框,该默认框与其匹配,这样,可以保证每个ground truth一定与某个默认框匹配。称与ground truth匹配的默认框为正样本。第二个原则是:对于剩余的未匹配默认框,若某个ground truth的  大于某个阈值(一般是0.5),那么该默认框也与这个ground truth进行匹配,作为正样本。第二个原则一定在第一个原则之后进行,因为要考虑到以下的这种情况,如果某个ground truth所对应最大IOU小于阈值,并且所匹配的默认框却与另外一个ground truth的  大于阈值,那么该默认框应该匹配谁,答案只能是前者,首先要确保某个ground truth一定有一个默认框与之匹配。不过,这种情况我觉得基本上是不存在的。由于默认框很多,某个ground truth的最大IOU肯定大于阈值,这两个原则按顺序一起使用,是作为一个保障。

上述产生了positive boxes,原则上positive boxes之外的默认框都是negative boxes,但是实际上negative boxes的数量会远多于positive boxes,导致两者之间的不均衡。因此SSD的作者采用,先将每一个物体位置上对应 predictions(default boxes)是 negative 的 boxes 进行排序,按照 default boxes 的 confidence 的大小。 选择最高的几个,保证最后 negatives、positives 的比例在3:1。

2.2.3 检测的卷积

网络框架中选取出来进行检查的不同尺度的特征层,是通过一组卷积滤波器来产生预测集合。这个预测需要产生类别的分数(c分类就有c个值)和相对于默认框的偏移值offsets(有4个值)。具体来说,例如p通道的m×n特征层,需要若干个3x3xP的滤波器进行运算,每个滤波器的运算结果就是上述c+4个值中的其中一个。

定义特征层的feature map cell固定有K个不同长宽比的默认框,而每个默认框对于的分类和偏移分量需要c+4个值来表示,那对于一个feature map cell就需要有k*(c+4)个滤波器了。而一个特征层需要s个滤波器,同时输出s个结果,s=N*M*k*(c+4)。输出的结果该预测本质来说也是一次卷积操作,输出的格式是一个1x1xS的层。

3 训练方式

3.1 loss定义

SSD的loss函数是源于MultiBox的目标函数,而SSD在其基础上进行了改造,主要是加入了多分类的目标,同时对矩形框的回归进行损失函数计算的改变。另外SSD的损失函数类似于Fast RCNN中的损失函数,总的损失函数是localization loss (loc) 和 confidence loss (conf) 的加权和,具体如下:

其中:

  • 用 Xpij(即式中的x)表示第 i个 default box与类别p的第j个ground truth box 相匹配,否则若不匹配的话,则Xpij 0 = 0 。
  • N是与 ground truth box 相匹配的 default boxes 个数
  • confidence loss(conf) 是 Softmax Loss,输入为每一类的置信度 c

  • 权重项 α,通常设置为 1
  • 位置回归则是采用 Smooth L1 loss(是MultiBox的损失函数L2-Norm的简化,虽然没有了“像素级准确”,但效率上提高了很多),L1目标函数为:

 

3.2 数据增强

数据增强可以使得训练出来的模型更加具有鲁棒性,SSD采用的数据增强策略是随机采用以下的方式进行采样:

  • 使用整个原始输入图像

  • 采样一个片段,使对象最小的jaccard重叠为0.1,0.3,0.5,0.7或0.9。

  • 随机采样一个片段

每个采样片段的大小为原始图像大小的[0.1,1],横宽比在1/2和2之间。如果真实标签框中心在采样片段内,则保留重叠部分。在上述采样步骤之后,将每个采样片大小调整为固定大小,并以0.5的概率水平翻转。其中这种采样具有把图片特征放大的作用,有利于小物体的检测。

3.3训练过程

3.3.1 初始化

网络中的基础网络,使用训练好的VGG16的参数进行初始化,其余的卷积部分采用“xavier”方法进行初始化。另外,对于每个原始框的默认框(前面部分也稍微提过),具体来说,由于conv4_3的大小较大(38×38),因此我们只在其上放置3个默认框:一个0.1比例的框和另外纵横比为1/2和2的框。对于所有其他层,我们设置6个默认框(前面提到过),而且conv4_3使用的L2正则化技术,将特征图中每个位置处的特征范数缩放为20,并在反向传播期间学习比例。

3.3.2 训练策略

优化器:SGD

学习率:0.001

momentum:0.9

weight decay:0.0005

batch:32

按此策略迭代4W次,再把学习率改为0.0001,继续迭代,2W次。

3.3.3 训练结果

结果如表1,SSD300模型比Fast R-CNN更准确。当以更大的500×500输入图像训练SSD,结果更准确,超过了Faster R-CNN 1.9% mAP。

表1.SSD训练结果

 

4预测与模型分析

4.1 预测方式

预测方式就是指最终检测所用的方式,即SSD算法步骤,这个预测方式于上述的训练方式大部分是相同的,对预测的算法步骤总结如下(看完训练之后看这里,会感到很熟悉):

1.利用训练好的网络,已经预设好的函数和默认框等参数进行检测,输入300(或500)大小的待测图。

2.抽取Conv4_3、Conv7、Conv8_2、Conv9_2、Conv10_2、Conv11_2层的feature map,然后分别在这些feature map层上面的每一个点构造6个(首层为3个)不同尺度大小的默认框,然后分别进行检测和分类,生成多个默认框。

3. 将不同feature map获得的默认框(这里可以称作为检测框、先验框)结合起来,经过NMS(非极大值抑制)方法来抑制掉一部分重叠或者不正确的结果框(默认框加上偏移值),生成最终的结果集合(即检测结果)。

4.2 模型分析

这里的模型分析主要是总结ssd中哪操作是对模型产生积极影响的,具体如下:

数据增强:Fast和Faster R-CNN使用原始图像和水平翻转(0.5概率)图像训练。SSD使用更广泛的采样策略,类似于YOLO,但它使用了我们没有使用的光度失真。SSD另外指出,用这个抽样策略提高6.7%的mAP。

更多特征图:SSD比较使用conv4_3预测的模型和没有它的模型。论文指出可以看出,通过添加conv4_3进行预测,它有明显更好的结果(72.1%vs68.1%)。这也符合直觉,conv4_3可以捕获对象更好的细粒度,特别是细小的细节。

更多默认框形状:默认情况下,每个位置使用6个默认框。如果删除具有1/3和3宽高比的框,性能下降0.9%。通过进一步移除1/2和2纵横比的框,性能再下降2%。使用多种默认框形状似乎使网络预测任务更容易。

Atrous算法:SSD使用了VGG16的atrous版本,遵循DeepLabLargeFOV。如果我们使用完整的VGG16,保持pool5与2×2-s2,并且不从fc6和fc7的采集参数,添加conv5_3,结果稍差(0.7%),而速度减慢大约50%。

5架构实现

本人跑过SSD的tensorflow框架的代码,从代码资料查找、下载,到训练,再到测试和计算mAP,等过程。以下是一些记录:

训练的模型采用github上SSD的tensorflow版本最多star的一个https://github.com/balancap/SSD-Tensorflow,并参考其称作步骤。

图4.模型来源

5.1训练

数据来源是voc2007与voc2012,图5中的VOCdevkit文件夹,就是数据集解压好的文件夹了,其余的是训练结果的model和测试结果log。

图5.我的文件夹

制作tfrecords文件,运行以下脚本文件即可产生,这个文件需要新建在SSD-Tensorflow-master文件夹下面,另外DATASET_DIR代表数据集的地址,OUTPUT_DIR代表你存放tfrecords的地方。

    #Directory where the original dataset is stored
    DATASET_DIR=/media/zhangfangjian/data/SSDproject/VOCdevkit/VOC2007/

    #Output directory where to store TFRecords files
    OUTPUT_DIR=/media/zhangfangjian/data/SSDproject/train_tfrecords

    python3 ./tf_convert_data.py \
        --dataset_name=pascalvoc \
        --dataset_dir=${DATASET_DIR} \
        --output_name=voc_2007_train \
        --output_dir=${OUTPUT_DIR}

train_ssd_network.py修改第154行的最大训练步数,将None改为比如50000,即训练5W步就会自动停止。制作训练的脚本文件,如下代码,也是新建在SSD-Tensorflow-master文件夹下面,注意,每一行的末尾的\的后面,是不能有空格号的,不然训练的时候会报错。运行一下代码,即可进行训练。

    #!/bin/bash
    DATASET_DIR=/media/zhangfangjian/data/SSDproject/train_tfrecords/  ###训练集转化成tfrecords存储的路径
    TRAIN_DIR=/media/zhangfangjian/data/SSDproject/sgd_3pe34_ssd_peper_model/        ###存储训练结果的路径,包括checkpoint和event,自行指定
    #CHECKPOINT_PATH=/media/zhangfangjian/data/SSDproject/SSD-Tensorflow-master/checkpoints/ssd_300_vgg.ckpt
    CHECKPOINT_PATH=/media/zhangfangjian/data/SSDproject/SSD-Tensorflow-master/checkpoints/vgg_16.ckpt
    python train_ssd_network.py \
        --train_dir=${TRAIN_DIR} \
        --dataset_dir=${DATASET_DIR} \
        --dataset_name=pascalvoc_2007 \
        --dataset_split_name=train \
        --model_name=ssd_300_vgg \
        --checkpoint_path=${CHECKPOINT_PATH} \
	--checkpoint_model_scope=vgg_16 \
	--checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
    	--trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box \
        --save_summaries_secs=160 \
        --save_interval_secs=1600 \
        --weight_decay=0.0005 \
        --optimizer=sgd \
        --learning_rate=0.005 \
	--learning_rate_decay_factor=0.9 \
        --batch_size=16

下图是我训练的结果,loss值一直不太稳定(图6),后来查了Google查了很多,发现很多人有这个问题出现,也没有明确的解决方法。不过在该tensorflow模型的github的评论下面(所有评论都看了一遍),有人提到过可能是ssd_vgg_300.py文件中的batch_size参数有问题,我改成下面之后(图7),同时测试过很多不同的优化器、步长初始化参数、衰减系数等的组合,loss的效果改善很多(图8),不过这个结果也不太好,需要后续继续研究和改进。

图6.不稳定的loss
图7.修改网络

 

图8.最后稳定到6左右

5.2 跑demo

跑的demo在notebooks文件夹下,一般是用jupyter来做(如图9)。代码中的ckpt_filename是设置为要做测试的模型的绝对路径(相对路径也行),另外有些博客说过这两行需要注释掉,经过我的尝试,结论是不用注释,也不能注释掉。然后就运行这个jupyter,即可得出结果图(图10)。

图9.demo
图10.demo结果图

 

5.3 测mAP

步骤是先生成tfrecords文件,然后运行sh文件。具体来说,利用上述训练中生成tfrecords文件的同样的方式(把sh代码中相应的train改为test),生成是要用到的文件。然后新建新的测试脚本(在同样的文件夹下),我的代码如下。

 python3 ./eval_ssd_network.py \
        --eval_dir=/media/zhangfangjian/data/SSDproject/ssd_eval_log/ \
        --dataset_dir=/media/zhangfangjian/data/SSDproject/test_tfrecords/ \
        --dataset_name=pascalvoc_2007 \
        --dataset_split_name=test \
        --model_name=ssd_300_vgg \
        --checkpoint_path=/media/zhangfangjian/data/SSDproject/SSD-Tensorflow-master/checkpoints/adam_94_3pe34 \
        --batch_size=1

另外需要找出pascalvoc_to_tfrecords.py ,然后更改文件的83行读取方式为’rb’。然后就运行测试的脚本文件。生成了结果文件之后,在相应的文件夹目录下,运行tensorboard,可以得到如图11的结果集合。

图11.tensorboard结果

5.4 其他框架的SSD

SSD还在很多很多的框架上有实现,例如keras、caffe(作者框架)、Pytorch等等很多。例如我还看过一下keras的SSD模型,记录一下,这里记录的是github上面800+star的一个模型,训练的是kitti数据集,下图就是我下载并解压的数据集,具体操作如下链接。keras的框架训练,主要直接读取voc格式是数据集就可以,不需要像tensorflow那样制作中间的tfrecords文件。

https://blog.csdn.net/Jesse_Mx/article/details/65634482

https://github.com/pierluigiferrari/ssd_keras

https://blog.csdn.net/remanented/article/details/79943418

6训练其他数据

如果想用tensorflow的ssd跑自己的数据,那就要制作自己的数据集,做成类似于VOC格式的数据集,然后在做出tfrecords文件,给ssd训练。

6.1 制作voc数据集

通过labelImg制作每张图片的标签(或者你用现成的标好的图也行),制作2007VOC数据集,具体步骤可以在谷歌上找到很多,例如https://blog.csdn.net/gaohuazhao/article/details/60871886。做好的数据集如下图所示。各个文件夹的作用:Annotations文件夹下有保存每张图片的xml文件。ImageSets有四个xml文件,用来划分训练验证测试集。JPEGImages文件夹下保存的是图片数据。

附分割训练测试验证集的代码:

import os
import random 
 
xmlfilepath=r'/media/comway/data/DialVOC/Annotations'
saveBasePath=r"/media/comway/data/DialVOC"
 
trainval_percent=0.9
train_percent=0.9
total_xml = os.listdir(xmlfilepath)
num=len(total_xml)  
list=range(num)  
tv=int(num*trainval_percent)  
tr=int(tv*train_percent)  
trainval= random.sample(list,tv)  
train=random.sample(trainval,tr)  
 
print("train and val size",tv)
print("traub suze",tr)
ftrainval = open(os.path.join(saveBasePath,'ImageSets/Main/trainval.txt'), 'w')  
ftest = open(os.path.join(saveBasePath,'ImageSets/Main/test.txt'), 'w')  
ftrain = open(os.path.join(saveBasePath,'ImageSets/Main/train.txt'), 'w')  
fval = open(os.path.join(saveBasePath,'ImageSets/Main/val.txt'), 'w')  
 
for i  in list:  
    name=total_xml[i][:-4]+'\n'  
    if i in trainval:  
        ftrainval.write(name)  
        if i in train:  
            ftrain.write(name)  
        else:  
            fval.write(name)  
    else:  
        ftest.write(name)  
  
ftrainval.close()  
ftrain.close()  
fval.close()  
ftest .close() 

附将数据重命名为六位数据代码:


import os
 
class BatchRename():
    '''
    批量重命名文件夹中的图片文件
    '''
    def __init__(self):
        #我的图片文件夹路径horse
        self.path = '/media/comway/data/dialData'
 
    def rename(self):
        filelist = os.listdir(self.path)
        total_num = len(filelist)
        i = 1
	n = 6
        for item in filelist:
            if item.endswith('.jpg'):
		n = 6 - len(str(i))
                src = os.path.join(os.path.abspath(self.path), item)
                dst = os.path.join(os.path.abspath(self.path), str(0)*n + str(i) + '.jpg')
                try:
                    os.rename(src, dst)
                    print 'converting %s to %s ...' % (src, dst)
                    i = i + 1
		    
                except:
                    continue
        print 'total %d to rename & converted %d jpgs' % (total_num, i)
 
if __name__ == '__main__':
    demo = BatchRename()
    demo.rename()

6.2 细节修改

打开进入SSD-Tensorflow-master—>datasets—>pascalvoc_common.py 改代码,根据自己情况更改,有几类就改成几类。


VOC_LABELS = { 
    'none': (0, 'Background'), 
    'aeroplane': (1, 'Vehicle'), 
    'bicycle': (2, 'Vehicle'), 
    'bird': (3, 'Animal'), 
    'boat': (4, 'Vehicle'), 
    'bottle': (5, 'Indoor'), 
    'bus': (6, 'Vehicle'), 
    'car': (7, 'Vehicle'), 
    'cat': (8, 'Animal'), 
    'chair': (9, 'Indoor'), 
    'cow': (10, 'Animal'), 
    'diningtable': (11, 'Indoor'), 
    'dog': (12, 'Animal'), 
    'horse': (13, 'Animal'), 
    'motorbike': (14, 'Vehicle'), 
    'Person': (15, 'Person'), 
    'pottedplant': (16, 'Indoor'), 
    'sheep': (17, 'Animal'), 
    'sofa': (18, 'Indoor'), 
    'train': (19, 'Vehicle'), 
    'tvmonitor': (20, 'Indoor'), 
}

SSD-Tensorflow-master—>datasets—>pascalvoc_to_tfrecords.py   然后更改文件的83行读取方式为’rb’)

另外就是按照上述的方法生成tfrecords文件,即可开始训练自己的数据。

 

7目前榜单

附上目前为止,问题检测模型的实时排名,这个排名是voc2012上的排名。http://host.robots.ox.ac.uk:8080/leaderboard/displaylb.php?cls=motorbike&challengeid=11&compid=4&submid=19549

图12.排名图

8参考文献

在学习研究ssd的过程中,看了很多论文、博客、源码等,感谢这些资料的作者,现在把影响我较多的一些资料的链接附上:

原论文:https://arxiv.org/abs/1512.02325

模型github:https://github.com/balancap/SSD-Tensorflow

其他博客:

http://www.studyai.com/article/3e454b9e#goto-page-logo

https://blog.csdn.net/u010167269/article/details/52563573

https://blog.csdn.net/c20081052/article/details/80391627

https://blog.csdn.net/WZZ18191171661/article/details/79444217

https://blog.csdn.net/zziahgf/article/details/79086677

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值