这里的写, 指的是把各种格式的数据(如字符, 图片等)统一转换成Tensorflow
的标准支持格式TFRecord
.
TFRecord是输入数据统一管理的格式, 它其实是一种二进制文件.
写入:
通过将数据填入到tf.train.Example
类,Example
的protocol buffer
包含了字段的tf.train.Features
, 使用数据修改Features, 实现将protocol buffer
序列化成一个字符串, 再通过tf.python_io.TFRecordWriter
类将序列化的字符串写入到TFRecord
中.读出:
使用tf.TFRecordReader
读取器, 通过tf.parse_single_example
解析器解析,parse_single_example
操作可以将Example
protocol buffer
解析为张量, 然后用解码器tf.decode_raw
解码.
tf.python_io.TFRecordWriter
把记录写入到TFRecords文件的类.
''' 作用: 创建一个TFRecordWriter对象, 将数据记录到指定的TFRecord文件中. 参数: path: (must)TFRecords文件的路径; options: TFRecordOptions对象; '''
''' 作用: 将一条序列化字符串记录写入到文件中. 参数: record: string, 序列化字符串记录. '''
''' 作用: 关闭TFRecordWriter. '''
tf.train.Example
Example是使用某种规则规则化后的数据, 通过使用TFRecordWriter写入到TFRecord中.
Example包含一个键值对数据结构(与dict相同), 使用属性features记录, 因此, 初始化时必须传入这个features参数, 它是一个tf.train.Features对象.
''' 作用: 初始化一个Example. 参数: features: tf.train.Features对象, 其中每条记录的key表示数据的描述, value为固定数据类型的特殊处理的数据. '''
''' 作用: 把这个Example序列化成字符串, 将这个字符串通过TFRecordWriter写入到TFRecord中. '''
tf.train.Features
协议化的描述数据信息, 结构为键值对, key为字符串, 用来描述数据, value为tf.train.Feature对象, 一个Feature包含一种数据类型的list, list中有若干数据.
list有三种: BytesList
, FloatList
, Int64List
''' 作用: 初始化一个Features 参数: feature: dict字典, key为数据名称, value为tf.train.Feature对象, 特殊的数据list. '''
tf.train.Features(feature={"image_raw":tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])),
"label":tf.train.Feature(int64_list=tf.train.Int64List(value=[train_labels_values[i]]))})
tf.train.Feature
一个Feature包含一种数据类型的list, list中有若干数据.
list类型主要有BytesList
, FloatList
, Int64List
三种类型
''' 作用: 初始化一个Feature, 内含数据队列. 参数: bytes_list: 队列数据为byte(一般是字符串)时使用, 将tf.train.BytesList赋给此参数; float_list: 队列数据为float时使用, 将tf.train.FloatList赋给此参数; int64_list: 队列数据为int64时使用, 将tf.train.Int64List赋给此参数. '''
tf.train.Feature(int64_list = tf.train.Int64List(value = [value]))
tf.train.Feature(bytes_list = tf.train.BytesList(value = [value]))
tf.train.Feature(float_list = tf.train.FloatList(value = [value]))
tf.train.BytesList, tf.train.FloatList, tf.train.Int64List
字符, 浮点, 整形三种数据队列
''' 作用: 初始化一个类型的队列, 传入数据 参数: value: 将相应类型的数据放在list中, 赋值给此参数 '''
这里使用Kaggle中Getting Started级别的Digit Recognizer
题目, 数据是MNIST
手写数字的csv格式, 这里使用train.csv作为例子, 实现将csv文件转换为TFRecord的操作.
import numpy as np
import pandas as pd
import tensorflow as tf
train_frame=pd.read_csv(filepath_or_buffer="train.csv")
train_labels_frame=train_frame.pop(item="label")
train_values=train_frame.values
train_labels_values=train_labels_frame.values
train_size=train_values.shape[0]
writer=tf.python_io.TFRecordWriter(path="train.tfrecords")
for i in range(train_size):
image_raw=train_values[i].tostring()
example=tf.train.Example(
features=tf.train.Features(
feature={
"image_raw":tf.train.Feature(bytes_list=tf.train.BytesList(value=[image_raw])),
"label":tf.train.Feature(int64_list=tf.train.Int64List(value=[train_labels_values[i]]))
}
)
)
writer.write(record=example.SerializeToString())
writer.close()
from PIL import Image # 这里使用PIL包读取图片
def _int64_feature(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(data_path, name):
rows = 64
cols = 64
depth = DEPTH
for ii in range(12):
writer = tf.python_io.TFRecordWriter(name + str(ii) + '.tfrecords')
for img_name in os.listdir(data_path)[ii*16384 : (ii+1)*16384]:
img_path = data_path + img_name
img = Image.open(img_path)
h, w = img.size[:2]
j, k = (h - OUTPUT_SIZE) / 2, (w - OUTPUT_SIZE) / 2
box = (j, k, j + OUTPUT_SIZE, k+ OUTPUT_SIZE)
img = img.crop(box = box)
img = img.resize((rows,cols))
img_raw = img.tobytes()
example = tf.train.Example(features = tf.train.Features(feature = {
'height': _int64_feature(rows),
'weight': _int64_feature(cols),
'depth': _int64_feature(depth),
'image_raw': _bytes_feature(img_raw)}))
writer.write(example.SerializeToString())
writer.close()
Tensorflow中, 有三种主要的读取数据文件的读写器类, 有共用的操作文件的Ops.
tf.TextLineReader 用于读取csv文件, 配合tf.decode_csv()方法使用;
tf.FixedLengthRecordReader 用于读取二进制编码文件, 配合tf.decode_raw()解码器方法使用;
tf.TFRecordReader 用于读取TFRecord文件, 配合tf.parse_single_example()解析器和tf.decode_raw()解码器方法使用.
三个类均继承于父类tf.ReaderBase, 常用的方法有:
read()
''' 作用: 生成一个每次读取固定长度数据的读取器. 参数: record_bytes: (must)整数, 固定的读取长度; header_bytes: 整数, 头数据长度, 默认为0; footer_bytes: 整数, 尾数据长度, 默认为0; name: Op的名字; '''
使用例子见Tensorflow: 队列操作章节中最后的读取数据的例子.
''' 作用: 生成一个每次读取一行内容的读取器 参数: skip_header_lines: 整数, 需要跳过的头行数, 默认为0; name: Op的名称. '''
使用例子:
filename_queue = tf.train.string_input_producer(["file0.csv", "file1.csv"])
reader = tf.TextLineReader()
key, value = reader.read(filename_queue)
# Default values, in case of empty columns. Also specifies the type of the
# decoded result.
record_defaults = [[1], [1], [1], [1], [1]]
col1, col2, col3, col4, col5 = tf.decode_csv(
value, record_defaults=record_defaults)
features = tf.concat(0, [col1, col2, col3, col4])
with tf.Session() as sess:
# Start populating the filename queue.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in range(1200):
# Retrieve a single instance:
example, label = sess.run([features, col5])
coord.request_stop()
coord.join(threads)
每次read的执行都会从文件中读取一行内容, decode_csv()
操作会解析这一行内容并将其转为张量列表. 如果输入的参数有缺失, record_default
参数可以根据张量的类型来设置默认值.
''' 作用: 生成一个每次从TFRecord中读取一个Features数据的读取器 参数: name: Op的名称; options: TFRecordOptions; '''
使用例子
def read_and_decode(filename):
#根据文件名生成一个队列
filename_queue = tf.train.string_input_producer([filename])
reader = tf.TFRecordReader()
_, serialized_example = reader.read(filename_queue) #返回文件名和文件
features = tf.parse_single_example(serialized_example,
features={
'label': tf.FixedLenFeature([], tf.int64),
'img_raw' : tf.FixedLenFeature([], tf.string),
})
img = tf.decode_raw(features['img_raw'], tf.uint8)
img = tf.reshape(img, [224, 224, 3])
img = tf.cast(img, tf.float32) * (1. / 255) - 0.5
label = tf.cast(features['label'], tf.int32)
return img, label
''' 作用: 将读取的csv记录(字符串)解析并转换成Tensor, csv文件中的每一列将会对应一个Tensor. 参数: records: (must)string类型的Tensor, 里面每个string代表csv中的一行, 代表一条记录; record_defaults: (must)list of Tensor, 每个Tensor对应一列, 当列中的数据为空时, 使用对应的Tensor填补输出结果; field_delim: string, 指明一条记录(一行)之间各列的分界符, 默认为','; name: op的名称. 输出: list of tensor, list长度与record_defaults相同, 各个tensor的shape相同. '''
''' 作用: 将bytes of string转换为指定类型的数据. 参数: bytes: (must)string类型的Tensor, 所有的元素长度相同; out_type: (must)指明输出数据的类型, tf.DType; little_endian: (不明)bool, 默认为True, 无视out_type参数, 将数据转为单字节格式, 类似uint8; name: op的名称. 输出: out_type类型的Tensor, 维度比bytes入参Tensor多一维; 多出的一维的值等于将bytes中单个string元素, 用out_type分割后产生的数据的长度. '''
''' 作用: 将一个Example proto 转为features指定格式的key: Tensor数据. 参数: serialized: (must)只含一条string元素的Tensor, 代表一条序列化的Example数据; features: (must)dict, 类似于存储时的features, key为字符串描述, 但value为tf.FixedLenFeature对象. name: op的名称; example_names: 只含一条string元素的Tensor, 表示Example的名称. 输出: dict, key为features参数中的key, value为转换出来的Tensor, 类型为string. '''
''' 作用: 固定长度Feature(tf.train.Feature)解析配置类, 用来描述Feature的属性, 以供tf.parse_single_example()方法解析. 参数: (继承于collections.namedtuple("FixedLenFeature",["shape", "dtype", "default_value"])类.) 第一: 数据的shape, 指定为[], 表示不指明; 第二: 数据的类型dtype, tf.DType; 第三: 数据缺失时默认的填补数据default_value, 必须与shape和dtype适应. '''
tf.FixedLenFeature([], tf.int64)
tf.FixedLenFeature([], tf.string)