importing data:
tf.data接口允许建立复杂的数据输入管道,距离在,图像模型的管道也许需要聚合分布在不同文件系统的图片,给每个图片随机干扰,并聚合,随机选取一批图像用于训练,对于文本模型,安德森,这个接口简化了处理大量数据,不同的数据格式,和复杂的转化。
接口引入了两个新的抽象给tensorflow:
tf.data.dataset表示一系列的元素,每个元素包含一个或者多个tensor类,例子:一个图像管道,一个元素可能是一个单独的训练样本,用一对儿tensor道标图像的数据和标签
创建dataset的两个不同的方法:要么从tensor里切片切出来,要么从别的dataset分块分出来
创建一个source:Dataset.from_tensor_slices(),从一个或者多个tensor类构建
用transformation:Dataset.batch()构建一个数据集从一个或者多个 tf.data,Dataset类
Tf.data.iterator提供一个从dataset提取元素的主要方法,这种操作通过iterator.get_next()返回dataset中的下一元素,通常作为输入管道代码和模型的接口,这个简单的迭代器叫做one-shot iterator,循环访问一次dataset。
基本machanics
Guide的这个部分表述了建立dataset和iterator类的基本方法,以及如何从他们中提取数据。
为了开始一个输入管道,必须建立一个source.比如,从内存中建立DATASET的方法:tf.data.Dataset.from_tensors()
or tf.data.Dataset.from_tensor_slices()
.
或者,如果你的输入数据实在硬盘上(并且是一种被推荐的TFRecord format格式),就可以构建一个
tf.data.TFRecordDataset
一旦有了Dataset类,就可以公国tf.data.Dataset类把他们转化成新的Dataset,例子:可以对每个element操作: Dataset.map(),或者多个element操作,Dataset.batch()。 Tf.data.Dataset,查看完整操作https://tensorflow.google.cn/api_docs/python/tf/data/Dataset
最常见的使用Dataset中数据的方法是用iterator类,迭代。可以一次提取dataset中的一个元素,(Dataset.make_one_shot_iterator()
)tf.data.Iterator提供两种操作:Iterator.initializer,让你能够初始化,重新初始化迭代器的情况。Iterator.get_next(),返回下一个元素,
Dataset 结构:
一个dataset中的数据由相同的结构,一个元素包含一个或者多个tensor类叫做components。每个组件(每个element中的tensor)都有tf.Dtype查看类型,tf.TensorShape将每个元素的静态形状输出,Dataset.output_types Dataset.output_shapes输出每个元素中组建的信息。
dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([4,10]))
print(dataset1.output_types) # ==> "tf.float32"
print(dataset1.output_shapes) # ==> "(10,)"
dataset2 = tf.data.Dataset.from_tensor_slices(
(tf.random_uniform([4]),
tf.random_uniform([4,100], maxval=100, dtype=tf.int32)))
print(dataset2.output_types) # ==> "(tf.float32,tf.int32)"
print(dataset2.output_shapes) # ==> "((),(100,))"
dataset3 = tf.data.Dataset.zip((dataset1, dataset2))
print(dataset3.output_types) # ==> (tf.float32,(tf.float32, tf.int32))
print(dataset3.output_shapes) # ==> "(10, ((),(100,)))"
或者给每个component起个名(一个element里的component名字一样,因为他们的shape一样,type一样),用字典传给tensor_slices,这样在查看信息的时候就可以直接看到了
dataset = tf.data.Dataset.from_tensor_slices(
{"a": tf.random_uniform([4]),
"b": tf.random_uniform([4,100], maxval=100, dtype=tf.int32)})
print(dataset.output_types) # ==> "{'a':tf.float32, 'b': tf.int32}"
print(dataset.output_shapes) # ==> "{'a': (), 'b':(100,)}"
解释:dataset2中有两个element,一个是tf.random_uniform([4]),包含4个component,另一个是(【4,100】),每个component有100维。
Dataset类支持任何结构的datasets,用Dataset.map()
, Dataset.flat_map()
, and Dataset.filter()
转换去给每一个
element
转换,元素的结构决定函数的参数
dataset1 =dataset1.map(lambda x:...)
dataset2 =dataset2.flat_map(lambda x, y:...)
# Note: Argument destructuring is notavailable in Python 3.
dataset3 =dataset3.filter(lambda x,(y, z):...)
创建一个iterator
一旦有了Dataset去代表你要输入的数据,下一就是创建一个迭代器去使用dataset中的elements. tf.data结构现在支持以下iterators,越来月复杂:
One-shot, initializable , reinitializable , feedable
One-shot,迭代器是iterator中最简单的一种形式,只可以从dataset中迭代一次,不用初始化,可以支持几乎所有基于队列的输入管道,但是不支持参数化,
dataset = tf.data.Dataset.range(100)
iterator =dataset.make_one_shot_iterator()
next_element =iterator.get_next()
for i in range(100):
value =sess.run(next_element)
assert i == value
Note:Currently, one-shot iterators are the only type that is easily usable with an Estimator
.
Initializable,用这种模式之前需要先初始化(初始化的时候不取值),通常使用方法是:获取数据集合dataset,在dataset里建立迭代器,创建next_element = iterator.get_next()
在运行session的时候先初始化迭代器,然后就可以用next_element了。
max_value = tf.placeholder(tf.int64,shape=[])
dataset = tf.data.Dataset.range(max_value)
iterator =dataset.make_initializable_iterator()
next_element =iterator.get_next()
# Initialize an iterator over adataset with 10 elements.
sess.run(iterator.initializer, feed_dict={max_value: 10})
for i in range(10):
value =sess.run(next_element)
assert i == value
# Initialize the same iterator over adataset with 100 elements.
sess.run(iterator.initializer, feed_dict={max_value: 100})
for i in range(100):
value =sess.run(next_element)
assert i == value
使用iterator中的值
Iterator.get_next()方法返回一个或者多个张量,对应于迭代器中的下一个元素,注意:这个方法并不直接更新迭代器,必须将其作为返回值传递给tf.Session.run()来使用下一个元素。如果迭代器到达了dataset的结尾,继续运行就会生成错误,跳出迭代,如果想用,需要重新初始化。通常是:
dataset = tf.data.Dataset.range(5)
iterator =dataset.make_initializable_iterator()
next_element =iterator.get_next()
# Typically `result` will be theoutput of a model, or an optimizer's
# training operation.
result = tf.add(next_element,next_element)
sess.run(iterator.initializer)
print(sess.run(result)) # ==> "0"
print(sess.run(result)) # ==> "2"
print(sess.run(result)) # ==> "4"
print(sess.run(result)) # ==> "6"
print(sess.run(result)) # ==> "8"
try:
sess.run(result)
except tf.errors.OutOfRangeError:
print("Endof dataset") #==> "End of dataset"
放在try except里
sess.run(iterator.initializer)
whileTrue:
try:
sess.run(result)
except tf.errors.OutOfRangeError:
break
注意:一次迭代,迭代器里所有组建都会迭代。
dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([4,10]))
dataset2 = tf.data.Dataset.from_tensor_slices((tf.random_uniform([4]), tf.random_uniform([4,100])))
dataset3 = tf.data.Dataset.zip((dataset1, dataset2))
iterator =dataset3.make_initializable_iterator()
sess.run(iterator.initializer)
next1, (next2, next3) = iterator.get_next()
读取输入数据:
利用NumPy arrays:
如果所有的数据都在内存里,创建dataset的最简单的办法就是把他们变为tensor类,然后用Dataset.from_tensor_slices().
: # Load the training data into two NumPy arrays, for example using`np.load()`.
with np.load("/var/data/training_data.npy")as data:
features =data["features"]
labels =data["labels"]
# Assume that each row of `features` 对应 tothe same row as `labels`.
assert features.shape[0]== labels.shape[0]
dataset = tf.data.Dataset.from_tensor_slices((features,labels))
(载入数据,放入内存data,assert(程序你帮我确认啊,错了要告诉我啊!!)特征和标签个数相同,然后切片)对于小数据集比较好,但是消耗内存因为array的内容会copy很多次,最大容量2GB
这样的话可以用占位符代替变量,然后先不传入值,整个session设计好,初始化的时候再传入值。
# Load the training data intotwo NumPy arrays, for example using `np.load()`.
with np.load("/var/data/training_data.npy")as data:
features =data["features"]
labels =data["labels"]
# Assume that each row of `features`corresponds to the same row as `labels`.
assert features.shape[0]== labels.shape[0]
features_placeholder = tf.placeholder(features.dtype, features.shape)
labels_placeholder = tf.placeholder(labels.dtype, labels.shape)
dataset = tf.data.Dataset.from_tensor_slices((features_placeholder,labels_placeholder))
# [Other transformations on`dataset`...]
dataset = ...
iterator =dataset.make_initializable_iterator()
sess.run(iterator.initializer, feed_dict={features_placeholder: features,
labels_placeholder: labels})
利用TFRecord data:
tf.data接口支持很多种文件格式,可以处理不适合放在内存里的数据,比如,TFRecord文件可是是一个简单的二进制格式,很多tensorflow都用它训练数据。Tf.data.TFRecordDataset类能帮你从一个或者多个TFRecord文件里读取数据。
# Creates a dataset that readsall of the examples from two files.
filenames = ["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
这样的话可以直接从硬盘读取测试集和验证集,分别run就行了。
filenames = tf.placeholder(tf.string,shape=[None])
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) #Parse the record into tensors.
dataset = dataset.repeat() #Repeat the input indefinitely.
dataset = dataset.batch(32)
iterator =dataset.make_initializable_iterator()
# You can feed the initializer withthe appropriate filenames for the current
# phase of execution, e.g. trainingvs. validation.
# Initialize `iterator` with trainingdata.
training_filenames = ["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
sess.run(iterator.initializer, feed_dict={filenames: training_filenames})
# Initialize `iterator` withvalidation data.
validation_filenames = ["/var/data/validation1.tfrecord",...]
sess.run(iterator.initializer, feed_dict={filenames: validation_filenames})
读取文本数据,许多的数据集使用多个文本文件存储,tf.data.TextLineDataset
会一行一行输出文件里的文版,可以用tf.placeholder(tf.string)输入数据。
filenames =["/var/data/file1.txt","/var/data/file2.txt"]
dataset = tf.data.TextLineDataset(filenames)
可以使用filter函数过滤不需要的信息。
filenames =["/var/data/file1.txt","/var/data/file2.txt"]
dataset = tf.data.Dataset.from_tensor_slices(filenames)
# Use `Dataset.flat_map()` totransform each file as a separate nested dataset,
# and then concatenate their contentssequentially into a single "flat" dataset.
# * Skip the first line (header row).
# * Filter out lines beginning with"#" (comments).
dataset = dataset.flat_map(
lambda filename:(
tf.data.TextLineDataset(filename)
.skip(1)
.filter(lambda line: tf.not_equal(tf.substr(line,0,1),"#"))))
用Dataset.map()处理数据。去处理dataset中的每一个element。
给出几个应用dataset.map的例子
分析协议缓冲区的messages
解码图像数据并改变大小。应用现实生活的图片处理图像数据的时候,把图像大小改成同样的大小是必要的。
# Reads an image from a file,decodes it into a dense tensor, and resizes it
# to a fixed shape.
def _分析_function(filename, label):
image_string = tf.read_file(filename)
image_decoded = tf.image.decode_image(image_string)
image_resized = tf.image.resize_images(image_decoded, [28,28])
return image_resized, label
# A vector of filenames.
filenames = tf.constant(["/var/data/image1.jpg","/var/data/image2.jpg",...])
# `labels[i]` is the label for theimage in `filenames[i].
labels = tf.constant([0,37,...])
dataset = tf.data.Dataset.from_tensor_slices((filenames,labels))
dataset = dataset.map(_parse_function)
利用tf.py_func()调用任意python逻辑
通常我们希望尽可能的用tensorflow的方式处理数据,但是有时候不可避免的需要调用额外的python第三方库。
import cv2
# Use a custom OpenCV function to readthe image, instead of the standard
# TensorFlow `tf.read_file()`operation.
def _read_py_function(filename, label):
image_decoded = cv2.imread(filename.decode(), cv2.IMREAD_GRAYSCALE)
return image_decoded, label
# Use standard TensorFlow operationsto resize the image to a fixed shape.
def _resize_function(image_decoded, label):
image_decoded.set_shape([None,None,None])
image_resized = tf.image.resize_images(image_decoded, [28,28])
return image_resized, label
filenames = ["/var/data/image1.jpg","/var/data/image2.jpg",...]
labels = [0,37,29,1,...]
dataset = tf.data.Dataset.from_tensor_slices((filenames,labels))
dataset = dataset.map(
lambda filename, label: tuple(tf.py_func(
_read_py_function, [filename, label], [tf.uint8, label.dtype])))
dataset = dataset.map(_resize_function)
批处理数据集元素
简单的batching:把连续n个elements合成一个:Dataset.batch()
inc_dataset = tf.data.Dataset.range(100)
dec_dataset = tf.data.Dataset.range(0,-100,-1)
dataset = tf.data.Dataset.zip((inc_dataset, dec_dataset))
batched_dataset =dataset.batch(4)
iterator =batched_dataset.make_one_shot_iterator()
next_element =iterator.get_next()
print(sess.run(next_element)) # ==> ([0, 1, 2, 3], [ 0, -1, -2, -3])
print(sess.run(next_element)) # ==> ([4, 5, 6, 7], [-4, -5, -6, -7])
print(sess.run(next_element)) # ==> ([8, 9, 10, 11], [-8, -9, -10, -11])
分析:inc:[0,1,…,99] dec:[0,-1,-2,….,-99] dataset = (inc,dec)
batched_dataset=把dataset中element中的组件每4个组成一个batch
Batchingtensors with 填充,如果element的长度不同,需要用Dataset.padded_batch()
可以设置参数,把不同长度的输入数据合起来,短的就补全。
训练工作流/
处理多个epochs循环
最简单的方法就是用Dataset.repeat()。如果不传入参数就无限期循环
filenames =["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...)
dataset = dataset.repeat(10)
dataset = dataset.batch(32)
如果想要在每次结束后看统计信息的话写一个训练循环
filenames =["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...)
dataset = dataset.batch(32)
iterator =dataset.make_initializable_iterator()
next_element =iterator.get_next()
# Compute for 100 epochs.
for _ in range(100):
sess.run(iterator.initializer)
whileTrue:
try:
sess.run(next_element)
except tf.errors.OutOfRangeError:
break
#[Perform end-of-epoch calculations here.]
随机打乱数据:dataset.shuffle()参数buffer_size等于需要从dataset随机选的数量
filenames =["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...)
dataset = dataset.shuffle(buffer_size=10000)
dataset = dataset.batch(32)
dataset = dataset.repeat()
Using high-level APIs
总结:importingdata的方法:具体代码自己回头再找吧
数据载入需要考虑两个步骤,一建立dataset(原始数据存储的位置)二,iterator(迭代dataset中的数据)
Dataset包含N个element(一个特征,),每个element包含M个component(一个样本的一个特征,每个element中的数据类型需要相同)
Dataset获取的形式有两种:source,从内存或者硬盘中来;transformation,从原有dataset转变而来,
iterator是用来迭代数据的,也就是dataset放着所有的数据,具体操作的时候由iterator取来,送给模型。分4中,one-shot initializable 还有其他两种。未完
数据读入流程:硬盘、内存、dataset、map\shuffle\batch\repeat、iterator(ont-shot不需要初始化,initializable,需要初始化)
filenames =["/var/data/file1.tfrecord","/var/data/file2.tfrecord"]
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...)
dataset = dataset.shuffle(buffer_size=10000)
dataset = dataset.batch(32)
dataset = dataset.repeat()