SSD: Single Shot MultiBox Detector 模型fine-tune和网络架构

前言

博主在上一篇中提到了两种可能的改进方法。其中方法1,扩充类似数据集,详见Udacity Self-Driving 目标检测数据集简介与使用 ,由于一些原因,并未对此数据集做过多探索,一次简单训练下,mAP为64%左右,这还需要进一步探索。而方法2,说的是fine-tune已经训练好的SSD model,最近没来得及进行调参,初次实验效果有限,先把过程和原理记录下来,免得忘了,然后还会说下SSD的网络架构。

SSD模型fine-tune

CNN fine-tune

model fine-tune,就是模型微调的意思。举个例子说明一下:假如给你一个新的数据集做图片分类,这个数据集是关于汽车的,不过样本量很少,如果从零开始训练CNN(Alexnet或者VGG),容易过拟合。那怎么办呢?于是想到了迁移学习,用别人训练好的Imagenet模型来做,继承现有模型学到的特征“知识”,这样再训练的效果就会好一些。

SSD检测任务也适用fine-tune策略。之前博主介绍的SSD经典训练方法也算是一种fine-tune,为什么这么说,因为我们使用VGG_ILSVRC_16_layers_fc_reduced.caffemodel这个预训练模型,这其实是作者在Imagenet上训练的一个变种VGG,已经具备了一定的分类特征提取能力,我们继承这些“知识”,有利于模型的快速收敛。

其实,我们也可以直接去学习训练好的SSD的模型“知识”。比如,作者在COCO数据集上训练了一个SSD检测模型,这个模型对90类物体有较好的检测能力,现在我们只对其中的汽车和行人感兴趣,就只想检测这两类(COCO数据集当然也包含这两类),手头还有KITTI数据集等,现在就可以在这个模型的基础上去fine-tune,copy大部分有用的检测“知识”,并且专心学习两类物体特有的“知识”。

这里以COCO为例,介绍一下如何使用新数据集去fine-tune一个SSD COCO model,默认是SSD300x300。首先是下载07+12+COCO ,这个是作者用VOC数据集去微调COCO模型的范例,我们以此为蓝本进行修改,主要修改点是数据集以及预训练的模型。

下载压缩包,找到finetune_ssd_pascal.py文件,打开后可以看到和之前的ssd_pascal.py区别不是很大,重要的是这么一句:

pretrain_model = "models/VGGNet/VOC0712/SSD_300x300_coco/VGG_coco_SSD_300x300.caffemodel"

这就是预训练的模型,可以下载的,在作者主页找到COCO models: trainval35k,下载解压可得到VGG_coco_SSD_300x300_iter_400000.caffemodel ,再改个名字放到对应路径就行。接下来给复制一份脚本,命名为finetune_ssd_kitti.py ,然后修改成各种KITTI相关的名称和路径,类别数量也要改(可参考之前博文修改)。

下面运行命令开始训练看看:

$ cd caffe
$ python examples/ssd/finetune_ssd_kitti.py

发现有大bug,错误描述如下:

Cannot copy param 0 weights from layer 'conv4_3_norm_mbox_conf'; shape mismatch.  Source param shape is 324 512 3 3 (1492992); target param shape is 16 512 3 3 (73728). To learn this layer's parameters from scratch rather than copying from a saved net, rename the layer.
*** Check failure stack trace: ***
    @     0x7f0bddd2f5cd  google::LogMessage::Fail()
    @     0x7f0bddd31433  google::LogMessage::SendToLog()
    @     0x7f0bddd2f15b  google::LogMessage::Flush()
    @     0x7f0bddd31e1e  google::LogMessageFatal::~LogMessageFatal()
    @     0x7f0bde5c34cb  caffe::Net<>::CopyTrainedLayersFrom()
    @     0x7f0bde5ca225  caffe::Net<>::CopyTrainedLayersFromBinaryProto()
    @     0x7f0bde5ca2be  caffe::Net<>::CopyTrainedLayersFrom()
    @           0x40a849  CopyLayers()
    @           0x40bca4  train()
    @           0x4077c8  main
    @     0x7f0bdc4c6830  __libc_start_main
    @           0x408099  _start
    @              (nil)  (unknown)
Aborted (core dumped)

这个问题困扰了几天,后来才知道,COCO模型有81类,而本次训练的文件只有4类,conf层没有办法共享权值。解决方法就是把conf层改个名字,跳过这些层的fine-tune,意味着这部分层的参数需要从零学起。至于loc层则可以不改名,因为位置坐标和类别无关,所有类别均可共享。那么,注意到该脚本下有两个一模一样的CreateMultiBoxHead函数:

mbox_layers = CreateMultiBoxHead(net, data_layer='data', from_layers=mbox_source_layers,
        use_batchnorm=use_batchnorm, min_sizes=min_sizes, max_sizes=max_sizes,
        aspect_ratios=aspect_ratios, steps=steps, normalizations=normalizations,
        num_classes=num_classes, share_location=share_location, flip=flip, clip=clip,
        prior_variance=prior_variance, kernel_size=3, pad=1, lr_mult=lr_mult)

现在,仅需要在这两个函数中添加参数conf_postfix='_kitti'就可以把conf层的名字修改了,其实就是在所有’conf’字符后面添加了’kitti’字样,新函数就变成了:

mbox_layers = CreateMultiBoxHead(net, data_layer='data', from_layers=mbox_source_layers,
        use_batchnorm=use_batchnorm, min_sizes=min_sizes, max_sizes=max_sizes,
        aspect_ratios=aspect_ratios, steps=steps, normalizations=normalizations,
        num_classes=num_classes, share_location=share_location, flip=flip, clip=clip,
        prior_variance=prior_variance, kernel_size=3, pad=1, lr_mult=lr_mult, conf_postfix='_kitti')

然后再运行命令,就可以正常开始训练了。博主所用脚本可以参考一下:finetune_ssd_kitti.py

一开始使用默认solver训练了一次,120000迭代,mAP勉强达到63%,感觉还是不够看的。后来觉着默认solver中的学习率策略可能不太对,如果使用大的学习率(比如0.001)训练太久的话,原有caffemodel的基础权重可能会被破坏的比较厉害,那效果就会打折扣,因此有大神建议博主可以每隔10000次迭代降低学习率为一半,就是暂时没空尝试,如果有效果再更新吧。

SSD网络架构

VGGNet-SSD网络结构图

如果只是训练想VGGNet的SSD,并不用太关心SSD的网络结构,毕竟有python脚本可用。可是如果要想进一步修改网络,比如把基础网络换成Mobilenet,Resnet等,或者是修改

  • 9
    点赞
  • 39
    收藏
    觉得还不错? 一键收藏
  • 54
    评论
评论 54
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值