Caffe学习系列(八):Caffe-SSD及其轻量化模型

Caffe学习系列(八):Caffe-SSD及其轻量化模型

Mobilenet、Shufflenet重点参考:轻量化神经网络综述
Squeezenet重点参考:纵览轻量化卷积神经网络:SqueezeNet、MobileNet、ShuffleNet、Xception
模型实现集锦1
模型实现集锦2

1. Caffe-SSD
1.1 SSD 原理

SSD基础原理
SSD详解
算法评估

1.2 SSD 训练自己的数据集

SSD安装及训练自己的数据集

1.数据集准备
2.官方网络模型下载
下载的官方模型文件夹名称为VOC0712,放入ssd-caffe/models/VGGNet/目录下,如下图所示。
在这里插入图片描述3.修改 examples/ssd/ssd_pascal.py 文件

SSD源码解读之ssd_pascal.py

# 第81--84行
# The database file for training data. Created by data/VOC0712/create_data.sh
train_data = "/home/hitwh/workspace/data/VOCdevkit/cucumber/lmdb/cucumber_trainval_lmdb"
# The database file for testing data. Created by data/VOC0712/create_data.sh
test_data = "/home/hitwh/workspace/data/VOCdevkit/cucumber/lmdb/cucumber_test_lmdb"
# 第234--266行
# Modify the job name if you want.
job_name = "SSD_{}".format(resize)
# The name of the model. Modify it if you want.
model_name = "VGG_VOC0712_{}".format(job_name)

# Directory which stores the model .prototxt file.
save_dir = "models/VGGNet/VOC0712/{}".format(job_name)
# Directory which stores the snapshot of models.
snapshot_dir = "models/VGGNet/VOC0712/{}".format(job_name)
# Directory which stores the job script and log file.
job_dir = "jobs/VGGNet/VOC0712/{}".format(job_name)
# Directory which stores the detection results.
output_result_dir = "{}/data/VOCdevkit/results/VOC2007/{}/Main".format(os.environ['HOME'], job_name)

# model definition files.
train_net_file = "/home/hitwh/workspace/Mobilenet-ssd/caffe/models/VGGNet/VOC0712/SSD_300x300/train.prototxt".format(save_dir)
test_net_file = "/home/hitwh/workspace/Mobilenet-ssd/caffe/models/VGGNet/VOC0712/SSD_300x300//test.prototxt".format(save_dir)
deploy_net_file = "/home/hitwh/workspace/Mobilenet-ssd/caffe/models/VGGNet/VOC0712/SSD_300x300//deploy.prototxt".format(save_dir)
solver_file = "/home/hitwh/workspace/Mobilenet-ssd/caffe/models/VGGNet/VOC0712/SSD_300x300//solver.prototxt".format(save_dir)
# snapshot prefix.
snapshot_prefix = "{}/{}".format(snapshot_dir, model_name)
# job script path.
job_file = "{}/{}.sh".format(job_dir, model_name)

# Stores the test image names and sizes. Created by data/VOC0712/create_list.sh
name_size_file = "data/cucumber/test_name_size.txt"
# The pretrained model. We use the Fully convolutional reduced (atrous) VGGNet.
# pretrain_model = "models/VGGNet/VGG_ILSVRC_16_layers_fc_reduced.caffemodel"
# Stores LabelMapItem.
label_map_file = "data/cucumber/labelmap_voc_cucumber.prototxt"

# MultiBoxLoss parameters.
num_classes = 2   

# 第330--338行
# Solver parameters.
# Defining which GPUs to use.
gpus = "0"                 # 只有一个GPU
gpulist = gpus.split(",")
num_gpus = len(gpulist)

# Divide the mini-batch to different GPUs.
batch_size = 8            # 减小内存占用
accum_batch_size = 8

# 第358--360行
# Evaluate on whole test set.
num_test_image = 656       # 测试集图片数
test_batch_size = 2

训练若对网络模型进行了修改,则不能使用预训练模型,需注释掉以下内容:

# 第 261 行
# The pretrained model. We use the Fully convolutional reduced (atrous) VGGNet.
# pretrain_model = "models/VGGNet/VGG_ILSVRC_16_layers_fc_reduced.caffemodel"

# 第 424 行
# check_if_exist(pretrain_model)

# 第 536 行
# train_src_param = '--weights="{}" \\\n'.format(pretrain_model)

# 第 560 行
#  f.write(train_src_param)
1.3 网络模型修改

