MobileNet-SSD训练自己的数据集

仅作笔记整理搬运使用,没有任何程序原创部分,主要给自己提个醒,避免重复搜索工作

一、配置

ubuntu18.04 ,显卡驱动,cuda10.1,cudnn7.6.5
查看cuda版本:
cat /usr/local/cuda/version.txt
查看cudnn版本:
cat /usr/local/cuda/include/cudnn.h | grep CUDNN_MAJOR -A 2

二、安装配置caffe-ssd

annaconda下创建caffe环境:conda create -n caffe2 python=2.7

opencv安装:pip install opencv-python

安装配置caffe-ssd
https://blog.csdn.net/CAU_Ayao/article/details/84000151

make runtest -j16 的时候会出错!

三、制作VOC数据集

https://blog.csdn.net/Sunhansong/article/details/107281225

四、voc数据集转化成lmbd数据集

https://blog.csdn.net/la_fe_/article/details/84928958

caffe 使用的是 LMDB 数据集格式,使用 caffe 框架实现mobilenets-ssd训练,还需要将 VOC 数据集转换为 lmdb 格式。

(虽然用cucumber有点奇怪,但是就顺着人家作者来吧)

  1. 在 home/shs/data/VOCdevkit 目录下创建 cucumber 目录,该目录中存放自己转换完成的VOC数据集,即Annotation/ImageSets/JPEGImages 等多个文件夹,ImageSets中的Main中要生成好四个txt文件;
  2. 在 home/shs/caffe-ssd/examples 目录下创建 cucumber 目录;
  3. 在 home/shs/caffe-ssd/data 目录下创建 cucumber 目录,同时将data/VOC0712下的 create_list.sh,create_data.sh,labelmap_voc.prototxt
    这三个文件copy到 cucumber 目录下,分别重命名为create_list_cucumber.sh,create_data_cucumber.sh, labelmap_voc_cucumber.prototxt
  4. 对上面新生成的两个create文件进行修改,主要修改是将 VOC0712 相关的信息替换成 cucumber

labelmap_voc_cucumber.prototxt 修改内容:
注意:"background"这个背景类别0标签不可以删掉

item {
  name: "none_of_the_above"
  label: 0
  display_name: "background"
}
item {
  name: "p"
  label: 1
  display_name: "p"
}
item {
  name: "d"
  label: 2
  display_name: "d"
}
item {
  name: "w"
  label: 3
  display_name: "w"
}

create_list_cucumber.sh 修改内容:

  for name in cucumber  # 修改此处为自己数据集的名字
  do
    if [[ $dataset == "test" && $name == "VOC2012" ]]
    then
      continue
    fi

create_data_cucumber.sh 修改内容:

root_dir=/home/shs/caffe-ssd
… …
data_root_dir="$HOME/data/VOCdevkit"  # 数据集路径
dataset_name="cucumber" 
mapfile="$root_dir/data/$dataset_name/labelmap_voc_cucumber.prototxt"
  1. 运行脚本
    在 home/shs/caffe-ssd/ 目录下分别运行:
./data/cucumber/create_list_cucumber.sh
./data/cucumber/create_data_cucumber.sh
  1. 运行create_data_cucumber.sh会出现问题
    ImportError:No module named caffe.proto
    https://blog.csdn.net/wangduyang/article/details/78211126
gedit ~/.bashrc

加入

export PYTHONPATH=~/caffe-ssd/python:$PYTHONPATH
source ~/.bashrc

在每次执行creat_data.sh生成lmdb的时候都需要进行上述操作。

五、Mobilenet-SSD下载并训练

1.Mobilenet-SSD下载

git clone https://github.com/chuanqi305/MobileNet-SSD.git

文件结构
template: 存放4个网络定义的公用模板,可以由gen.py脚本修改并生成
MobileNetSSD_deploy.prototxt :运行网络定义文件
solver_train.prototxt :网络训练超参数定义文件
solver_test.prototxt :网络测试超参数定义文件
train.sh :网络训练脚本
test.sh :网络测试脚本
gen_model.sh :生成自定义网络脚本(调用template文件夹内容)
gen.py :生成公用模板脚本(暂不用)
demo.py :实际检测脚本(图片存于images文件夹)
merge_bn.py :合并bn层脚本,用于生成最终的caffemodel

2.训练自己的数据集

  1. 运行gen_model.sh脚本
./gen_model.sh 4

**注意:**这里的用法是:# usage: ./gen_model.sh CLASSNUM,CLASSNUM是你的类别数,比如我的数据集有三类,应该再加上background这一类,所以CLASSNUM 类别数就为4

执行之后,得到 Mobilenet-SSD/examples 文件夹里面的3个prototxt就是从模板生成的正式网络定义,根据原作者设置,其中的deploy文件是已经合并过bn层的,需要后面配套使用

  1. 修改三个prototxt的路径
    将 Mobilenet-SSD/examples 下网络文件的路径修改为自己的路径.
    MobileNetSSD_test.prototxt:
