Create Object Detection Model on Windows 10

หลายคนคงเคยได้ยินการนำ Machine Learning มาใช้ในการตรวจจับวัตถุอย่างใน Self Driving Car ซึ่งเราสามารถทำการสร้าง Object Detection Model สำหรับงานที่เราต้องการได้ โดยเลือกใช้ Tensorflow Model ซึ่งจะต้องทำการติดตั้ง Protocol Buffer ( protobuf ) ซึ่งเป็นภาษาที่ใช้จัดการกับข้อมูลเชิงโครงสร้างแบบ Serializing Structured Data เทียบกับภาษา XML แล้วจะมีขนาดเล็กกว่า และทำงานได้เร็วกว่า


Requirement

Download

Flow Create Model

  1. Gathering Data
  2. Labeling Data
  3. Generate TFRecords for Training
  4. Configuring Training
  5. Training Model
  6. Exporting Inference Graph
  7. Testing Object Datector

Get Started

STEP1

  • ทำการถ่ายรูปวัตถุจำนวนหนึ่งจากกล้องโทรศัพท์มือถือ โดยควรให้พื้นหลังมีลักษณะแบบสุ่มและมีสภาพแสงที่แตกต่างกัน แล้วนำมาใส่ไว้ในโฟลเดอร์ images/ คำเตือนตั้งชื่อภาษาอังกฤษ
  • ทำการตรวจสอบ Resolution ของภาพ โดยคลิกขวา Properties แล้วเลือก Detail จะเห็นว่าภาพที่ถ่ายจากโทรศัพท์มือถือมี Resolution ของภาพใหญ่ไป 1280 x 1280 เราจะทำการลดขนาดของภาพให้เหลือ Resolution 600 x 600
  • ทำการสร้างไฟล์ transform_image_resolution.py สำหรับการลด Resolution ของภาพให้มีขนาดเล็กลง เพื่อทำให้การ Train ทำได้ไวขึ้น
from PIL import Image
import os
import argparse

def rescale_images(directory, size):
    for img in os.listdir(directory):
        im = Image.open(directory+img)
        im_resized = im.resize(size, Image.ANTIALIAS)
        im_resized.save(directory+img)

if __name__ == '__main__':
    parser = argparse.ArgumentParser(description="Rescale images")
    parser.add_argument('-d', '--directory', type=str, required=True, help='Directory containing the images')
    parser.add_argument('-s', '--size', type=int, nargs=2, required=True, metavar=('width', 'height'), help='Image size')
    args = parser.parse_args()
    rescale_images(args.directory, args.size)
  • ทำการรัน transform_image_resolution.py
# C:\> python transform_image_resolution.py -d images/ -s 600 600
  • ทำการตรวจสอบ Resolution ของภาพอีกครั้งจะเห็นว่าได้ Resolution ของภาพเป็น 600 x 600 ตามที่เราต้องการแล้ว
  • ทำการแบ่งภาพออกเป็น Train 80 ( images/train ) กับ Test 20 ( images/test )

STEP2

  • ทำการสร้าง Label ด้วย LabelImg โดยคลิก Open Dir แล้วเลือกโฟลเดอร์ train/
  • ทำการเลือกรูปภาพ คลิกขวา Create ReactBox แล้วทำการวาดกรอบเพื่อกำหนดวัตถุ
  • ทำการกำหนดชื่อของ Label Image แล้วคลิก OK คำเตือนตั้งชื่อภาษาอังกฤษ
  • ทำการกำหนดชื่อไฟล์ของ Image และ Label ให้เหมือนกัน แล้วคลิก Save
  • ทำให้ครบทุกไฟล์ในโฟลเดอร์ train/ และ test/
  • จะได้ไฟล์ที่อยู่ในโฟล์เดอร์ train/ และโฟลเดอร์ test/ ประมาณนี้
  • ทำการสร้างไฟล์ xml_to_csv.py สำหรับการแปลงไฟล์ XML ที่ได้จากการทำ Label เป็นไฟล์ CSV
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()
  • ทำการรัน xml_to_csv.py
# C:\> python xml_to_csv.py
  • จะได้ไฟล์ CSV ประมาณนี้
  • ทำการสร้างไฟล์ generate_tfrecord.py สำหรับการสร้าง TFRecords เพื่อแปลงข้อมูลจากการทำ Label ให้สามารถนำไป Train ด้วย Object Detector ได้