VGG的网络模型由 ssd_pascal.py 文件生成,可生成 VGG,ZF,Resnet101 和 Resnet152 四种网络。

# Create train net.  # 生成训练网络  往下还有 test net 和 deploy net
net = caffe.NetSpec()
net.data, net.label = CreateAnnotatedDataLayer(train_data, batch_size=batch_size_per_device,
        train=True, output_label=True, label_map_file=label_map_file,
        transform_param=train_transform_param, batch_sampler=batch_sampler)

VGGNetBody(net, from_layer='data', fully_conv=True, reduced=True, dilated=True,
    dropout=False)  # 生成 VGGNet

AddExtraLayers(net, use_batchnorm, lr_mult=lr_mult)

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)

VGGNetBody 函数在 caffe/python/caffe/model_libs.py 文件中定义,此外,还定义了其他网络,因此若要修改VGGNet网络模型,需修改model_libs.py 文件。

def VGGNetBody(net, from_layer, need_fc=True, fully_conv=False, reduced=False,
        dilated=False, nopool=False, dropout=True, freeze_layers=[], dilate_pool4=False):
    kwargs = {
            'param': [dict(lr_mult=1, decay_mult=1), dict(lr_mult=2, decay_mult=0)],
            'weight_filler': dict(type='xavier'),
            'bias_filler': dict(type='constant', value=0)}

    assert from_layer in net.keys()
    net.conv1_1 = L.Convolution(net[from_layer], num_output=64, pad=1, kernel_size=3, **kwargs)

    net.relu1_1 = L.ReLU(net.conv1_1, in_place=True)
    net.conv1_2 = L.Convolution(net.relu1_1, num_output=64, pad=1, kernel_size=3, **kwargs)
    net.relu1_2 = L.ReLU(net.conv1_2, in_place=True)
1.3 结果检测

运行以下命令,其中将末尾的路径设置好即可

python examples/ssd/ssd_detect.py

但不知为何,检测字体如下图一样low
在这里插入图片描述为了解决该问题,博主参考了这篇博客,将检测结果整理成 results.txt 文件如下:

examples/images/cat.jpg 8 0.999429 169 26 347 356
examples/images/cropped_panda.jpg 12 0.975958 0 1 95 97
examples/images/fish-bike.jpg 2 0.717551 52 81 448 307
examples/images/fish-bike.jpg 15 0.99994 204 3 344 170

然后在 caffe 目录下运行以下命令调用 plot_detections.py 文件画图,即可在 caffe/examples 目录下看到完美版效果了

python examples/ssd/plot_detections.py examples/images/result.txt /home/mx/caffe --labelmap-file data/VOC0712/labelmap_voc.prototxt --save-dir examples/

针对本文自己的数据集,使用以下命令

python examples/ssd/plot_detections.py examples/images/results.txt /home/hitwh/workspace/Mobilenet-ssd/caffe --labelmap-file data/cucumberA/labelmap_voc_cucumber.prototxt --save-dir examples/images/

在这里插入图片描述

1.2 SSD 结果可视化

Caffe-SSD:可视化(绘制loss,accuracy曲线)

切换至 Caffe/jobsVGGNet/VOC0712/SSD_300x300/ 目录下,可看到生成的 VGG_VOC0712_SSD_300x300.log 日志文件,运行一下命令可绘制训练曲线

python plot_training_log.py 6 trainloss.png VGG_VOC0712_SSD_300x300.log 

运行以下命令可绘制训练精度曲线

python plot_training_log.py 0 testloss.png VGG_VOC0712_SSD_300x300.log 
2. Mobilenet-SSD

目标检测:Mobilenet-SSD实现步骤
意味着TX1上Mobilenet-SSD能达到17帧左右,这离真正的real-time又近了一步

2.1 MobileNet-SSD 网路修改

这一步是由以下命令自动完成,不需要人为改动,但可通过上述原理了解改动原理

 # usage: ./gen_model.sh CLASSNUM 
 ./gen_model.sh 2 

在这里插入图片描述

2.2 合并bn层

运行以下命令,得到 no_bn.prototxt 和 no_bn.caffemodel

python2 merge_bn.py --model ./example/defults/MobileNetSSD_deploy.prototxt --weights ./snapshot/defults-A/mobilenet_iter_14000.caffemodel 
2.3 Mobilenet-ssdlite训练

caffe-SSD配置及用caffe-MobileNet-SSD训练自己的数据集
MobileNetv2-SSDLite训练自己的数据集

3. SqueezeNet-SSD

Squeezenet原理

3.1 模型下载
git clone https://github.com/chuanqi305/SqueezeNet-SSD

将模型放在 Mobilenet-ssd 目录下,使用mobilenet-ssd 的 train.sh test.sh 和 demo.py 进行训练和测试。下述 shufflenet 同样进行此操作。

3.2 网络修改

除了修改类别/路径,还需修改最后几层的参数

fire5fire9fire10fire11fire12_2fire13_2
162424242416
8121212128

代码如下:

layer {
  name: "fire11_mbox_conf"
  type: "Convolution"
  bottom: "fire11/concat"
  top: "fire11_mbox_conf"
  param {
    lr_mult: 1.0
    decay_mult: 1.0
  }
  param {
    lr_mult: 2.0
    decay_mult: 0.0
  }
  convolution_param {
    num_output: 12    # 修改此处
    pad: 1
    kernel_size: 3
    stride: 1
    weight_filler {
      type: "msra"
    }
    bias_filler {
      type: "constant"
      value: 0.0
    }
  }
}
laye

此外, test.prototxt 和 deploy.prototxt 的 reshape 也要根据类别修改

layer {
  name: "mbox_conf_reshape"
  type: "Reshape"
  bottom: "mbox_conf"
  top: "mbox_conf_reshape"
  reshape_param {
    shape {
      dim: 0
      dim: -1
      dim: 2   # 修改此处
    }
  }
}
3.3 训练报错

网络修改报错:
Check failed: 0 == bottom[0]->count() % explicit_count (0 vs. 128) bottom count (128480) must be divisible by the product of the specified dimensions (168)

解决办法:Check failed: 0 == bottom[0]->count() % explicit_count (0 vs. 76) bottom count (160600) must be divi

4. ShuffleNet-SSD

Shufflenet原理
简明版

4.1 caffe 源码修改

1.ShuffleNet-SSD需要修改 caffe 源码,添加网络层,首先下载 shuffle 层文件

git clone https://github.com/farmingyard/ShuffleNet

将下载后的 shuffle_channel_layer.hpp .cpp .cu 文件放在 caffe/src/caffe/layers/ 目录下
2.修改 caffe.proto 文件
在caffe 目录下搜索 caffe.proto 文件并打开,定位到 441 行 找到 message LayerParameter 函数,添加网络层,修改如下:

message LayerParameter {
 ... ... 
// ShuffleNet
  optional ShuffleChannelParameter shuffle_channel_param = 164;  
}
message ShuffleChannelParameter {
  optional uint32 group = 1[default = 1]; // The number of group
}

3.重新编译

make clean
make all -j16
make pycaffe
make test
make runtest
4.2 网络修改

1.路径与尾层参数修改和 squeezenet 类似,注意 test.prototxt 和 deploy.prototxt文件的类别数修改

conv13conv17conv18_2conv19_2conv20_2conv21_2
162424242424
81212121212

2.ConvolutionDepthwise层的修改
shufflenet 中还引入了“ConvolutionDepthwise”层,该层可修改为“Convolution”层,并在参数内添加 group 机制即可,数目与 num_output 一致。
ConvolutionDepthwise 主要位于在“convX/b”层中,其中 X 表示层2,3,4…。

layer {
  name: "conv17/b"
  type: "Convolution"  # ConvolutionDepthwise 修改为 Convolution
  bottom: "conv17/ChnlShf"
  top: "conv17/b"
  param {
    lr_mult: 1.0
    decay_mult: 1.0
  }
  convolution_param {
    num_output: 240
    bias_term: false
    pad: 1
    kernel_size: 3
    stride: 1
    group: 240   # 添加 group 机制
    weight_filler {
      type: "msra"
    }
  }
}
5. 模型P-R曲线

主要参考SSD算法评估

5.1 源码修改

修改四个文件: solver.cpp,caffe.prototxt,bbox_util.hpp和bbox_util.cpp
修改后的文件在这里

5.2 运行测试

在 solver_test.prototxt 文件中添加

show_pr_value: true 
show_per_class_result: true

在 Mobilinet-ssd 目录下运行以下命令

sh test.sh

结果如下:

在这里插入图片描述

6. Tiny-SSD

深度学习【25】物体检测:Tiny SSD
Tiny-SSD : 使用Squeeze-Net 替换 VGG-16

7. 网络模型总结

网络模型 github 地址

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

la_fe_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值