data_param {
    # 第 24 行
    source: "/home/shs/data/VOCdevkit/cucumber/lmdb/cucumber_test_lmdb/"
    batch_size: 8
    backend: LMDB
  }
  annotated_data_param {
    batch_sampler {
    }
      # 第 31 行
    label_map_file: "/home/shs/caffe-ssd/data/cucumber/labelmap_voc_cucumber.prototxt"

MobileNetSSD_train.prototxt:

data_param {
  # 第 49 行
    source: "/home/shs/data/VOCdevkit/cucumber/lmdb/cucumber_trainval_lmdb/"
    batch_size: 24
    backend: LMDB
..........................
      max_sample: 1
      max_trials: 50
    }
  # 第 136 行
    label_map_file:
     "/home/shs/caffe-ssd/data/cucumber/labelmap_voc_cucumber.prototxt"
  }

Mobilenet-ssd目录下的 solver_train.prototxt 和 solver_test.prototxt

solver_mode: CPU

???为啥

  1. 开始训练
    先把train.sh修改地址
#../../build/tools/caffe train -solver="solver_train.prototxt" \
../caffe-ssd/build/tools/caffe train -solver="solver_train.prototxt" \
./train.sh

train.sh里的内容解析:(根据自己的路径实际情况做微调)

第2行是train.prototxt的路径,第7行是snapshot保存中间模型的路径,第8行是slover文件的路径,第9行是预训练权重,第10行是用到的gpu编号,这些都可以按需修改。笔者将最后一行的gpu从0修改为0,1,可利用双GPU训练

solver_train.prototxt文件内容:

