乐趣区

关于python:关于Tensorflow目标检测预训练模型的迁移学习

前言

对于 TF 的指标检测迁徙学习,我一开始是想通过 Tensorflow 提供的 API,用 JS 来实现的。然而官网岂但没有案例,网上也没有踩坑的博客,加之我又焦急要弄水印检测。

于是就在网上看了很多人用 python 实现的自定义训练,我也试过很多。运行的时候各种问题,不是短少模块,就是版本兼容问题说什么 convert ‘t’ to a tensor and failed,还有运行 Tensorboard 打不开等等各种问题。所以我把运行过程遇到的大小谬误,以及谬误起因,如何解决报错都记录了下来,上面内容有跳过后面的环境搭建。如果要残缺的从环境搭建,模型测试和接下来的迁徙学习,须要联合后面的两篇文章一起看。

数据集制作

指标检测的数据集就是对以往图片通过工具进行无休止的标注了,标注工具有很多,这里我应用的是 LableImg。地址:https://github.com/heartexlabs/labelImg,该工具曾经有发行版,标注会与图片生成绝对应的 xml 文件。为了前面的训练,能够将数据集分成 train(训练集)和 test(测试集),而后在我的项目的 “models\research\object_detection” 新建 images(名字自定,只是前面配置要用到)文件夹并放入其中。

数据处理

这里要通过脚本将 xml 和图片门路转成 xml,而后再将 xml 转为训练须要的 record 格局,在转换前须要在我的项目的 ”models\research\object_detection” 下新建 “training” (寄存训练配置,标注映射,训练日志)和 “inference_graph” (最初训练的模型),这里能够间接将国外博主 demo(TensorFlow-Object-Detection-API-Tutorial-Train-Multiple-Objects-Windows-10),会笼罩并携带这几个文件夹,如下。

1. 将 xml 文件转换为 csv 文件

1.1. 新建 xml_to_csv.py 放入上图目录下。

1.2. 代码编写

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


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():
    for folder in ['train','test']:
        image_path = os.path.join(os.getcwd(), ('images/' + folder))
        xml_df = xml_to_csv(image_path)
        xml_df.to_csv(('images/' + folder + '_labels.csv'), index=None)
        print('Successfully converted xml to csv.')


main()

1.3. 运行(胜利后会在 image 下生成两个 csv 文件)
python xml_to_csv.py

2. 将 csv 文件转换为 tfrecord 文件

2.1. 新建 generate_tfrecord.py 放入上图目录 (models\research\object_detection) 下。

2.2. 代码编写,这里要留神 class_text_to_int 函数的值须要批改标注的项曾经定义的映射值。

