tf.data数据加载
tf.data用于构建Tensorflow的数据加载。
在tf.data中引入了tf.data.Dataset这样一个抽象来表示一系列的element,每一个元素都由一定的component组成。(如一个图像训练的样本可以看作一个element,其中包含了图像和标签两个component)
graph LR;
D(Dataset)-->E1(Element)
D-->N1(...)
E1-->C1(Component)
E1-->N2(...)
classDef wbox fill:#fff,stroke:#fff;
class D,E1,N1,N2,C1 wbox;获取数据输入
由NumPy数组创建
对于在内存中的数据,使用Dataset.from_tensor_slice是最方便的:
train, test = tf.keras.datasets.fashion_mnist.load_data()
dataset = tf.data.Dataset.from_tensor_slices((images, labels))☆ 上面的创建方式仅适用于小数据集,因为浪费内存。
由Python generator创建
Dataset.from_generator将一个Python generator转换为tf.data.Dataset,它以一个callable作为输入(而非一个iterator)。
在参数列表中: args用来提供Python generator初始化所需要的参数。
output_type必须要指定以确定数据类型。
output_shape是可选的,但是因为Tensorflow中的部分操作不支持未知的shape因而最好指定。如果shape是可变的或未知,可以定义为None,对于scalar其形状为()。
☆ 使用比较方便,但是需要注意可能会有兼容性、可移植性方面的问题。
由TFRecord创建
使用tf.data.TFRecordDataset来实现从一个或多个TFRecord文件导入数据,只需要提供filenames参数即可,接受单一字符串、字符串列表或者字符型的tf.Tensor。
这样读出来的只是二进制数据,通常使用tf.train.Example来序列化存储,对于这样的数据需要进行解码:
由text数据创建
使用tf.data.TextLineDataset,只需要提供.txt格式的文件路径即可:
默认的TextLineDataset是逐个文件地给出其中的每一行,使用Dataset.interleave可以在各个文件之间依次切换着输出每一行。
由CSV数据创建
对于CSV格式的数据,在加载到内存之后当然也可以使用Dataset.from_tensor_slice来创建Dataset,不过我们更希望能直接从硬盘中读取。
experimental.make_csv_dataset可以直接读取CSV格式的文件:
另外,select_columns参数可以只把其中需要的几列挑选出来:
:pill:直接通过这一个函数创建的数据集,label部分是按照标签分开的,需要使用一下方式进行合并!
除了这一个函数,还有一个更低级的experimental.CsvDataset,它不支持每一列的自动类型推导,但这也意味着可以手动控制每一列的数据类型,并且第二个参数还可以同时为空缺的数据指定默认值。
☆ 从函数名可以看出这一系列都是实验性函数,之后版本的API中可能出现更改。
由一系列文件创建
有时候数据集会以分散在目录里的一系列文件的形式给出,对于这样的数据可以以文件路径作为信息构建数据集,使用Dataset.list_files()函数来构建:
其中每一个element的形式是文件路径:
数据处理
Dataset.map
对于数据处理,一个很重要的变换函数是Dataset.map,它可以将一个指定的函数f应用到数据集中的每一个element上,以实现数据的批量处理。
在指定的函数f中,可以使用Tensorflow的API,也支持使用其他的Python API来处理数据。
对于一些使用tf.Train.Example原型来存储的数据,就理所当然的可以应用Dataset.map来对原始数据进行解码。
通过Dataset.map实现图像解码
很显然图像的解码可以通过和Dataset.map的配合来实现。
样本过滤
使用Dataset.skip()变换可以跳过开头的几个样本,Dataset.filter()可以使用特定的条件对于数据集中的element进行筛选,只需要提供一个判断用的函数。
时序数据
对于和时序相关的数据,原始数据是“时间”上连续的,为了构建数据集,我们往往需要以此创建连续的时间切片。
通过batch
基本思路为:
先转化为一系列batch,这样每一个element就是一个batch的数据。
应用
Dataset.map来处理每一个batch,分割出输入和输出。
通过window
使用Dataset.window可以更好地控制这一个过程,但注意这一函数返回的Dataset中element依旧是Dataset。可以利用Dataset.flat_map方法,它要求作为参数的map_func是一个将element转化为Dataset的函数,然后它会将返回的Dataset展开。
这样就相当于在整一条的数据上使用“滑动窗口”一样的方法,以特定的shift值过了一遍。之后再利用上面的在batch中创建出训练集和标签的方法,即可完成数据集的创建。
数据输出
分批量输出
定长数据:batch
使用Dataset.batch()可以方便地产生批量数据,约束条件是其中每一个元素都要拥有相同的形状。
对于输出的批量,在默认的函数设置下是未知的,因为最后一个batch可能是不全的,Tensorflow无法判断所以将其形状设为None。可以使用drop_remainder参数来丢弃最后一个不完全的batch,这样其形状就会固定了。
不定长数据:padded_batch
对于不定长的数据,在分批量调用的时候注意使用Dataset.padded_batch而非一般性的Dataset.batch
☆ padded_batch需要指定形状,在Tensorflow Guide的文章中写错了,没有指定形状。同时形状的描述也很特别,值得考量。 填充的值可以指定。 详见API:
Dataset.padded_batch。
输出形式如下:
多epoch重复输出
使用Dataset.repeat()变换可以实现重复枚举数据:
无参数的
Dataset.repeat()会无限地重复枚举。 注意repeat和batch的调用顺序会影响输出数据的长度变化(主要因为最后一个batch会不全):


先repeat
先batch
随机化
Dataset.shuffle()通过维护指定大小的buffer并从中随机选取来实现一定程度的随机输出。
☆ 对于这样的随机方案,随机的完全性取决于buffer的大小,大的buffer虽然随机性更好但是占用大量内存。 对于随机,先调用
repeat或是shuffle也会存在差异:
参考
Last updated
Was this helpful?
