1.配置 caffe-ssd
######Tips: 因为之前单纯配置过caffe,所以相关的依赖包都已经有下载了,如果你的电脑还没有安装过caffe,可以先移步至:Ubuntu 16.04 下用 cmake 安装 caffe 将其中第5步中大量的依赖库下载完再回来继续这里的内容。
- 下载源码
github 地址: https://github.com/weiliu89/caffe
在命令行中输入:
git clone https://github.com/weiliu89/caffe
下载完以后会得到一个名为 caffe
的文件夹,我们进入这个文件夹然后在此路径下打开命令行输入:
git checkout ssd
来切换caffe的分支:
这时我们的example里面就会有一个名为 ssd 的文件夹。
此时我们新建名为 build
的文件夹然后打开 cmake 来编译 caffe-ssd:
mkdir build
cmake-gui
然后按如下步骤点击:
然后:
上述步骤完成后,进入cmake-gui编译完的build文件夹:
cd build
make -j3
这里 -j3 是表示三核并行编译,这个是根据你的电脑配置来的,若8核可以 -j7 或者 -j8。
这里并不需要做任何的文件修改,直接编译即可。编译完成后再编译python接口,
make pycaffe
输出:
然后将caffe-ssd中的 python 文件夹路径加入环境变量:
sudo gedit ~/.bashrc
在文件末尾加入:
export PYTHONPATH=/path/to/caffe/python
然后:
source ~/.bashrc
至此我们的 caffe-ssd 就配置完成了。
2.配置 MobileNet-ssd
MobileNet-SSD 是依赖于我们刚才配置的ssd 的。
github下载地址:https://github.com/chuanqi305/MobileNet-SSD
同样的,我们先下载源文件:
git clone https://github.com/chuanqi305/MobileNet-SSD
下载完以后是一个名为 MobileNet-SSD
的文件夹,其中 MobileNet-SSD/template
文件夹下有我们需要训练的 .prototxt 文件,我们需要整改网络,包括修改输入数据集文件夹的路径,输入图片的尺寸,输入的 batch_size 等等参数可以在这里修改。
然后在 MobileNet-SSD
文件夹下,通过 gen_model.sh 来将 template 文件夹里的文件转化成训练文件。我的数据集是识别2种目标,再加上背景,所以后面跟 3。 运行成功后会自动生成一个 example 的文件夹,里面包含的是训练所用的文件。
sh gen_model.sh num_class+1
3.制作自己的数据集
首先我们要有已经准备好的图片,以及对应的xml文件,格式跟 VOC 数据集的格式一样就可以了,这里若是需要自己标注可以用 labelImg 工具。
以我电脑中的文件为例:
我们将名为 JPEGImages 包含图片的文件夹, Annotations 包含 xml 真值文件的文件夹放入名为 pcdata 的文件夹中,新建 /ImageSets/Main/
这个文件夹。(Ps:这里这个名字是为了与 标准的VOC数据集保持一致,后面修改文件可以少修改一点内容,不过也可以用其他的路径,包括放在其他的地方,只要修改路径的时候小心,保证对应位置的路径正确就可以了。)
在准备好以上的数据文件以后,还要把数据集分成训练集和测试集,这里我们直接用一个python脚本 classify.py 来自己生成.txt文件,文件内容如下:
import os
import random
trainval_percent = 0.8 # 修改训练集与测试集比例,此时train:test=8:2
train_percent = 0.7 # train 占 trainval 中的 0.7 , 后面只用 trainval,所以这里这个数值不重要
fdir = '/home/t702/youben/mydata/ImageSets/Main/' # 修改对应路径
xmlfilepath = '/home/t702/youben/mydata/Annotations/' # 修改对应路径
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()
运行后就会在 /ImageSets/Main/
文件夹中出现下面4个txt文件:
以 test 为例, 里面就是随机分配的图片的名字前缀。
至此我们数据准备工作就做好了!
接下来就是将图片文件转化为训练用的 lmdb 文件了。
这一步主要是修改第一步中配置的 caffe-ssd 中 caffe/data/VOC0712
路径下,
create_data.sh
create_list.sh
labelmap_voc.prototxt
这三个文件夹的修改。这里我将改完的 labelmap_voc.prototxt 文件放在了pcdata 下, 改完的 create_data.sh,create_list.sh 放在了 MobileNet-SSD文件夹下(下面我重命名为:MobileNet-SSD-pc, 知识名称不一样,不耽误)
labelmap_voc.prototxt
这个文件主要是输入标签与文本的对应关系,以我自己的数据集为例,识别人与车,是两分类,还有一个背景,所以是一个3分类,在我的xml文件中的标签分别为 Pedestrian
和 Car
,里边的 name 要和你自己的数据集的 xml 文件名保持一致。所以内容改为下面就可以了:
item {
name: "background"
label: 0
display_name: "background"
}
item {
name: "Pedestrian"
label: 1
display_name: "Pedestrian"
}
item {
name: "Car"
label: 2
display_name: "Car"
}
这里我将改完的 labelmap_voc.prototxt 文件放在了pcdata 下(后面用到的时候,为了防止出错,路径改为绝对路径就可以了)
create_list.sh
这个文件主要是根据我们刚才的 /ImageSets/Main/
文件夹下的 4 个txt 文件 进一步生成转换 lmdb 需要用的形式, 为下一步 create_data.sh 文件的运行提供方便。 主要修改部分就是后面带有备注的几行。根据自己的情况修改对应路径及文件名称就可以了。
内容如下:
#!/bin/bash
root_dir=$HOME/youben/ # 改成caffe-ssd 的根目录
sub_dir=ImageSets/Main # 刚才新建的文件夹路径,用以读取刚才 classfiy.py 生成的 txt 文件
bash_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for dataset in trainval test train val # 刚才四个文件夹的名字,其实主要用的就是 test 和 trainval
do
dst_file=$bash_dir/$dataset.txt
if [ -f $dst_file ]
then
rm -f $dst_file
fi
for name in pcdata # pcdata 是我存放 JPEGImage 和 Annotations 的文件夹名称
do
if [[ $dataset == "test" && $name == "VOC2012" ]]
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\//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\//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
可以看见在 create_list.sh 所在的路径下会生成
train.txt, test.txt, trainval.txt, val.txt, test_name_size.txt
这五个txt 文件:
仍然以 test.txt 为例,其中内容为:
可以看见这里就是图片与对应 xml 路径的一一对应,以便后面读取。
create_data.sh
这里就是构建数据集的最后一步了。同上主要修改部分是我添加标注的几行:
内容如下:
cur_dir=$(cd $( dirname ${BASH_SOURCE[0]} ) && pwd )
root_dir="$HOME/youben/caffe" # 改成自己 caffe 的目录路径
cd $root_dir
redo=1
data_root_dir="$HOME/youben" # 改成自己 caffe 所在根目录
dataset_name="pcdata" # 修改成了我自己的文件名字
mapfile="/home/t702/youben/pcdata/labelmap_head.prototxt" # 上面 labelmap_head.prototxt 的绝对路径
anno_type="detection"
db="lmdb"
min_dim=0
max_dim=0
width=0
height=0
extra_cmd="--encode-type=jpg --encoded"
if [ $redo ]
then
extra_cmd="$extra_cmd --redo"
fi
for subset in test trainval
do
python $root_dir/scripts/create_annoset.py \
--anno-type=$anno_type \
--label-map-file=$mapfile \
--min-dim=$min_dim --max-dim=$max_dim --resize-width=$width --resize-height=$height \
--check-label $extra_cmd $data_root_dir \
/home/t702/youben/caffe/examples/MobileNet-SSD-pc/$subset.txt \ #create_list.sh 生成的 test.txt, trainval.txt 两个文件的绝对路径
/home/t702/youben/pcdata/$db/$dataset_name"_"$subset"_"$db \ # 生成 lmdb 文件的路径及名称
/home/t702/youben/caffe/examples/$dataset_name # 这里也对应改一下路径
done
根据上面的修改,会在 /home/t702/youben/pcdata/
对应路径下生成lmdb的文件夹:
其中会包含生成生成两个 lmdb 文件:
4.训练文件
将对应的 lmdb 文件路径加入刚才用 gen_model.sh 生成的 example 文件夹中的 train.prototxt 和 test.prototxt ,然后修改 solve_train.prototxt
中的训练超参数和路径,
最后修改 train.sh 设置好训练的caffe绝对路径及相应文件路径,再运行:
sh train.sh
就可以了。