Adience 数据集简介:
实例中的数据集为Adience数据集,Adience数据集包含26580张图片,总共含有2284个类,涉及的年龄范围有8个区间(0~2, 4~6, 8~13, 15~20, 25~32, 38~43, 48~53, 60~),并且这个数据集含有噪声、姿势、光照等变化,尽可能真实地去模拟现实生活的情景。
Adience数据集的地址为:链接:https://pan.baidu.com/s/12uiTKUueWpOPHkknz_mvPg
提取码:x8wf
文件目录与FLAGS设置:
FLAGS = tf.app.flags.FLAGS设置:
tf.app.flags.DEFINE_string('fold_dir', '../Folds/train_val_txt_files_per_fold/test_fold_is_0', '数据索引所在的文件夹')
tf.app.flags.DEFINE_string('data_dir', './aligned', '数据集所在的文件夹')
tf.app.flags.DEFINE_string('output_dir', '../Folds/Process_TFRecords/tesst_fold_is_0', '转换后 TFRecord 文件所在的位置')
tf.app.flags.DEFINE_string('train_list', 'age_train.txt', '训练数据集文件名列表')
tf.app.flags.DEFINE_string('valid_list', 'age_val.txt', '交叉验证数据集文件名列表')
tf.app.flags.DEFINE_integer('train_shards', 10, '训练集需要划分的TFRecords文件数目')
tf.app.flags.DEFINE_integer('valid_shards', 2, '验证集需要划分的TFRecords文件数目')
tf.app.flags.DEFINE_integer('num_threads', 2, '处理数据所需要的线程数量')
FLAGS = tf.app.flags.FLAGS
TFRecords转换基本函数:
def _int64_feature(value):
if not isinstance(value, list):
value = [value]
return tf.train.Feature(int64_list=tf.train.Int64List(value=value))
def _bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def convert_to_example(filename, image, label, hight, width):
example = tf.train.Example(features=tf.train.Features(feature={
'image/class/label':_int64_feature(label),
'image/filename':_bytes_feature(str.encode(os.path.basename(filename))),
'image/encoded':_bytes_feature(image),
'image/hight':_int64_feature(hight),
'image/width':_int64_feature(width)
}))
return example
数据预处理(变换为 Tensorflow 专用格式 TFRecords )完整代码:
# -*- coding: utf-8 -*-
# @Time : 2019/3/16 8:50
# @Author : Chaucer_Gxm
# @Email : gxm4167235@163.com
# @File : Study_Data_Process.py
# @GitHub : https://github.com/Chaucergit/Code-and-Algorithm
# @blog : https://blog.csdn.net/qq_24819773
# @Software: PyCharm
import os
import random
import sys
import threading
import numpy as np
import tensorflow as tf
import json
from six.moves import xrange
from datetime import datetime
tf.app.flags.DEFINE_string('fold_dir', '../Folds/train_val_txt_files_per_fold/test_fold_is_0', '数据索引所在的文件夹')
tf.app.flags.DEFINE_string('data_dir', './aligned', '数据集所在的文件夹')
tf.app.flags.DEFINE_string('output_dir', '../Folds/Process_TFRecords/tesst_fold_is_0', '转换后 TFRecord 文件所在的位置')
tf.app.flags.DEFINE_string('train_list', 'age_train.txt', '训练数据集文件名列表')
tf.app.flags.DEFINE_string('valid_list', 'age_val.txt', '交叉验证数据集文件名列表')
tf.app.flags.DEFINE_integer('train_shards', 10, '训练集需要划分的TFRecords文件数目')
tf.app.flags.DEFINE_integer('valid_shards', 2, '验证集需要划分的TFRecords文件数目')
tf.app.flags.DEFINE_integer('num_threads', 2, '处理数据所需要的线程数量')
FLAGS = tf.app.flags.FLAGS
resize_hight = 256
resize_width = 256
class ImageCoder(object):
def __init__(self):
self._sess = tf.Session()
self._png_data = tf.placeholder(dtype=tf.string)
image = tf.image.decode_png(self._png_data, channels=3)
self._png_to_jpeg = tf.image.encode_jpeg(image, format='rgb', quality=100)
self._decode_jpeg_data = tf.placeholder(dtype=tf.string)
self._decode_jpeg = tf.image.decode_jpeg(self._decode_jpeg_data, channels=3)
cropped = tf.image.resize_images(self._decode_jpeg, [resize_hight, resize_width])
cropped = tf.cast(cropped, tf.uint8)
self._recoded = tf.image.encode_jpeg(cropped, format='rgb', quality=100)
def png_to_jpeg(self, image_data):
return self._sess.run(self._png_to_jpeg, feed_dict={self._png_data:image_data})
def resample_jpeg(self, image_data):
image = self._sess.run(self._recoded, feed_dict={self._decode_jpeg_data: image_data})
# image = self._sess.run(self._recoded, feed_dict={self._decode_jpeg_data: image_data})
return image
def find_images_files(list_file, data_dir):
print('从路径 %s 寻找数据集索引所指的具体文件名与标签'% list_file)
files_labels = [x.strip().split(' ') for x in tf.gfile.FastGFile(list_file, 'r').readlines()]
labels = []
filenames = []
for path, label in files_labels:
pic_file_patf = '%s/%s' %(data_dir, path)
if os.path.exists(pic_file_patf):
filenames.append(pic_file_patf)
labels.append(label)
# unique_labels = set(labels)
shuffled_index = list(range(len(filenames)))
# 定义随机种子,固定每次生成的随机数一样,进而打乱filenames的顺序
random.seed(12345)
random.shuffle(shuffled_index)
filenames = [filenames[i] for i in shuffled_index]
labels = [labels[i] for i in shuffled_index]
return filenames, labels
def _int64_feature(value):
if not isinstance(value, list):
value = [value]
return tf.train.Feature(int64_list=tf.train.Int64List(value=value))
def _bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))
def convert_to_example(filename, image, label, hight, width):
example = tf.train.Example(features=tf.train.Features(feature={
'image/class/label':_int64_feature(label),
'image/filename':_bytes_feature(str.encode(os.path.basename(filename))),
'image/encoded':_bytes_feature(image),
'image/hight':_int64_feature(hight),
'image/width':_int64_feature(width)
}))
return example
def is_png(filename):
return '.png' in filename
def process_image(filename, coder):
with tf.gfile.FastGFile(filename, 'rb') as f:
image_data = f.read()
if is_png(filename):
print('把PNG格式文件%s转换为JPEG格式' % filename)
image_data = coder.png_to_jpeg(image_data)
image = coder.resample_jpeg(image_data)
return image, resize_hight, resize_width
def process_image_files_batch(coder, thread_index, ranges, name, filenames, labels, num_shards):
num_threads = len(ranges)
num_shards_per_batch = int(num_shards / num_threads)
print('此线程分担 %d 个Shards。' % num_shards_per_batch)
shard_ranges = np.linspace(ranges[thread_index][0], ranges[thread_index][1], num_shards_per_batch + 1).astype(int)
print('Shard的范围为:', shard_ranges)
num_files_in_thread = ranges[thread_index][1] - ranges[thread_index][0]
print('线程中处理图片的数量为:', num_files_in_thread)
counter = 0
for s in xrange(num_shards_per_batch):
shard = thread_index * num_shards_per_batch + s
print('%s线程%d正在生成第%d个文件' % (name, thread_index, shard))
output_filename = '%s-%.5d-of-%.5d' % (name, shard, num_shards)
output_file = os.path.join(FLAGS.output_dir, output_filename)
# 定义书写 TFRecords 文件的方法
writer = tf.python_io.TFRecordWriter(output_file)
shard_counter = 0
files_in_shard = np.arange(shard_ranges[s], shard_ranges[s+1], dtype=int)
print('在Shard中的图片的索引范围为:', files_in_shard)
for i in files_in_shard:
# 获取单张图片的name和label
filename = filenames[i]
label = int(labels[i])
# 处理单张图片
image, hight, width = process_image(filename, coder)
example = convert_to_example(filename, image, label, hight, width)
writer.write(example.SerializeToString())
shard_counter += 1
counter += 1
writer.close()
print('%s 线程 %d 的第 %d 步已经写入 %d 张图片在 Batch 中' % (datetime.now(), thread_index, counter, num_files_in_thread))
sys.stdout.flush()
shard_counter = 0
def threading_process_images(name, filenames, labels, num_shards):
# 首先判断文件名的数量与标签的数量是否一致
assert len(filenames) == len(labels)
# 生成线程锁需要运行的节点
spacing = np.linspace(0, len(filenames), FLAGS.num_threads + 1).astype(np.int)
ranges = []
threads = []
for i in xrange(len(spacing) - 1):
ranges.append([spacing[i], spacing[i+1]])
print('在文件序列%s使用%d个线程' % (ranges, FLAGS.num_threads))
print('在此强制刷新缓存区')
sys.stdout.flush()
# 调用tf.train.Coordinator() 来创建一个线程协调器,管理启动的线程。
coord = tf.train.Coordinator()
# 声明一个用于处理图像基本操作的类
coder = ImageCoder()
threads = []
for thread_index in xrange(len(ranges)):
print('启动线程----%d' % thread_index)
args = (coder, thread_index, ranges, name, filenames, labels, num_shards)
t = threading.Thread(target=process_image_files_batch, args=args)
t.start()
threads.append(t)
coord.join(threads)
print('在%s, 完成了 %d 张图片的转换' % (datetime.now(), len(filenames)))
print('处理 %s 完毕' % name)
sys.stdout.flush()
def main(unuse_argv):
# 1.通过文件夹和txt文件获取文件名与标签值列表
filename_valid = '%s/%s' % (FLAGS.fold_dir, FLAGS.valid_list)
filename_train = '%s/%s' % (FLAGS.fold_dir, FLAGS.train_list)
print(filename_valid)
print('******************************************************')
print(filename_train)
# 2.定义读取文件夹中每个图像的函数,对数据集中的每个图像进行读取,返回每个图像的文件路径+名称,以及对应的标签
filename_valid, labels_valid = find_images_files(filename_valid, FLAGS.data_dir)
# 线程函数去执行转换格式
threading_process_images('valid_data', filename_valid, labels_valid, FLAGS.valid_shards)
filename_train, labels_train = find_images_files(filename_train, FLAGS.data_dir)
# 线程函数去执行转换格式
threading_process_images('train_data', filename_train, labels_train, FLAGS.train_shards)
# 5.创建书写 json 文件的文件夹
if os.path.exists(FLAGS.output_dir) is False:
print('创建文件夹%s' % FLAGS.output_dir)
os.makedirs(FLAGS.output_dir)
# 4.获取书写 json 文件的参数
len_labels_valid = len(labels_valid)
unique_labels_valid = set(labels_valid)
len_labels_train = len(labels_train)
unique_labels_train = set(labels_train)
out_file = os.path.join(FLAGS.output_dir, 'md.json')
md = {'num_valid_shards': FLAGS.valid_shards,
'num_train_shards':FLAGS.train_shards,
'valid_counts':len_labels_valid,
'train_counts':len_labels_train,
'timestamp': str(datetime.now()),
'nlabels':len(unique_labels_train)}
with open(out_file, 'w') as f:
json.dump(md, f)
print('数据转换完成')
if __name__ == '__main__':
tf.app.run()
运行过程与结果:
......
启动线程----0
此线程分担 5 个Shards。
启动线程----1
Shard的范围为: [ 0 1182 2364 3546 4728 5911]
此线程分担 5 个Shards。
Shard的范围为: [ 5911 7093 8275 9458 10640 11823]
线程中处理图片的数量为: 5912
train_data线程1正在生成第5个文件
线程中处理图片的数量为: 5911
train_data线程0正在生成第0个文件
在Shard中的图片的索引范围为: [5911 5912 5913 ... 7090 7091 7092]
在Shard中的图片的索引范围为: [ 0 1 2 ... 1179 1180 1181]
2019-03-16 13:14:11.869724 线程 0 的第 1182 步已经写入 5911 张图片在 Batch 中
train_data线程0正在生成第1个文件
在Shard中的图片的索引范围为: [1182 1183 1184 ... 2361 2362 2363]
2019-03-16 13:14:12.719736 线程 1 的第 1182 步已经写入 5912 张图片在 Batch 中
train_data线程1正在生成第6个文件
在Shard中的图片的索引范围为: [7093 7094 7095 ... 8272 8273 8274]
2019-03-16 13:14:47.542721 线程 0 的第 2364 步已经写入 5911 张图片在 Batch 中
train_data线程0正在生成第2个文件
在Shard中的图片的索引范围为: [2364 2365 2366 ... 3543 3544 3545]
2019-03-16 13:14:47.946224 线程 1 的第 2364 步已经写入 5912 张图片在 Batch 中
train_data线程1正在生成第7个文件
在Shard中的图片的索引范围为: [8275 8276 8277 ... 9455 9456 9457]
2019-03-16 13:15:23.292752 线程 0 的第 3546 步已经写入 5911 张图片在 Batch 中
train_data线程0正在生成第3个文件
在Shard中的图片的索引范围为: [3546 3547 3548 ... 4725 4726 4727]
2019-03-16 13:15:23.852874 线程 1 的第 3547 步已经写入 5912 张图片在 Batch 中
train_data线程1正在生成第8个文件
在Shard中的图片的索引范围为: [ 9458 9459 9460 ... 10637 10638 10639]
2019-03-16 13:15:58.858819 线程 0 的第 4728 步已经写入 5911 张图片在 Batch 中
train_data线程0正在生成第4个文件
在Shard中的图片的索引范围为: [4728 4729 4730 ... 5908 5909 5910]
2019-03-16 13:15:59.038819 线程 1 的第 4729 步已经写入 5912 张图片在 Batch 中
train_data线程1正在生成第9个文件
在Shard中的图片的索引范围为: [10640 10641 10642 ... 11820 11821 11822]
2019-03-16 13:16:34.308167 线程 0 的第 5911 步已经写入 5911 张图片在 Batch 中
2019-03-16 13:16:35.276127 线程 1 的第 5912 步已经写入 5912 张图片在 Batch 中
在2019-03-16 13:16:36.276222, 完成了 11823 张图片的转换
处理 train_data 完毕
数据转换完成