SSD(SSD: Single Shot MultiBox Detector)是采用单个深度神经网络模型实现目标检测和识别的方法。如图2所示,该方法是综合了Faster R-CNN的anchor box和YOLO单个神经网络检测思路(YOLOv2也采用了类似的思路,详见YOLO升级版:YOLOv2和YOLO9000解析),既有Faster R-CNN的准确率又有YOLO的检测速度,可以实现高准确率实时检测。在300*300分辨率,SSD在VOC2007数据集上准确率为74.3%mAP,59FPS;512*512分辨率,SSD获得了超过Fast R-CNN,获得了80%mAP/19fps的结果,如图0-2所示。SSD关键点分为两类:模型结构和训练方法。模型结构包括:多尺度特征图检测网络结构和anchor boxes生成;训练方法包括:ground truth预处理和损失函数。本文解析的是SSD的tensorflow实现源码,来源balancap/SSD-Tensorflow。本文结构如下:
图2 SSD与MultiBox,Faster R-CNN,YOLO原理
(此图来源于作者在eccv2016的PPT)
图0-2 SSD检测速度与精确度。(此图来源于作者在eccv2016的PPT)
SSD的网络模型如图3所示。
图3 SSD模型结构。(此图来源于原论文)
模型建立源代码包含于ssd_vgg_300.py中。模型多尺度特征图检测如图1-2所示。模型选择的特征图包括:38×38(block4),19×19(block7),10×10(block8),5×5(block9),3×3(block10),1×1(block11)。对于每张特征图,生成采用3×3卷积生成 默认框的四个偏移位置和21个类别的置信度。比如block7,默认框(def boxes)数目为6,每个默认框包含4个偏移位置和21个类别置信度(4+21)。因此,block7的最后输出为(19*19)*6*(4+21)。
所需的环境:
-
Anaconda3(64bit)
-
CUDA-9.2
-
CuDNN-7.15
-
Python-3.6
-
TensorFlow 或者 TensorFlow-gpu(由于考虑到项目工程量比较大,所以本文选用GPU版本进行训练)
步骤:
安装Anaconda3:在anaconda官网下下载对应windows版本的anaconda安装包,下载完成后按照提示进行安装,anaconda3里包含很多python IDE。
图4
安装cuda和cuDNN:安装Tensorflow-gpu版本必须先把cuda环境配置好,这样才能成功安装,如何查看cuda安装成功呢?可以在vs2017里面进行查看。
-
数据集制作:利用LabelImg工具对预先得到的需要训练的图片进行框选目标的最小包围框,LabelImg会自动将框选的目标生成所需要的xml文件。
-
图5
Xml文件中记录了人和帽子以及马甲的最小包围框。
-
格式转换:由于SSD-TensorFlow不能直接对图片进行训练,需要先将得到的图片转换为.tfrecord格式,在转换的过程中可以选择将多少张图片转为一个.tfrecord。
启动训练:在训练之前需要修改pascalvoc_2007.py和ssd_300_vgg.py文件中的识别目标数,改成自己需要识别的种类,然后在train_ssd_network.py文件中修改相应的参数。修改完成即可运行train_ssd_network.py文件,在console窗口可以查看相关的运行信息,当然在运行期间也可以查看tensorboard下的各个参数指标。
检验模型:模型检验在eval_ssd_network.py文件下进行检验,得到的输出信息mAP,为模型检验的准确率。
详细流程
Pascal voc2007数据集:
使用SSD-tensorflow的标准数据集包括Pascal voc2007和Pascal voc2012可以选择一起训练,也可以对两种数据集分开训练。在对视频进行处理时利用Matlab可以很容易将视频按自己选择的帧数截成图片。
得到图片后将图片以统一格式命名,放在JPEGImages文件夹下,接着将图片中的目标框选出来,框选图片有两种方法,一种是利用代码得到xml文件,不过这种方法每次都要改变代码里边框的大小信息,比较麻烦。还有一张使用自动化工具LabelImg。
Step1:点击open打开需要框选的图片的路径:。
Step2:点击Create RectBox,在图片上框选人所在位置。
Step3:在弹出的对话框中输入person。
Step4:对于hat,以及vest的框选重复步骤1,2,3即可直到所有的图片框选完。
注意:对同一幅图片.jpg文件和.xml命名要一样。
ssd-tensorflow-model工程相关参数修改:
-
转换为tfrecord格式:
首先将数据集保存在工程路径下,方便进行数据格式转换,以及模型训练。
Step1:打开pascalvoc_to_tfrecords.py文件,修改画框的参数,将SAMPLES_PER_FILES,改为自己需要将多少张图片转换成一个.tfrecord文件
比如我将其改为400,也就是是400张图片转换为一个.tfrecord文件。
Step2:tf_convert_data.py中,dataset_dir改为刚刚自己转换的图片所在的文件夹所在路径。output_dir改为自己需要保存的.tfrecord文件路径。
Step3:开始运行此.py文件代码,生成如下图所示文件
相关.py文件参数修改:
数据格式处理好了之后,下一步就要根据自己的目标种数修改大量的.py文件了,由于原项目工程为根据官网的标准数据集训练的共有20种目标需要训练,而自己的数据集训练目标为3种,所以对应的信息要修改。
Step1:修改pascalvoc2007.py相关信息,原项目21种目标,此处改为自己的目标种数NUM_CLASSES = 3,TRAIN_STATISTICS 第一个参数为目标出现在图片的张数,第二个参数为目标出现的总次数。SPLITS_TO_SIZES 为将数据集划分为训练数据集与测试数据集的张数。
Step2:修改pascalvoc_common.py相关信息
Step3:在ssd_vgg_300.py文件中修改如下参数。改为目标数加一(加一为背景还要算一种)。
-
开始训练模型:
为了开始训练模型,首先要将train_ssd_network.py文件相关信息修改正确。
Step1:train_dir改为自己需要将模型保存的路径下。
Step2:log_every_n_steps改为自己需要多少步保存显示相关信息。
Step3:save_summaries_secs为多少秒保存一次日志。
Step4:save_interval_secs为多少秒保存一次得到的模型。
Step5:gpu_memory_fraction为训练时需要占用多少百分百的显存。
Step6:leaning_rate为设置需要多大的学习率,一般开始学习率大一点以便不困在局部最优解,当loss比较小时learning_rate设置小一点降低loss。
Step7:end_learning_rate为训练结束时的学习率。
Step8:dataset_name修改为pascalvoc_2007,因为数据集为pascalvoc2007数据集。
Step9:num_classes为自己的目标数加一。
Step10:dataset_split_name改为train,划分tfrecord文件。
Step11:dataset_dir为转换的tfrecord文件路径。
Step12:model_name改为ssd_300_vgg,因为我们的图片resize为大小了。
Step13:batch_size根据自己显卡内存大小适当修改,太大了会报显存不足。
Step14:max_number_of_steps为最大训练步数,一般50000-100000均可。
Step15:checkpoint_path是否在预训练模型的基础上训练,此处我们可以在ssd_300_vgg模型的基础上训练我们的模型。
训练时输出窗口得到如下信息:
当loss值比较稳定而且比较小时说明模型训练的差不多了,可以停下来检验模型训练的好坏。
本次训练由于各种设备上的原因导致此次训练时间较为长,在ssd_300_vgg模型的基础上我训练了50000-60000次,得到了模型检测效果还比较好,接着为了得到更好的识别率,我将learning_rate改为了0.00001,继续训练了50000-60000步,模型精度提高了20%左右。
下图为在tensorboard下看到的训练过程中相关参数的变化,total_loss为训练过程中的损失度,可以看到损失度比较小,训练比较顺利。
图片检测效果分析:
ssd-tensorflow-model相比于Google API的缺点在于对小目标检测效果比较差,而此次训练得到的结果也能反映出这一点,当目标在图片中所占比例比较大时,训练得到的模型在检测时其效果比较好,寻找目标的位置较为准确,目标识别概率正确度高,如下图所示。
总结
优点:SSD(Single Shot MultiBox Detector)在训练时,这种算法对于不同横纵比的object的检测都有效,这是因为算法对于每个feature map cell都使用多种横纵比的default boxes,这也是此算法的核心。另外本文的default box做法是很类似Faster RCNN中的anchor的做法的。最后本文也强调了增加数据集的作用,包括随机裁剪,旋转,对比度调整等等,而且此模型训练速度较YOLO更加迅速,可以获得更加明显的效果。
缺点:文中作者提到该算法对于小的object的detection比大的object要差。作者认为原因在于这些小的object在网络的顶层所占的信息量太少,所以增加输入图像的尺寸对于小的object的检测有帮助。另外增加数据集对于小的object的检测也有帮助,原因在于随机裁剪后的图像相当于“放大”原图像,所以这样的裁剪操作不仅增加了图像数量,也放大了图像。