Target
- 二分类任务样本制作成标准TF格式(TFRecords)
- 读入TFRecords并展示图片
- 高效多线程读入TFRecords
Introduction
tensorflow/core/example/example.proto 中有详细的例子说明.
message Example {
Features features = 1;
};
简要说就是每个样本变成了一个key-value的字典形式, key为字符串,value可以是字符串, 整型, 浮点型. 不同类型的标签在TF中会非常容易的实现. 但是在Caffe中(-.-)..
Value的格式(注:Int为Int64)
- BytesList
- FloatList
- Int64List
tensorflow/core/example/feature.proto 中定义
// Containers to hold repeated fundamental values.
message BytesList {
repeated bytes value = 1;
}
message FloatList {
repeated float value = 1 [packed = true];
}
message Int64List {
repeated int64 value = 1 [packed = true];
}
// Containers for non-sequential data.
message Feature {
// Each feature can be exactly one kind.
oneof kind {
BytesList bytes_list = 1;
FloatList float_list = 2;
Int64List int64_list = 3;
}
};
message Features {
// Map from feature name to feature.
map feature = 1;
};
[个人理解]
说明一下, 一条数据或一个样本其实就是一个Example(其实还有SequenceExample,本文只说明Example), 数据中会存在许多的属性, 所有的属性信息都存储在Features类中, 并且每个属性由Key-Value来实现 map
官方例子:
//features {
// feature {
// key: "age"
// value { float_list {
// value: 29.0
// }}
// }
// feature {
// key: "movie"
// value { bytes_list {
// value: "The Shawshank Redemption"
// value: "Fight Club"
// }}
// }
//}
了解了存储格式代码就比较好弄了
制作TFRecords
#_*_ coding:utf-8 _*_
import os
import numpy as np
import tensorflow as tf
import cv2
'''
Example : fileName
Train/1.jpg 0
Train/2.jpg 1
Train/3.jpg 1
Train/4.jpg 1
'''
# 因为创建Feature需要list
def toList(value):
if type(value) == list:
return value
else:
return [value]
# 创建不用类型的Feature数据
def _int64_feature(value):
value = toList(value)
value = [int(x) for x in value]
return tf.train.Feature(int64_list=tf.train.Int64List(value = value))
def _float_feature(value):
value = toList(value)
value = [float(x) for x in value]
return tf.train.Feature(float_list=tf.train.FloatList(value = value))
def _bytes_feature(value):
return tf.train.Feature(bytes_list=tf.train.BytesList(value = toList(value)))
# Make TFRecords
def MakeTFRecord(fileName,tfrecords,imageRoot):
# 创建一个TFRecordWriter来进行写入数据
writer = tf.python_io.TFRecordWriter(tfrecords)
fp = open(fileName,'r')
lines = fp.readlines()
for line in lines:
line = line.strip().split()
imagePath = os.path.join(imageRoot,line[0])
print imagePath
## PIL Image 通道顺序RBG
#img = Image.open(imagePath)
#img_raw = img.tobytes()
## cv2 通道顺序BGR, 本例采取灰度图
img = cv2.imread(imagePath,0)
# 注意resize之后要赋值回img
img = cv2.resize(img,(128,128))
#cv2.imshow("d",img)
#cv2.waitKey(0)
# 把图像数据变成二进制,节省空间
img_raw = img.tostring()
# 创建一个Example
example = tf.train.Example(
# 创建一个Features
features=tf.train.Features(
# 填写不同类型的key-value
feature={
"img_raw":_bytes_feature(img_raw),
"label": _int64_feature(line[1:])
}
))
# 把example进行序列化,Serializes the protocol message to a binary string
writer.write(example.SerializeToString())
writer.close()
读取并显示 TFRecords
其实上面的制作理解了,读其实只是一个逆过程,一个解序列化的过程
# 创建tfrecords迭代器,每个样本都是序列化的
serialized_ex_it = tf.python_io.tf_record_iterator(tfrecords)
for serialized_ex in serialized_ex_it:
# 创建Example对象
example = tf.train.Example()
# 进行解序列化(注:解析的是Example对象)
example.ParseFromString(serialized_ex)
# 输出所有信息, 如果想知道TFRecords中属性可以输出example
print example
# 取出正确的key并且正确的类型的value值,错一个都会取不出值
image = example.features.feature['img_raw'].bytes_list.value
label = example.features.feature['label'].int64_list.value
print image, label
虽然上述可以读取数据,但是每个样本都需要解析一次,往往我们的数据都是结构化的,能不能一次就读入许多数据,并且在训练的时候数据是需要反复输入到训练集中的.
# Read TFRecords using queue structs
def ReadTFRecord(tfrecords):
# 可以把多个tfrecords排成一个queue,这样可以方便的使用多个tfrecords文件
record_queue = tf.train.string_input_producer([tfrecords])
# 读取TFRecords器
reader = tf.TFRecordReader()
# 一个数据一个数据的读返回key-value值,都保存在serialized_ex中
# 注意: 这里面keys是序列化的副产物,命名为tfrecords+random(),表示唯一的ID,没有作用,可以设置为_
#keys, serialized_ex = reader.read(record_queue)
_, serialized_ex = reader.read(record_queue)
# 直接解析出features数据,并且使用固定特征长度,及每个Example中一定会存在一个image和一个label
# 并不是输入的图片大小不同就使用VarLenFeature.
features = tf.parse_single_example(serialized_ex,
features={
# 取出key为img_raw和label的数据,尤其是int位数一定不能错!!!
'img_raw': tf.FixedLenFeature([],tf.string),
'label': tf.FixedLenFeature([], tf.int64)
})
img = tf.decode_raw(features['img_raw'], tf.uint8)
# 注意定义的为int多少位就转换成多少位,否则容易出错!!
label = tf.cast(features['label'], tf.int64)
return img, label
imgs,labels = ReadTFRecord(tfrecords)
sess = tf.Session()
# 多线程调节器
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess,coord=coord)
# 输出10个样本
for i in range(10):
image,label = sess.run([imgs,labels])
print image.shape,'label:', label