更新:找到了训练效果不好的原因:由于粗心把polyp拼写成了ployp。(泪流满面)
文中基本所有相关字段已经改正,如果有发现未改正的地方,欢迎在评论区指出,谢谢大家!~
常见的数据集有很多,例如coco数据集,他们都是封装好的,用于现成的网络的训练和预测过程,方便的同时也给想训练自己数据集的同学带来了困扰。使用基于tensorflow 的目标检测API的训练必须使用TFrecord这种数据集格式。
幸运的是,目标检测API提供了部分数据集格式转换的程序可供参考。
从一份VOC格式的文件开始,它是VOC2007年数据。数据目录如下:
准备好VOC数据集后,修改一些内容,将VOC数据集转换成TFrecord数据集。
这段代码在下面路径下的create_pascal_tf_record.py中。
当然,理解其内容后要修改一部分代码,包括:
之后将文件复制到API\reserch下,运行命令
Python create_pascal_tf_record.py --data_dir=D:\jupyter_notebook\VOC2007 --year=VOC2007 --set=train --output_path='pascal_train.record'
这里需要注意:将代码放到reserch文件目录下,而不是objection下,源代码中导入的包中要修改相应路径(必要时设置一下系统路径,chdir一下),这样比较方便。
这里将会遇到这个问题(超级烦人,解决费了好长时间):
导致这个问题的原因有很多:
之后,就得到了这个封装好的TFrecord:(命令行的路径带单引号就是这个结果)
知道了TFrecord长什么样子后,就要想办法把自己的数据转化成TFrecord了,而我的数据是之前用来进行基于语义分割的息肉检测,如下图:
可以说转化是相当麻烦了,一方面它不是VOC这种封装好的数据集,另一方面它还是掩码而不是候选框。
因此我想到了两种方案:
于是,我选择了1………
才怪,我选择了2。
首先我使用lableimg打个标签看看啥样。
lableIMG源码: https://github.com/tzutalin/labelImg
lableIMG封装好的:https://tzutalin.github.io/labelImg/ (建议点这)
尝试了几张图片,最终得到的都是些下面的固定格式的XML文件:
(于是我有个大胆的想法,通过遍历掩码的像素,得到候选框的边框,再将其写入文件,美滋滋。待会再试。)
然后将XML的信息提取出来转化成一个csv:
# -*- coding: utf-8 -*-
"""
将文件夹内所有XML文件的信息记录到CSV文件中(notebook可执行)
"""
import os
import glob
import pandas as pd
import xml.etree.ElementTree as ET
os.chdir('D:\\jupyter_notebook\\polyp\\code\\test\\')
path = 'D:\\jupyter_notebook\\polyp\\code\\test\\'
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)
print(xml_df)
xml_df.to_csv('tv_vehicle_labels.csv', index=None)
print('Successfully converted xml to csv.')
main()
这样的csv:
然后再通过CSV生成TFrecord.(,py文件,需要命令行执行:
命令:
python generate_tfrecord.py --csv_input=tv_vehicle_labels.csv --output_path=train.record)
需要注意的问题也如刚开始的那样。
看懂之后要改文件路径和相关参数,简单看看就能懂的,我就不一点点说了
# -*- coding: utf-8 -*-
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
#注意将对应的label改成自己的类别!!!!!!!!!!
def class_text_to_int(row_label):
if row_label == 'dog':
return 1
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('D:\\jupyter_notebook\\polyp\\code\\test\\images')
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()
最后就得到了这个训练集的record文件。
我的路径设置仅供参考:
以训练集代码为例,验证集改改变量名就ok:
由掩码转化成csv:
'''
train --> csv
'''
train_path='D:\\jupyter_notebook\\polyp\\data\\cvcvideoclinicdbtrainvalid\\train\\'
list = os.listdir(train_path)
lable_list = []
for f in range(0,len(list)):
filename=list[f]
if(filename.split('.')[0].endswith('mask')):
im = imageio.imread(train_path+filename)
minh=im.shape[1]
minw=im.shape[0]
maxh=0
maxw=0
for i in range(0,im.shape[0]): #288 高 h
for j in range(0,im.shape[1]): #384 宽 w
if(im[i][j]>0):
#print(im[i][j])
if(jmaxw): maxw=j
if(imaxh): maxh=i
if(minh==im.shape[1] & minw==im.shape[0] & maxh==0 & maxw==0):
minh=minw=maxh=maxw=0
value = (
str(filename.split('_mask')[0]+filename.split('_mask')[1]),
im.shape[1],
im.shape[0],
str('polyp'),
int(minw),
int(minh),
int(maxw),
int(maxh)
)
lable_list.append(value)
print(f,'has finished!')
column_name = ['filename', 'width', 'height', 'class', 'xmin', 'ymin', 'xmax', 'ymax']
lable_df = pd.DataFrame(lable_list, columns=column_name)
print(lable_df)
再运行之前所说的csv转化成TFrecord, 修改images的地址等参数,得到了TFrecord
命令:
python generate_tfrecord_train.py --csv_input=object_detection\data\train_labels.csv --output_path=object_detection\data\train_dataSet.record
转化的代码:
# -*- coding: utf-8 -*-
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
#注意将对应的label改成自己的类别!!!!!!!!!!
def class_text_to_int(row_label):
if row_label == 'polyp':
return 1
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('D:\\jupyter_notebook\\API\\research\\object_detection\\images\\train\\')
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()
运行:
最终得到了:训练集和验证集(这里的名字之前是为了测试集,后来发现要准备验证集,就作为验证集了,反正数据多,不怕)