这里我们尝试迁移训练Tensorflow的目标检测模型SSD MobileNet V2 COCO。首先看一下我们的所需要的文件目录:
第一个是labelImg图片标注软件,第二个是Tensorflow模型库,第三个是我们的项目文件。下面让我们以此来配置这些环境。
一、在Ubuntu上安装labelImg
首先下载仓库代码:
git clone https://github.com/tzutalin/labelImg.git
进入下载好的文件夹并安装一些依赖软件包:
sudo apt-get install pyqt5-dev-tools
sudo pip3 install -r requirements/requirements-linux-python3.txt
make qt5py3
至此安装好了,启动软件可以使用如下命令:
python3 labelImg.py
二、下载Tensorflow 模型库
git clone https://github.com/tensorflow/models.git
同样如果网络不好的话建议手动下载然后复制到相关目录。
三、安装相关的软件
这里需要注意的是使用pip还是pip3,如果你的电脑中有python2和python3两个版本,请注意选择对应的,我这里使用的是python 3.6。
# CPU版本
pip3 install tensorflow
pip3 install pillow
pip3 install jupyter
pip3 install matplotlib
pip3 install lxml
鉴于之前安装OpenVINO时已经安装了Tensorflow,所以这里可能显示已经安装了。
如果你想安装Tensorflow GPU版本,可以使用以下命令并配置CUDA:
# GPU版本
pip3 install tensorflow-gpu
到这个网址下载最新的Protobuf库,比如说protoc-3.11.1-linux-x86_64.zip,然后放在models/research目录下解压:
unzip protoc-3.11.1-linux-x86_64.zip
然后运行编译过程,注意在目录models/research目录下:
./bin/protoc object_detection/protos/*.proto --python_out=.
在本地运行时,models/research和models/research/slim目录需要添加到PYTHONPATH,可以通过在目录models/research下运行命令:
export PYTHONPATH=$PYTHONPATH:`pwd`:`pwd`/slim
需要注意的是每次打开新终端时,都要输入这个命令,想方便的话可以将上面两个目录的绝对路径添加到~/.bashrc文件的末尾。
然后可以测试一下安装是否成功:
python3 object_detection/builders/model_builder_test.py
出现以下输出说明安装成功:
因为models目录里有太多其他的文件了,我们只需要用到目标检测模块,所以搭建好环境之后我们自己新建一个项目文件夹,这样的话更加清楚文件的结构。
首先新建Object-Detection,然后将models/research中的object_detection文件夹和slim文件夹复制一份到Object-Detection文件夹中。
四、数据集制作
在Object_Detection/object_detection/data目录下新建一个文件夹VOC2007,文件名可以自己设定,接着在这个文件夹中新建4个文件夹,分别为JPEGImages,Annotations,ImageSets,Tools。搜集好的图片放在JPEGImages目录下,标注后的数据保存在Annotations目录下。
首先我们在网上搜集了三个类别的图片,分别是人、汽车和树,每个类别各50张。由于一开始的图片大小不统一,为了方便操作,我们用美图秀秀批处理助手把这些图片都转成了统一大小的图片了,然后我们把这些原图片放在JPEGImages目录里。当然也可以通过脚本转换。
在使用标注软件之前,我们需要把图片的文件名格式统一化,这样标注文件的名字也会同样具有统一的格式,这样的话就方便后面写程序处理,为此我们在Tools文件夹中已经写一个batch_rename.py脚本。
#!/usr/bin/python3
# -*- coding:utf8 -*-
import os
import sys
class BatchRename():
def __init__(self):
#给定目标目录
self.path = '../JPEGImages'
def rename(self):
filelist = os.listdir(self.path)
total_num = len(filelist)
print ("total_num : %d" % total_num)
i = 1
for item in filelist:
if item.endswith('.jpg'):
n = 4 - len(str(i))
src = os.path.join(os.path.abspath(self.path), item)
dst = os.path.join(os.path.abspath(self.path), str(0)*n + str(i) + '.jpg')
try:
os.rename(src, dst)
print ('converting %s to %s ...' % (src, dst))
i = i + 1
except:
continue
if __name__ == '__main__':
demo = BatchRename()
demo.rename()
运行该脚本,可以统一图片的文件名。接着我们启动labelImg软件,进入到labelImg目录,终端输入:
python3 labelImg.py
软件启动后,我们可以设定打开的图片文件目录为之前的JPEGImages,输出保存的目录为Annotations,然后按w按键,会出现十字,然后按住鼠标左键,拖动,直到将全部目标包括在内,注意,选择区域尽量小。然后放开鼠标,在文本框中输入类别名称,比如:tree。
然后点击save保存。接着可以点击Next Image下一张,以此类推来进行图片标注。
标注好以后,为了训练,我们需要将数据集分成训练集、验证集和测试集。为此,我们先在ImageSets目录下新建一个Main文件夹,然后用我们写的脚本来自动生成这些数据集的文件名列表,运行data_split.py脚本,将会在Main目录生成test.txt,train.txt,val.txt,trainval.txt四个文件。其中,train.txt是用来训练的数据集文件名列表,而val.txt是用来验证的数据集文件名列表,其实在我们训练自定义模型的时候,只需要这两个文件。
#!/usr/bin/python3
# -*- coding:utf-8 -*-
import os
import random
trainval_percent = 0.9 # trainval占总数的比例
train_percent = 0.8 # train占trainval的比例
xmlfilepath = '../Annotations'
txtsavepath = '../ImageSets/Main'
total_xml = os.listdir(xmlfilepath)
num = len(total_xml)
lis = range(num)
tv = int(num * trainval_percent)
tr = int(tv * train_percent)
trainval = random.sample(lis, tv)
train = random.sample(trainval, tr)
ftrainval = open(txtsavepath + '/trainval.txt', 'w')
ftest = open(txtsavepath + '/test.txt', 'w')
ftrain = open(txtsavepath + '/train.txt', 'w')
fval = open(txtsavepath + '/val.txt', 'w')
for i in lis:
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()
ftest.close()
ftrain.close()
fval.close()
在object_detection/data路径下新建barrier_detection_label_map.pbtxt文件,编辑以下内容:
item {
name: "person"
id: 1
display_name: "person"
}
item {
name: "car"
id: 2
display_name: "car"
}
item {
name: "tree"
id: 3
display_name: "tree"
}
表明我们需要检测三类物体,分别是人、车和树,对应的ID分别为1、2、3。
五、模型转换
由于此数据集是我们自己制作的,保存格式模仿了PascalVoc(与ImageNet采用的格式相同),而tensorflow提供了将PascalVoc格式的数据集转换成tfrecored格式的脚本,路径为Object_Detection/object_detection/dataset_tools/create_pascal_tf_record.py,我们直接修改一下使用就好了,这也是为什么之前我们要创建对应的文件夹的原因。修改的关键主要使各个文件的路径,你可以输出一些看一下是否正确,这里给出修改后的文件和源文件使用diff命令的结果,可以仔细对照:
85,88c85
< #img_path = os.path.join(data['folder'], image_subdirectory, data['filename'])
< print("data['folder']", data['folder'])
< print("data['filename']", data['filename'])
< img_path = os.path.join('VOC2007', data['folder'], data['filename'])
---
> img_path = os.path.join(data['folder'], image_subdirectory, data['filename'])
90,92d86
< print("dataset_directory:", dataset_directory)
< print("img_path:", img_path)
< print("full_path:", full_path)
171c165
< FLAGS.set + '.txt')
---
> 'aeroplane_' + FLAGS.set + '.txt')
接下来你可以在命令行运行这些转换的脚本,但是因为对应的命令较长,为了方便我们把运行的命令也写成一个脚本create_tfrecord.sh,内容如下:
python3 object_detection/dataset_tools/create_pascal_tf_record.py \
--label_map_path=object_detection/data/barrier_detection_label_map.pbtxt \
--data_dir=object_detection/data --year=VOC2007 --set=train \
--output_path=object_detection/data/barrier_train.record
python3 object_detection/dataset_tools/create_pascal_tf_record.py \
--label_map_path=object_detection/data/barrier_detection_label_map.pbtxt \
--data_dir=object_detection/data --year=VOC2007 --set=val \
--output_path=object_detection/data/barrier_val.record
然后将其放入Object_Detection目录,注意这个脚本中的文件路径,特别是反斜杠之后没有空格,我就因为这个栽了大坑,如果你之前设置的不一样的话需要对应修改。我们为脚本添加执行权限然后运行:
chmod +x create_tfrecord.sh
./create_tfrecord.sh
这样就能在目录Object_Detection/object_detection/data目录生成两个数据文件:barrier_train.record和barrier_val.record。
六、模型训练
在Object_Detection/object_detection目录下新建ssd_mobilenet目录,将下载好解压的文件放入这个目录。将这个目录里的管道文件pipeline.config复制一份并更名为pipeline_2018_03_29.config,对新的文件做以下修改:
修改类别数:
num_classes: 5
修改训练模型位置,建议使用绝对路径:
fine_tune_checkpoint: "/<yourpath>/Object_Detection/object_detection/ssd_mobilenet/ssd_mobilenet_v2_coco_2018_03_29/model.ckpt"
修改训练次数:
num_steps: 1000
修改训练数据位置:
train_input_reader {
# 标签映射配置文件路径
label_map_path: "/<yourpath>/Object_Detection/object_detection/data/barrier_detection_label_map.pbtxt"
tf_record_input_reader {
# 训练集路径
input_path: "/<yourpath>/Object_Detection/object_detection/data/barrier_train.record"
}
}
修改验证数据位置:
eval_input_reader {
label_map_path: "/<yourpath>/Object_Detection/object_detection/data/barrier_detection_label_map.pbtxt"
shuffle: false
num_readers: 1
tf_record_input_reader {
input_path: "/<yourpath>/Object_Detection/object_detection/data/barrier_val.record"
}
}
Tensorflow官方提供了训练的脚本,路径为
Object_Detection/object_detection/legacy/train.py,所以我们可以直接使用它来开始我们的迁移学习训练,在目录Object_Detection目录下新建一个训练的脚本文件train.sh,并写入以下内容:
# 如果不存在这个路径,就递归地创建它
if [ ! -d "object_detection/ssd_mobilenet/train_logs" ]; then
mkdir -p object_detection/ssd_mobilenet/train_logs
fi
# 设置管道配置文件的路径
PIPELINE_CONFIG_PATH=object_detection/ssd_mobilenet/pipeline_ssd_mobilenet_v2_coco_2018_03_29.config
# 设置模型训练过程中产生的记录文件的存放位置
TRAIN_LOGS=object_detection/ssd_mobilenet/train_logs
# 运行train.py文件
python3 object_detection/legacy/train.py \
--logtostderr \
--train_dir=$TRAIN_LOGS \
--pipeline_config_path=$PIPELINE_CONFIG_PATH
文件夹train_logs中存放模型训练过程中产生的记录文件,可以用来导出我们需要的模型。然后运行脚本就可以开始训练:
./train.sh
可以在训练的时候可视化训练过程,新开一个终端,在Object_Detection目录下运行:
tensorboard --logdir=object_detection/ssd_mobilenet/train_logs
在浏览器打开http://localhost:6006,即可看到loss等信息的实时变化。
七:导出模型
进入train_logs目录,可以看到一些文件如下:
仍然可以用Tensorflow官方的脚本导出训练好的模型,该脚本路径为
object_detection/export_inference_graph.py
在Object_Detection目录下新建一个脚本export_model.sh,写入以下内容:
# 如果不存在这个路径,就递归地创建它
if [ ! -d "object_detection/ssd_mobilenet/output_inference_graph" ]; then
mkdir -p object_detection/ssd_mobilenet/output_inference_graph
fi
# 运行export_inference_graph.py文件
python3 object_detection/export_inference_graph.py \
--input_type image_tensor \
--pipeline_config_path object_detection/ssd_mobilenet/pipeline_ssd_mobilenet_v2_coco_2018_03_29.config \
--trained_checkpoint_prefix object_detection/ssd_mobilenet/train_logs/model.ckpt-100 \
--output_directory object_detection/ssd_mobilenet/output_inference_graph
然后运行:
./export_model.sh
导出后的文件内容和我们下载的预训练模型类似,至此,我们自己的模型已经训练完成。在此基础上你可以像之前那样将这个模型也转换成OpenVINO的IR格式文件。
留言