在ModelArts上用Caffe-SSD进行目标检测模型训练

本着不再当队长的原则,这学期的深度学习实践课进了别的同学的队伍,果然,当普通队员的感觉就是……真香!

今天服从组织安排,用华为云的ModelArts尝试跑一下Caffe框架下的SSD模型来进行目标检测。队友说,让我尽量试试,还给我发了一大堆文档,可以说是相当耐心了。认真学习。

首先是在ModelArts中创建一个GPU实例并编译好Caffe-SSD, 这里队友实在看不下去我编译时的弱智操作,帮我完成了这一步。。


准备数据集

虽然模拟电梯环境采集了一些数据,但是明显有很多重复的。

所以只能在寻找另外的方法,而网上很少有所需的数据,于是打算自己爬图片做标注后用于训练。

获取图片

爬取谷歌图片

打算用googleimagesdownload工具

由于图片数量较多,还需要安装chromedriver, 我的谷歌版本时版本 78.0.3904.97,下载对应版本, 放在图片存放路径的文件夹中,切换到目录运行命令:

googleimagesdownload -k "电动车" -l 300 --chromedriver="./chromedriver

然后就开始自动下载啦~~~

图片预处理

筛选出符合要求的图片后,接下来进行数据增强。一方面是为了增加样本量,另一方面能够提高模型的泛化能力。

由于大小不一,先统一转为500*500

1
2
3
4
5
6
7
8
9
10
11
12
13
14
from PIL import Image
import os.path
import glob
def convertjpg(jpgfile,outdir,width=500,height=500):
img=Image.open(jpgfile)
try:
new_img=img.resize((width,height),Image.BILINEAR)
new_img.save(os.path.join(outdir,os.path.basename(jpgfile)))
except Exception as e:
print(e)


for jpgfile in glob.glob("C:/Users/18771/Desktop/emotor_1/*.jpg"):
convertjpg(jpgfile,"C:/Users/18771/Desktop/emotor_2")

处理完其实已经没多少数据了,应该多爬一点的..

接下来可以用labelImg标注数据了,我已经是个熟练工了。。感觉触摸板都要摸烂了。。

生成LMDB数据集

将数据集划分下训练集、测试集和验证集

按VOC标准建好目录结构,把数据传到ModelArts上面

ImageSets里Main文件夹,用到4个文件:

  • train.txt 是用来训练的图片文件的文件名列表
  • val.txt是用来验证的图片文件的文件名列表
  • trianval.txt是用来训练和验证的图片文件的文件名列表

  • test.txt 是用来测试的图片文件的文件名列表

用脚本生成训练集和测试集,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
import os
import random

trainval_percent = 0.8 # 修改训练集与测试集比例,此时train:test=8:2
train_percent = 0.7 # train 占 trainval 中的 0.7 , 后面只用 trainval,所以这里这个数值不重要
fdir = '/home/ma-user/work/caffe/data/VOC1227/VOCdevkit/VOC1227/ImagesSets/Main/' # 修改对应路径
xmlfilepath = '/home/ma-user/work/caffe/data/VOC1227/VOCdevkit/VOC1227/Annotations/label' # 修改对应路径
txtsavepath = fdir
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)

ftrainval = open(fdir + 'trainval.txt', 'w')
ftest = open(fdir + 'test.txt', 'w')
ftrain = open(fdir + 'train.txt', 'w')
fval = open(fdir + '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()

接下来引用分好的dataset建立list文件,改下create_list.sh中的路径, 这个文件是从VOC0712中拷贝过来的,记得注释掉[[ \$dataset == “test” && \$name == “VOC1227” ]] 不然无法生成test

文件内容详解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
#!/bin/bash

root_dir=/home/ma-user/work/caffe/data/VOC1227/VOCdevkit
sub_dir=ImagesSets/Main
bash_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for dataset in trainval test
do
dst_file=$bash_dir/$dataset.txt
if [ -f $dst_file ]
then
rm -f $dst_file
fi
for name in VOC1227
do
//if [[ $dataset == "test" && $name == "VOC1227" ]]
//then
//continue
//fi
echo "Create list for $name $dataset..."
dataset_file=$root_dir/$name/$sub_dir/$dataset.txt

img_file=$bash_dir/$dataset"_img.txt"
cp $dataset_file $img_file
sed -i "s/^/$name\/JPEGImages\/image\//g" $img_file
sed -i "s/$/.jpg/g" $img_file

label_file=$bash_dir/$dataset"_label.txt"
cp $dataset_file $label_file
sed -i "s/^/$name\/Annotations\/label\//g" $label_file
sed -i "s/$/.xml/g" $label_file

paste -d' ' $img_file $label_file >> $dst_file

rm -f $label_file
rm -f $img_file
done

# Generate image name and size infomation.
if [ $dataset == "test" ]
then
$bash_dir/../../build/tools/get_image_size $root_dir $dst_file $bash_dir/$dataset"_name_size.txt"
fi

# Shuffle trainval file.
if [ $dataset == "trainval" ]
then
rand_file=$dst_file.random
cat $dst_file | perl -MList::Util=shuffle -e 'print shuffle(<STDIN>);' > $rand_file
mv $rand_file $dst_file
fi
done

接下来根据建好的list文件,生成lmdb文件用于之后的训练

需要export一下openblas的路径

1
2
3
4
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/ma-user/anaconda2/lib
source ~/.bashrc
echo 'export LD_LIBRARY_PATH=/home/ma-user/work/OpenBLAS:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc

然后调用convert_annoset生成lmdb文件

1
2
3
4
5
/home/ma-user/work/caffe/build/tools/convert_annoset --anno_type=detection --encode_type=jpg --encoded=true --shuffle=true \
--label_map_file=/home/ma-user/work/caffe/data/VOC1227/labelmap_voc.prototxt \
/home/ma-user/work/caffe/data/VOC1227/VOCdevkit/ \
/home/ma-user/work/caffe/data/VOC1227/trainval.txt \
/home/ma-user/work/caffe/data/emotor_lmdb1227
1
2
3
4
5
/home/ma-user/work/caffe/build/tools/convert_annoset --anno_type=detection --encode_type=jpg --encoded=true --shuffle=true \
--label_map_file=/home/ma-user/work/caffe/data/VOC1227/labelmap_voc.prototxt \
/home/ma-user/work/caffe/data/VOC1227/VOCdevkit/ \
/home/ma-user/work/caffe/data/VOC1227/test.txt \
/home/ma-user/work/caffe/data/emotor_lmdb1227test

训练模型

修改模型中的相应参数,开跑。。

1
2
3
/home/ma-user/work/caffe/build/tools/caffe train \
-solver=/home/ma-user/work/caffe/MobileNet-SSD/solver_train.prototxt \
--weights=/home/ma-user/work/caffe/MobileNet-SSD/mobilenet_iter_73000.caffemodel

美滋滋地开跑了,结果loss全是0????

还得重新看数据集有什么问题。。弄了一天,人都傻了。。

后来反应过来是文件名写错了。




当房间烧成了废墟 我看见了更皎洁的月光

我看见了所有赐予我的幸福

所有转瞬即逝的欢乐

我看见了我违背的誓言

不曾释怀的痛楚

未能痊愈的伤痛

压抑住的泪水

我看见了我不曾哀悼的死亡

没有回应的祈祷

未曾开启的门 和始终开放的门

我看见了被我遗弃的爱人

未能实践的梦想

我看见了所有给予我却不能接受的一切

我看见了我期盼的却未能收到的来信

我看见了所有应该发生但从未发生的一切

——《尘与雪》