Tersorflow目标检测入门的5个Demo

2018-12-21  本文已影响279人  随行的羊

Demo One

Tensorflow版本为1.12.0,Python3版本为3.6.3,Protoc版本为3.6.1

第一步,下载models,网址为:

git clone https://github.com/tensorflow/models.git

第二步,进入research目录,运行命令:

protoc object_detection/protos/*.proto --python_out=.

第三步,进入object_detection目录,运行命令:

jupyter notebook

就会在浏览器上启动一个服务器,在服务器呈现的目录中找到object_detection_tutorial.ipynb,进入编辑页面,点击运行所有:

object_detection_tutorial 运行所有

然后服务器就开始运行,它会到服务器上下载一个frozen_inference_graph.pb文件,大小29.1M。下载完之后,再点击一下运行所有:

检测成功

如果没有出现问题的话,就会检测成功。如果出现网络错误,可以点击“服务”,选择“重启并运行所有”就可以了。

第一个demo相对来说比较简单。


Demo Two

第一步,下载标注工具,下载地址:

https://github.com/tzutalin/labelImg/releases

第二步,进入到labelImg-1.8.0目录,运行命令:

python3 labelImg.py

这个时候就会启动标注工具,界面是这样的:

labelImg

在运行这个命令的时候,你可能会碰到很多问题,一般都是命令没有找到,只要安装相应的命令就可以了,我相信聪明的你一定会解决这些问题的。

第三步,准备两个文件夹,一个是test,一个是train,train里面有100张你要标注的jpg图片,比如你可以拿100张你自己的头像。然后使用labelImg标注,一张张标注会生成一个个XML文件。然后再搞另外10张图出来,标注一下,放到test目录下。标注的类别我们记为yourface,很重要,请记住这个类别。

第四步,需要把xml转成csv文件,使用的python代码为:

# xml2csv.py

import os
import glob
import pandas as pd
import xml.etree.ElementTree as ET

os.chdir('/Users/yangyh/Desktop/coreimage/train')   #1
path = '/Users/yangyh/Desktop/coreimage/train'   #2

def xml_to_csv(path):
    xml_list = []
   for xml_file in glob.glob(path + '/*.xml'):
        tree = ET.parse(xml_file)
        root = tree.getroot()
        for member in root.findall('object'):
            value = (root.find('filename').text,
                     int(root.find('size')[0].text),
                     int(root.find('size')[1].text),
                     member[0].text,
                     int(member[4][0].text),
                     int(member[4][1].text),
                     int(member[4][2].text),
                     int(member[4][3].text)
                     )
           xml_list.append(value)
    column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
    xml_df = pd.DataFrame(xml_list, columns=column_name)
    return xml_df


def main():
    image_path = path
    xml_df = xml_to_csv(image_path)
    xml_df.to_csv('yangyh_plate1_train.csv', index=None)   #3
    print('Successfully converted xml to csv.')


main()

注意将上述代码的#1、#2、#3更改一下。然后运行命令:

python3 xml2csv.py

同样的,把目录和名称改为test,再运行一次。可以打开csv文件,看一下这两个文件里面的数据,数据结构还是挺有趣的。如果运行时发现格式错误,就要检查一下是不是在复制黏贴的时候,格式是否出问题了。

第五步,进入第一个demo小练习的models文件夹中的research目录,运行命令:

python3 setup.py install

安装object_detection。

第六步,进入第一个demo小练习的models文件夹中的object_detection目录:

models/research/object_detection

创建images文件夹,将刚才的train和test目录中的jpg图片全部放进这个文件夹中。

第七步,还是在这个目录下,创建my_data目录,将刚才的test和train放进这个目录中,确保需要有csv文件。然后需要把csv文件转成record文件,用到的python代码为:

"""
    Usage:
    # From tensorflow/models/
    # Create train data:
    python generate_tfrecord.py --csv_input=data/train_labels.csv  --output_path=train.record
    # Create test data:
    python generate_tfrecord.py --csv_input=data/test_labels.csv  --output_path=test.record
    """
from __future__ import division
from __future__ import print_function
from __future__ import absolute_import

import os
import io
import pandas as pd
import tensorflow as tf

from PIL import Image
from object_detection.utils import dataset_util
from collections import namedtuple, OrderedDict

flags = tf.app.flags
flags.DEFINE_string('csv_input', '', 'Path to the CSV input')
flags.DEFINE_string('output_path', '', 'Path to output TFRecord')
FLAGS = flags.FLAGS


# TO-DO replace this with label map
def class_text_to_int(row_label):
    if row_label == 'yourface':    #1
        return 1
    else:
        return 0    #2


def split(df, group):
    data = namedtuple('data', ['filename', 'object'])
    gb = df.groupby(group)
    return [data(filename, gb.get_group(x)) for filename, x in zip(gb.groups.keys(), gb.groups)]


def create_tf_example(group, path):
    with tf.gfile.GFile(os.path.join(path, '{}'.format(group.filename)), 'rb') as fid:
        encoded_jpg = fid.read()
    encoded_jpg_io = io.BytesIO(encoded_jpg)
    image = Image.open(encoded_jpg_io)
    width, height = image.size

    filename = group.filename.encode('utf8')
    image_format = b'jpg'
    xmins = []
    xmaxs = []
    ymins = []
    ymaxs = []
    classes_text = []
    classes = []

    for index, row in group.object.iterrows():
        xmins.append(row['xmin'] / width)
        xmaxs.append(row['xmax'] / width)
        ymins.append(row['ymin'] / height)
        ymaxs.append(row['ymax'] / height)
        classes_text.append(row['class'].encode('utf8'))
        classes.append(class_text_to_int(row['class']))

    tf_example = tf.train.Example(features=tf.train.Features(feature={
                                                     'image/height': dataset_util.int64_feature(height),
                                                     'image/width': dataset_util.int64_feature(width),
                                                     'image/filename': dataset_util.bytes_feature(filename),
                                                     'image/source_id': dataset_util.bytes_feature(filename),
                                                     'image/encoded': dataset_util.bytes_feature(encoded_jpg),
                                                     'image/format': dataset_util.bytes_feature(image_format),
                                                     'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),
                                                     'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),
                                                     'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),
                                                     'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),
                                                     'image/object/class/text': dataset_util.bytes_list_feature(classes_text),
                                                     'image/object/class/label': dataset_util.int64_list_feature(classes),
                                                     }))
    return tf_example

def main(_):
    writer = tf.python_io.TFRecordWriter(FLAGS.output_path)
    path = os.path.join(os.getcwd(), 'images')    #3
    examples = pd.read_csv(FLAGS.csv_input)
    grouped = split(examples, 'filename')
    for group in grouped:
        tf_example = create_tf_example(group, path)
        writer.write(tf_example.SerializeToString())

    writer.close()
    output_path = os.path.join(os.getcwd(), FLAGS.output_path)
    print('Successfully created the TFRecords: {}'.format(output_path))

if __name__ == '__main__':
    tf.app.run()

如果你是从网上下载这个代码的,需要修改#2位置的代码。如果你想修改训练的jpg图片的目录地址,你可以修改#3。还记得之前类别不,#1要改为yourface。文件名取名为:generate_tfrecord.py。

然后运行命令:

python3 generate_tfrecord.py --csv_input=my_data/train/yangyh_plate1_train.csv --output_path=my_data/train/yangyh_plate1_train.record
#忽略此注释

获得train.record。同样的,继续运行命令:

python3 generate_tfrecord.py --csv_input=my_data/test/yangyh_plate1_test.csv --output_path=my_data/test/yangyh_plate1_test.record
#忽略此注释

获得test.record。

第八步,安装wget,不管你使用任何办法,只要能安装上wget命令就行了。然后下载一些文件,运行命令:

wget http://download.tensorflow.org/models/object_detection/ssd_mobilenet_v1_coco_11_06_2017.tar.gz

下载完成后,解压文件后,可以看到有不少文件。

第九步,在object_detection目录下创建my_training文件夹,输入命令:

vim object-detection.pbtxt

打开vim编辑器,输入内容:

item {
  id: 1
  name: 'yourface'    
}

注意你的类别名,有几个类别就填写几个item,保存退出。

第十步,从目录中找到ssd_mobilenet_v1_pets.config文件,目录为:

models/research/object_detection/samples/configs/ssd_mobilenet_v1_pets.config

取出来,放在object_detection目录下,打开,修改内容:

num_classes: 37 -> num_classes: 1
fine_tune_checkpoint: "PATH_TO_BE_CONFIGURED/model.ckpt" -> fine_tune_checkpoint: "ssd_mobilenet_v1_coco_11_06_2017/model.ckpt"
train_input_reader/input_path: "PATH_TO_BE_CONFIGURED/pet_faces_train.record-?????-of-00010" -> train_input_reader/input_path: "my_data/train/yangyh_plate1_train.record"
train_input_reader/label_map_path: "PATH_TO_BE_CONFIGURED/pet_label_map.pbtxt" -> train_input_reader/label_map_path: "my_training/object-detection.pbtxt"
num_examples: 1100 -> num_examples: 10 #test有几张图就填几张,我这里准备了10张。
eval_input_reader/input_path: "PATH_TO_BE_CONFIGURED/pet_faces_val.record-?????-of-00010" -> eval_input_reader/input_path: "my_data/test/yangyh_plate1_test.record"
eval_input_reader/label_map_path: "PATH_TO_BE_CONFIGURED/pet_label_map.pbtxt" -> eval_input_reader/label_map_path: "my_training/object-detection.pbtxt"
#忽略此注释

改完之后,保存退出。(注意,这个文件一旦编辑好了num_classes,下次就无法修改了,训练之前一定要慎重设置这个参数,考虑拓展性。)

第十一步,在object_detection目录下找到legacy目录,把里面的train.py拷贝一份到object_detection目录下,运行命令:

python3 train.py --logtostderr --train_dir=my_training/ --pipeline_config_path=ssd_mobilenet_v1_pets.config

执行命令的时候报错,提示:

ImportError:No module named nets

那我们需要安装一下slim,进入research/slim目录,运行:

python3 setup.py install

执行命令的时候报错,提示:

error: could not create 'build': File exists

然后在网址https://github.com/pachyderm/python-pachyderm/issues/20找到了解决问题的答案:

Yeah, I did actually. This is because of a case-insensitive file system and the BUILD file. You have to rename the BUILD file and adjust the references to it in setup.py
#忽略此注释

我们进入slim目录,将BUILD文件命名为BUILD1,然后执行命令:

python3 setup.py install

这样就成功了,其实我之前也成功过,采用不安装命令的方式,直接迁移目录,有兴趣的童鞋也可以试试。
然后,执行命令:

python3 train.py --logtostderr --train_dir=my_training/ --pipeline_config_path=ssd_mobilenet_v1_pets.config

就成功了,然后开始训练了,注意要把不相干的进程都关了,不然电脑卡死。
如果看到以下内容就表示训练进行中,设置的steps是200000步,你也可以设置小一点,只要到时候测试集的数据可以通过就OK。但是要注意,训练期间不要开其他的IDE,可能会影响训练,导致训练中止,比如说训练期间打开多个Android Studio,最好不要。


恭喜,成功了!

Demo Three

接着上一个练习,可以看到my_training文件夹中有很多文件:

my_training

我们需要把my_training中的模型文件转成pb文件。

第一步,进入到object_detection目录下,运行命令:

python3 export_inference_graph.py --input_type image_tensor --pipeline_config_path ssd_mobilenet_v1_pets.config --trained_checkpoint_prefix my_training/model.ckpt-4495 --output_directory mac_n_cheese_inference_graph/
#忽略此注释

注意参数my_training/model.ckpt-4495,运行成功后,会出现mac_n_cheese_inference_graph目录:


mac_n_cheese_inference_graph

其中,frozen_inference_graph.pb是我们需要的文件。

第二步,在object_detection目录下的test_images目录中加入几张之前没参与训练的图片,命名为image1~image7。

第三步,然后和第一个Demo一样,在object_detection目录下运行:

jupyter notebook
 (千万注意运行这个进行目标检测的时候,不要再进行GPU模型训练,否则GPU模型训练会报错。)

进入这个文件时,修改几个参数,我们不需要再从服务端下载model了,所以需要修改文件。

MODEL_NAME = 'ssd_mobilenet_v1_coco_2017_11_17' -> MODEL_NAME = 'mac_n_cheese_inference_graph'
MODEL_FILE删除
DOWNLOAD_BASE删除
PATH_TO_LABELS = os.path.join('data', 'mscoco_label_map.pbtxt') -> PATH_TO_LABELS = os.path.join('my_training', 'object-detection.pbtxt')
把Download Model整块代码删除
for i in range(1, 3) -> for i in range(1, 8)
#忽略此注释

第四步,改完之后,点击cell、run all,即可得到结果。


Demo Four

经过了前三个小练习,相信你已经跟我一样开始训练了。

但是我遇到了新的问题,我的电脑是iMac i5 3.4G HZ CPU,训练速度很慢,我算了一下,20万步大概要训练20多天,就是说训练100张图,训练完我头发都白了,肯定不成。那就试试GPU版本的吧!

这次请原谅我不厚道地换了个设备,使用Windows系统,系统参数如下:

Windows 10
CPU:i7-4770 3.40G HZ
内存:16G
GPU:NVIDIA GeForce GTX 750 Ti

从参数可以看出这个电脑的CPU虽然是i7,但是HZ数和iMac的HZ数是一样的,结果当我在Windows电脑上跑Tensorflow-CPU时,训练速度居然比在iMac上的慢,不得不感叹苹果硬件的牛逼。

但我现在决定使用GPU了。

《Win10 +VS2017+ python3.67 + CUDA10 + cuDNNv7.3.1 + tensorflow-gpu 1.12.0 最新版》这篇教程给了我很大的帮助。

第一步,安装一下Python3.6.7。

第二步,安装CUDA,按照教程来没什么问题,其中可以通过这个:查询GPU是否支持CUDA。我把安装路径改在了D盘,但是下载下来还是变成了C盘,不管它了,C盘就C盘。使用命令可以nvcc -V可以验证是否正确安装了CUDA。(有一个深坑一定要注意,就是安装的时候,按照默认的就好,选择精简模式,而不要手贱选自定义模式,否则出问题后果自负。)

第三步,下载cuDNN,按照教程来基本没什么问题,有一点需要注意,教程的路径是:

C:\ProgramData\NVIDIA GPU Computing Toolkit\v10

而你自己的路径可能是:

C:\ProgramData\NVIDIA GPU Computing Toolkit\v10.0

v10后面多了个.0,这个坑很深。我的Path就是因为写错了,导致运行时,一直报错:

ImportError: DLL load failed: The specified module could not be found.

第四步,安装Tensorflow-GPU,按照教程来应该没什么问题。他说安装tensorboard需要翻墙,我这边不用翻墙。我运行了一下pip list,发现和文中不太一样:

six                 1.11.0
slim                0.1
tensorboard         1.12.0
tensorflow-gpu      1.12.0
termcolor           1.1.0
Werkzeug            0.14.1
wheel               0.32.3

并没有tensorpack、terminado、testpath、threadpool。

第五步,运行:

import tensorflow as tf

应该没什么问题了。

第六步,将之前的命令跑一遍:

python train.py --logtostderr --train_dir=my_training/ --pipeline_config_path=ssd_mobilenet_v1_pets.config

注意是python而不是python3,因为在windows上只有python命令,虽然我使用的是Python3。
发现出问题了,报错信息:

Allocator (GPU_0_bfc) ran out of memory trying to allocate

查阅相关资料都说是batch_size设置太大了,大了就变小一点咯。
进入ssd_mobilenet_v1_pets.config这个配置文件,将batch_size:24改成batch_size:8,再重新运行,就没问题了!

效果呢,20万步只需要3天左右的时间!Amazing!Unbelievable!


Demo Five

接下来我们尝试采用多个分类,多个分类和单个分类的差别不是很大,主要的操作步骤还都是在《Tersorflow目标检测的第二个Demo小练习》这个当中。开始吧!

《Tersorflow目标检测的第二个Demo小练习》的第七步中generate_tfrecord.py文件需要修改一下代码,class_text_to_int已经变成了很多分类了:

if row_label == 'yourface':
    return 1
elif row_label == 'yourleg':
    return 2
else:
    return 0

然后修改object-detection.pbtxt文件,里面的item已经变成很多类别了:

item {
  id: 1
  name: 'yourface'    
}
item {
  id: 2
  name: 'yourleg'    
}

最后一处就是ssd_mobilenet_v1_pets.config这个文件了,修改代码:

num_classes: 37 -> num_classes: 2

然后继续训练吧。


总结:虽然完成了5个Demo,但离要完成的目标还很远,还有很多问题需要解决。

-------------------------------我是分割线-------------------------------

2018-12-21

上一篇下一篇

猜你喜欢

热点阅读