使用slim模型做自己的数据分类详细过程
使用GitHub上的模型
1. 在https://github.com/tensorflow/models下载model-master压缩包
-
本案例要使用slim文件夹中的train_image_classifier.py(可以将slim文件夹单独copy出来)
-
下载并制作自己的数据集放到创建的H:\Self-Study\PyCharm\test\slim\images目录中,这里做了五种分类,每类中有800个数据,共4000,其中按8:2分为train和test
-
将自己的数据集制作成tfrecord文件。编写generate_tfrecord.py脚本文件,代码如下(高亮部分分别为:指定数据集路径、生成标签文件名、生成tfrecord文件当时犯错的地方):
import tensorflow as tf
import os
import random
import math
import sys
# 验证集数量
_NUM_TEST = 800
# 随机种子
_RANDOM_SEED = 0
# 数据块
_NUM_SHARDS = 5
# 数据集路径
DATASET_DIR = "H:/Self-Study/PyCharm/test/slim/images/"
# 标签文件名字
LABELS_FILENAME = "H:/Self-Study/PyCharm/test/slim/images/labels.txt"
# 定义tfrecord文件的路径+名字
def _get_dataset_filename(dataset_dir, split_name, shard_id):
output_filename = 'image_%s_%05d-of-%05d.tfrecord' % (split_name, shard_id, _NUM_SHARDS)
return os.path.join(dataset_dir, output_filename) # 获取dataser_dir当前目录,并与output_filename组合成新目录
# 判断tfrecord文件是否存在
def _dataset_exists(dataset_dir):
for split_name in ['train', 'test']:
for shard_id in range(_NUM_SHARDS):
# 定义tfrecord文件的路径+名字
output_filename = _get_dataset_filename(dataset_dir, split_name, shard_id)
if not tf.gfile.Exists(output_filename): # 判断目录或文件是否存在
return False
return True
# 获取所有文件及分类
def _get_filenames_and_classes(dataset_dir):
directories = [] # 这是一个数据目录列表
class_names = [] # 这是一个分类名称列表
for filename in os.listdir(dataset_dir): # 用于返回指定的文件夹包含的文件或文件夹的名字的列表。这个列表以字母顺序。
path = os.path.join(dataset_dir, filename)
if os.path.isdir(path): # 判断path是不是一个目录,不是则为False
directories.append(path)
class_names.append(filename)
photo_filenames = [] # 文件目录列表
for directory in directories:
for filename in os.listdir(directory): # 每一类文件夹下的文件
path = os.path.join(directory, filename) # 每个文件的路径+名称
photo_filenames.append(path) # 添加到文件目录列表中
return photo_filenames, class_names
def int64_feature(values):
if not isinstance(values, (tuple, list)):
values = [values]
return tf.train.Feature(int64_list=tf.train.Int64List(value=values))
def bytes_feature(values):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[values]))
def image_to_tfexample(image_data, image_format, class_id):
return tf.train.Example(features=tf.train.Features(feature={
'image/encoded': bytes_feature(image_data),
'image/format': bytes_feature(image_format),
'image/class/label': int64_feature(class_id)
}))
def write_label_file(labels_to_class_names, dataset_dir, filename=LABELS_FILENAME):
labels_filename = os.path.join(dataset_dir, filename)
with tf.gfile.Open(labels_filename, 'wb') as f:
for label in labels_to_class_names:
class_name = labels_to_class_names[label]
f.write('%d:%s\n' % (label, class_name))
def _convert_dataset(split_name, filenames, class_names_to_ids, dataset_dir):
assert split_name in ['train', 'test']
# 计算每个数据块的数据量
num_per_shard = int(len(filenames) / _NUM_SHARDS)
with tf.Graph().as_default():
with tf.Session() as sess:
for shard_id in range(_NUM_SHARDS):
output_filename = _get_dataset_filename(dataset_dir, split_name,shard_id)
with tf.python_io.TFRecordWriter(output_filename) as tfrecord_writer:
start_ndx = shard_id * num_per_shard
end_ndx = min((shard_id + 1) * num_per_shard, len(filenames))
for i in range(start_ndx, end_ndx):
try:
sys.stdout.write('\r>> Converting image %d/%d shard %d' % (i + 1, len(filenames), shard_id))
sys.stdout.flush()
image_data = tf.gfile.FastGFile(filenames[i], 'rb').read()
class_name = os.path.basename(os.path.dirname(filenames[i]))
class_id = class_names_to_ids[class_name]
example = image_to_tfexample(image_data, b'jpg', class_id)
tfrecord_writer.write(example.SerializeToString())
except IOError as e:
print("Could not read: ", filenames[i])
print("Error: ", e)
print("Skip it\n")
sys.stdout.write('\n')
sys.stdout.flush()
if __name__ == '__main__':
# 判断tfrecord文件是否存在
if _dataset_exists(DATASET_DIR):
print("tfrecord文件已存在")
else:
photo_filenames, class_names = _get_filenames_and_classes(DATASET_DIR)
# 把分类转为字典格式,类似于{"houses": 2, "flowers": 0, ... , "guitars": 1}
class_names_to_ids = dict(zip(class_names, range(len(class_names))))
# 将数据切分为训练集和测试集
random.seed(_RANDOM_SEED)
random.shuffle(photo_filenames) # 打乱数据
training_filenames = photo_filenames[_NUM_TEST:]
testing_filenames = photo_filenames[:_NUM_TEST]
# 数据转换
_convert_dataset('train', training_filenames, class_names_to_ids, DATASET_DIR)
_convert_dataset('test', testing_filenames, class_names_to_ids, DATASET_DIR)
labels_to_class_names = dict(zip(range(len(class_names)),class_names))
write_label_file(labels_to_class_names, DATASET_DIR)
运行之后会产生:
-
到H:\Self-Study\PyCharm\test\slim\datasets\中修改文件
在dataset_factory.py中做两处内容增加:
myimages.py文件是在flowers.py文件的基础上修改而创建的,主要做两处修改如下:(分别是你生成的tfrecord的文件格式,以及自己设置的数据集train和test的大小)
-
在H:\Self-Study\PyCharm\test\slim文件夹中创建train.batwindows批处理文件
文件内容如下:
D:/Users/HZK/Anaconda3/envs/tensorflow-gpu/python H:/Self-Study/PyCharm/test/slim/train_image_classifier.py ^
--train_dir=H:/Self-Study/PyCharm/test/slim/model ^
--dataset_name=myimages ^
--dataset_split_name=train ^
--dataset_dir=H:/Self-Study/PyCharm/test/slim/images ^
--batch_size=10 ^
--max_number_of_steps=10000 ^
--model_name=inception_v3 ^
pause
第一行表示运行训练文件,路径为全路径
第二行表示模型存放位置
第三行为创建的myimages文件名
第四行为使用的训练集
第五行为数据集所在的位置
第六行为批次大小,默认为32,看个人GPU,我用10
第七行为训练次数,默认无限次
第八行为使用模型名称
-
运行train.bat,运行过程显示如下
会在model文件夹中产生如下文件: