TF_IO_TFRecords.md

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 feature. 所有的Key都是字符型, 但是数据可以是bytes,float或int64类型.

官方例子:

//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

你可能感兴趣的:(TF_IO_TFRecords.md)