"""
Usage:
  # From tensorflow/models/
  # Create train data:
  python generate_tfrecord.py --csv_input=images/train_labels.csv --image_dir=images/train --output_path=train.record

  # Create test data:
  python generate_tfrecord.py --csv_input=images/test_labels.csv  --image_dir=images/test --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

from tensorflow.python.framework.versions import VERSION
if VERSION >= "2.0.0a0":
    import tensorflow.compat.v1 as tf
else:
    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('image_dir', '','Path to the image directory')
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 == 'nine':
        return 1
    elif row_label == 'ten':
        return 2
    elif row_label == 'jack':
        return 3
    elif row_label == 'queen':
        return 4
    elif row_label == 'king':
        return 5
    elif row_label == 'ace':
        return 6
    else:
        None


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(), FLAGS.image_dir)
    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.3. 运行,胜利后会在“models\research\object_detection”目录下生成两个 record 文件。

python generate_tfrecord.py --csv_input=images\train_labels.csv --image_dir=images\train --output_path=train.record
python generate_tfrecord.py --csv_input=images\test_labels.csv --image_dir=images\test --output_path=test.record

文件配置

在以下文件配置前,要确保指标检测预训练模型 (faster_rcnn_inception_v2_coco_2018_01_28) 曾经下载,如何下载和如何选取能够看后面文章,而后放入 “models\research\object_detection” 下。

1.labelmap.pbtxt

创立一个 pbtxt 后缀文件,放入“models\research\object_detection\training”, 没有“training”文件夹则创立,labelmap 存入与 generate_tfrecord.py 的标签映射相似。

2.faster_rcnn_inception_v2_pets.config

找到“research\object_detection\samples\configs”下的“faster_rcnn_inception_v2_pets.config”复制到“research\object_detection\training”下,也就是和下面文件一样, 最初还要批改以下配置。

第 9 行:num_classes 是类别个数,批改成本人的类别个数,对于 basketball, shirt, 和 shoe 的例子,num_classes=3,第 110 行:fine_tune_checkpoint 批改为:fine_tune_checkpoint : "E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/faster_rcnn_inception_v2_coco_2018_01_28/model.ckpt"

第 126 和 128 行:在 train_input_reader 局部, input_path 和 label_map_path 改为:input_path : "E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/train.record"

label_map_path: "E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/training/labelmap.pbtxt"

第 132 行:num_examples 个数批改成 \images\test 文件夹中的图片数量

第 140 和 142 行:在 eval_input_reader 局部,把 input_path 和 label_map_path 门路批改成:input_path : "E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/test.record"

label_map_path: "E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/training/labelmap.pbtxt"

(留神:批改门路中的”/”不要打成”//”或者”\”。以及”不要错打成’。此外,具体的行数可能会和本文对不上,但在左近不难找,或者参考视频。)

环境配置

因为后面曾经把根本的依赖包和工具都曾经装置了,从模型下载的库里的“三个环境变量”(特地留神一下,要联合上一篇一起操作)也配置了。官网的模型检测也能运行了。然而,迁徙学习还有点不太一样,须要的依赖更多一点,所以再操作一些配置。

1.slim 装置

在以后虚拟环境下切换目录到上一级,也就是 “models\research”,再进入 slim, 运行“python setup.py install”,当呈现“error: could not create ‘build’: 当文件已存在时,无奈创立该文件”报错时,须要将 slim 下的 BUILD 文件删除再运行 “python setup.py install”。

2.object-detection 装置

其实这个在后面演示官网例子的检测时就曾经装置了,这里就再提一下,因为很重要,并且再前面训练的时候抛出的异样也和这里无关,这个就前面再说吧。

开始训练

1. 创立 train.py

1.1. “train.py” 文件在 /object_detection/legacy 当中,把它放入到 /object_detection 中,在门路 \object_detection 下输出指令:

(object_dection) E:\4work\8python\1study\object_detection\object-detection-model\research\object_detection>python train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config

2. 关上 tensorboard

一个 Tensorflow 可视化工具,在后面装置 Tensorflow-GPU 时候也默认装置了,如果没有则 “pip install tensorboard”, 版本最好与 tensorflow 统一。通过指定训练 log 查看训练过程面板, 执行完后胜利的话会呈现端口号为 6006 的拜访地址,而后放到浏览器中就能够查看。这里我用谷歌拜访不了,放到火狐就能够了,起因是啥,目前也不晓得,如果各位也遇到打不开的状况能够多试几个浏览器。

(object_dection) E:\4work\8python\1study\object_detection\object-detection-model\research\object_detection>tensorboard --logdir=training

3. 报错汇总

这里的报错汇总是,开始执行训练时候,抛出的各种问题,有很多细节联合其余博客总结的,具体有哪些博客起源,我记不清就不放进去,如果你看到了,能够留言通知我,我再具体告之来处。

3.1. 报错:No module named ‘nets’

起因:models\research\slim 没有配置,也就是我后面提到的环境配置
办法:在以后环境下切换目录到 “models\research\slim” 下,运行“python setup.py install”,当呈现“error: could not create ‘build’: 当文件已存在时,无奈创立该文件”报错时,须要将 slim 下的 BUILD 文件删除再运行 “python setup.py install”。

3.2. 报错:NewRandomAccessFile failed to Create/Open: E:/4work/8python/1study/object_detection/object-detection-model/research/object_detection/labelmap.pbtxt : ϵͳ\udcd5Ҳ\udcbb\udcb5\udcbdָ\udcb6\udca8\udcb5\udcc4\udcceļ\udcfe\udca1\udca3 ; No such file or directory。

起因:faster_rcnn_inception_v2_pets.config 里 train_input_reader 下 label_map_path 门路写错了,导致没有找到文件。
办法:批改该门路即可。

3.3. 报错:Tried to convert ‘t’ to a tensor and failed. Error: Argument must be a dense tensor: range(0, 4) – got shape [4], but wanted []。

起因:通过查找后,终于在 github 的 issues 发现一个大佬说是 Python3 的兼容文件,他们很多是 python3.6 环境下降级 tensorflow 版本,比方从 1.4 到 1.6 报的谬误。
办法:把 research/object_detection/utils/learning_schedules.py 文件的 第 167-169 多增加一个 list(),这只是第一步,还有第二步而且很重,因为改完后马上执行训练,仍然会报整个谬误。

# # 批改 167 - 170
rate_index = tf.reduce_max(tf.where(tf.greater_equal(global_step, boundaries),
                                    range(num_boundaries),
                                    [0] * num_boundaries))
# # 成
rate_index = tf.reduce_max(tf.where(tf.greater_equal(global_step, boundaries),
                                    list(range(num_boundaries)),
                                    [0] * num_boundaries))

因为在训练中应用的 object-detection 还是之前编译的,当初批改了代码须要从新编译。目录切换到上一级 (research) 下,从新编译装置后再进行训练即可。

python setup.py build
python setup.py install

模型导出

通过一个早晨的训练,训练次数达 13 万多,损失值降到了根本小于 0.04, 按 ctrl+ c 终止训练。

1. 导出 Inference Graph

上面“model.ckpt-XXXX”中的“XXXX”批改为最高的数字(训练次数最高的那一个文件) 这个指令会在 \object_detection\inference_graph 文件夹中生成一个 frozen_inference_graph.pb 文件,也就是本人训练后的模型。

python export_inference_graph.py --input_type image_tensor --pipeline_config_path training/faster_rcnn_inception_v2_pets.config --trained_checkpoint_prefix training/model.ckpt-XXXX --output_directory inference_graph

模型测试

原本是想将训练的模型改为 js 版的,然而原文作者写了图片检测,视频流检测和网络摄像头实时检测的程序,所以这里就通过以下的两个脚本演示。尽管然而,脚本里有用了 cv2,上次装置原本就出了问题,所以这次还是屡次翻车,以下就是呈现的各种装置情况。

1. 报错:No module named ‘cv2’。
原本是通过 pip install opencv-python 下载的,然而电脑有个 星杀毒流 软件,又抛出 Could not install packages due to an OSError: [WinError 225] 无奈胜利实现操作,因为文件蕴含 * 毒或潜在的垃圾软件,当我卸载 RAV Lndpoint Protectio 后,后果还是报错:Could not build wheels for opencv-python which use PEP 517 and cannot be installed directly,我也尝试过网上说的降级 pip,用 conda 装置全都没用。最初关上 anaconda 面板,搜寻 “opencv” 挨个装置后,发现又呈现了新的问题。

2. 报错:’ImportError: DLL load failed: 找不到指定的模块 ’。
报错起因可能是版本不对,然而在 anaconda 中没找到降级 cv 版本的中央,无奈之下就手动下载 opencv-python 包进行装置,找到与本人零碎 (win 后携带参数) 和以后虚拟环境 python 版本 (cp 即 python 版本) 对应的安装包即可。

3. 测试图片指标检测

python Object_detection_image.py

4. 测试视频指标检测

python Object_detection_video.py

退出移动版