rain_net:“example/MobileNetSSD_train.prototxt” #训练用的网络文件
test_net:“example/MobileNetSSD_test.prototxt” #测试用的网络文件
test_iter: 673 #测试时的迭代次数
test_interval: 1000 #每训练1000次迭代一次
base_lr: 0.0005 #基准学习率
display: 5 #每5次迭代屏幕显示一次信息
max_iter: 20000 #最大迭代次数
lr_policy: “multistep” #学习率调整策略
gamma: 0.5
weight_decay: 0.00005 #权重衰减
snapshot: 1000 #每1000次迭代抓取一次快照
snapshot_prefix:“snapshot_power/mobilenet” #快照保存的前缀
solver_mode: GPU #这里一定要GPU
debug_info: false
snapshot_after_train: true
test_initialization: false #不做测试初始化
average_loss: 10 #每10次迭代平均下loss
stepvalue: 10000
stepvalue: 20000
iter_size: 1
type: “RMSProp” #一种优化方法,挖坑,以后填
eval_type: “detection” #这里一定要写检测,默认为classification
ap_version: “11point” #计算AP的方法

  1. 训练时出错!
    (1)math_functions.cpp:250 Check failed: a (=b (0 vs -1.19209e-007)
    https://blog.csdn.net/house_s/article/details/82502938
    1.找到math_functions.cpp,并打开第一个路径为~/caffe/src/caffe/util的math_functions.cpp
    2.找到第250行出错的地方,双斜杠屏蔽
    3.重新在caffe-ssd路径下make py
    (2)training error: Data layer prefetch queue empty
    https://blog.csdn.net/LuohenYJ/article/details/88416180
    这种问题出现通常是注释掉 CHECK_LE(a, b) 出现Data layer prefetch queue empty。导致程序出现死循环。
    解决办法修改caffe-ssd/src/caffe/util/sampler.cpp,如下面修改代码所示//renew注释下,加入两个判断,使得bbox长宽不要越界。
  // Figure out bbox dimension.
  float bbox_width = scale * sqrt(aspect_ratio);
  float bbox_height = scale / sqrt(aspect_ratio);
 
  //renew
  if(bbox_width>=1.0)
  {
    bbox_width=1.0;
  }
  if(bbox_height>=1.0)
  {
    bbox_height=1.0;
  }
  
  // Figure out top left coordinates.
  float w_off, h_off;
  caffe_rng_uniform(1, 0.f, 1 - bbox_width, &w_off);
  caffe_rng_uniform(1, 0.f, 1 - bbox_height, &h_off);

!! 记得 make py
(3)Check failed: error == cudaSuccess (2 vs. 0) out of memory
https://blog.csdn.net/menglanzeng/article/details/97616685
我把train.prototxt中第50行的batch_size改为1

  data_param {
    source: "trainval_lmdb/"
    batch_size: 1
    backend: LMDB
  }
  1. 继续训练
    https://blog.csdn.net/baidu_32173921/article/details/72470019
    复制train.sh并重命名为train_resume.sh。
更改
-weights="mobilenet_iter_73000.caffemodel" \
为:
-snapshot="snapshot/mobilenet_iter_XXXX.solverstate" \

这里XXXX是你以前停止训练的迭代次数。
如果您不知道要XXXX运行

ls -ltr snapshot/

则可以在底部找到最后的迭代。

然后接着上次训练

./train_resume.sh

理论上可以,但没成功。

3.测试

  1. 合并bn层
    在caffe根目录/examples/MobileNet-SSD下
python2 merge_bn.py --model ./example/MobileNetSSD_deploy.prototxt --weights ./snapshot/mobilenet_iter_10000.caffemodel 

运行以下命令,MobileNet-SSD中多出 no_bn.prototxt 和 no_bn.caffemodel,这就是我们想要获得的模型文件和参数文件。

  1. 修改demo.py
caffe_root = '/home/shs/caffe-ssd/'
……
#net_file= 'deploy.prototxt'
net_file= 'no_bn.prototxt'  
#caffe_model='mobilenet_iter_73000.caffemodel'  
caffe_model='no_bn.caffemodel'
#test_dir = "images" #测试的就是images文件夹里的图片
test_dir = "images"

……

CLASSES = ('background','p','d','w')

注意:测试的时候,终端运行时按回车键切换下一张图片,测完images文件夹里所有图片就退出终端了,要是点叉号关窗口,终端就退不出去了,Ctrl+C也不好使。

  1. 查看mAP
    先把solver_test.prototxt修改地址
train_net: "example/MobileNetSSD_train.prototxt"
test_net: "example/MobileNetSSD_test.prototxt"

修改test.sh

#../../build/tools/caffe train -solver="solver_test.prototxt" \
../caffe-ssd/build/tools/caffe train -solver="solver_test.prototxt" \
./test.sh

查看loss值和detection_eval(mAP)评测模型效果

4.可视化

  1. 训练模型时保存log日志文件
    https://blog.csdn.net/zxyhhjs2017/article/details/84963012?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-2
    https://blog.csdn.net/xunan003/article/details/73017436

修改train.sh

#!/bin/sh
if ! test -f example/MobileNetSSD_train.prototxt ;then
	echo "error: example/MobileNetSSD_train.prototxt does not exist."
	echo "please use the gen_model.sh to generate your own model."
        exit 1
fi
mkdir -p snapshot
export GLOG_logtostderr=0
export GLOG_log_dir='../MobileNet-SSD/' #log存放位置
#../../build/tools/caffe train -solver="solver_train.prototxt" \
../caffe-ssd/build/tools/caffe train -solver="solver_train.prototxt" \
-weights="mobilenet_iter_73000.caffemodel" \
-gpu 0

训练完成后发现在我们保存的目录下生成了两个上锁log文件caffe.INFO和caffe.ubuntu.root.log.INFO.20170611-103712.5383。点击打开后我们可以看到我们所训练的日志文件。

  1. 利用生成的log文件绘制accuary loss曲线图
    首先绘制图,caffe中其实已经自带了这样的小工具 caffe-master/tools/extra/parse_log.sh 和caffe-master/tools/extra/extract_seconds.py还有 caffe-master/tools/extra/plot_training_log.py.example;拷贝以上文件到当前训练模型的目录下。

    然后我们到你保存的log文件目录下将1中保存的log文件解锁,解锁命令:

sudo chmod -R 777 ./caffe.ubuntu.root.log.INFO.20170611-103712.5383

解锁后我们就可以更改该log文件名为123.log(注意:要画图一定是.log文件,所以不改名不可以画)。

然后复制该xxx.log文件到你训练模型所在目录下。

然后就可以利用命令画图了:在模型所在目录下命令: ./plot_training_log.py.example y 0.png 123.log

./plot_training_log.py.example y 0.png 123.log 

0.png是你保存的绘制出的图片名称,123.log是你保存的log文件名称。
y表示的是你的所绘制的图片到底是什么图片,具体解释如下:

   y的数字代表意义(0~7):

   Supported chart types:    0: Test accuracy  vs. Iters    (准确率与迭代次数图)

                                       1: Test accuracy  vs. Seconds    (准确率与时间图)

                                       2: Test loss  vs. Iters    (测试损失与迭代次数图)

                                       3: Test loss  vs. Seconds    (测试损失与时间图)

                                       4: Train learning rate  vs. Iters    (学习率与迭代次数图)

                                      5: Train learning rate  vs. Seconds    (学习率与时间图)

                                      6: Train loss  vs. Iters    (训练损失与迭代次数图)

                                      7: Train loss  vs. Seconds   (训练损失与时间图)

  运行后生成的文件有:log-data.log.test和log-data.log.test和xxx.png
  1. test测试log日志文件保存与绘图类似过程

参考网址:
https://blog.csdn.net/la_fe_/article/details/84928958
https://blog.csdn.net/nimo_cap/article/details/82888196
https://cloud.tencent.com/developer/article/1020066
https://zhuanlan.zhihu.com/p/95904525?from_voters_page=true

你可能感兴趣的:(迫于科研的搬运工)