"""
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.DEFINE_string('image_dir', '', 'Path to images')
FLAGS = flags.FLAGS

# TO-DO replace this with label map
def class_text_to_int(row_label):
    if row_label == 'basketball':
        return 1
    elif row_label == 'shirt':
        return 2
    elif row_label == 'shoe':
        return 3
    else:
        return 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(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()
  • ทำการแก้ไขไฟล์ generate_tfrecord.py
# TO-DO replace this with label map
def class_text_to_int(row_label):
    if row_label == 'battery_bin':
        return 1
    elif row_label == 'bottle_bin':
        return 2
    elif row_label == 'orange_bin':
        return 3
    elif row_label == 'paper_bin':
        return 4
    else:
        return None
  • ทำการรัน generate_tfrecord.py
# C:\> python generate_tfrecord.py --csv_input=images\train_labels.csv --image_dir=images\train --output_path=train.record
# C:\> python generate_tfrecord.py --csv_input=images\test_labels.csv --image_dir=images\test --output_path=test.record
  • ทำการสร้างโฟลเดอร์ models/research/object_detection/training
  • ทำการสร้างไฟล์ training/labelmap.pbtxt
item {
    id: 1
    name: 'battery_bin'
}

item {
    id: 2
    name: 'bottle_bin'
}

item {
    id: 3
    name: 'orange_bin'
}

item {
    id: 4
    name: 'paper_bin'
}
  • ทำการคัดลอกไฟล์ samples/configs/faster_rcnn_inception_v2_pets.config มาไว้ในโฟลเดอร์ training/
  • ทำการคัดลอกไฟล์ train.record และ test.record มาไว้ในโฟลเดอร์ models/research/object_detection/training/
  • ทำการดาวน์โหลด COCO-Trained Models โดยเลือกเป็น faster_rcnn_inception_v2_coco
  • ทำการแตกไฟล์ไว้ในโฟลเดอร์ object_detection/
  • ทำการแก้ไขไฟล์ training/faster_rcnn_inception_v2_pets.config
...
model {
  faster_rcnn {
    num_classes: 4
...
train_config: {
  fine_tune_checkpoint: "C:/models/research/object_detection/faster_rcnn_inception_v2_coco_2018_01_28/model.ckpt"
...
train_input_reader: {
  tf_record_input_reader {
    input_path: "C:/models/research/object_detection/training/train.record"
  }
  label_map_path: "C:/models/research/object_detection/training/labelmap.pbtxt"
}
...
eval_input_reader: {
  tf_record_input_reader {
    input_path: "C:/models/research/object_detection/training/train.record"
  }
  label_map_path: "C:/models/research/object_detection/training/labelmap.pbtxt"
  shuffle: false
  num_readers: 1
}
...
  • ทำการคัดลอกไฟล์ models/research/object_detection/legacy/train.py มาไว้ในโฟลเดอร์ models/research/object_detection/
  • ทำการรัน train.py
# C:\models\research\object_detection> python train.py ^
 --logtostderr ^
 --train_dir=training/ ^
 --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config
  • จะทำการ Train Model ด้วย Tensorflow
  • ทำการตรวจสอบ Loss โดยใช้ Tensorboard เพื่ออ่านค่า ซึ่งจะถูกบันทึกทุก ๆ 5 นาที
# C:\models\research\object_detection> tensorboard --logdir=training
  • ทำการ Train Model จนกระทั่งได้ Loss เป็นที่พอใจแล้ว ให้ทำการ Terminate เพื่อหยุดการทำงาน โดยการกด Ctrl+C
  • ทำการตรวจสอบ Model ที่ได้จากการ Train
  • ทำการ Export Inference Graph เพื่อนำไปใช้ Run Model
# C:\models\research\object_detection> 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-latest ^
 --output_directory inference_graph
  • ทำการดาวน์โหลดไฟล์ object_detection_with_own_model.ipynb
  • ทำการรัน Jupyter Notebook
# C:\models\research\object_detection> jupyter notebook
  • จะทำการเปิด Jupyter Notebook ขึ้นมา แล้วคลิก object_detection_with_own_model.ipynb
  • ทำการแก้ไขไฟล์ object_detection_with_own_model.ipynb
MODEL_NAME = 'inference_graph'
PATH_TO_FROZEN_GRAPH = MODEL_NAME + '/frozen_inference_graph.pb'
PATH_TO_LABELS = 'training/labelmap.pbtxt'
  • คลิก Cell แล้วเลือก Run All

อ่านเพิ่มเติม : https://bit.ly/2WCjwof

Leave a Reply

Your email address will not be published. Required fields are marked *