本系列为tensorflow官方教程与文档学习笔记,结合个人理解提取其中的关键内容,便于日后复习。
The tf.data
API enables you to build complex input pipelines from simple, reusable pieces.
API的用途举例:
为了创建并使用输入管道,首先要有一个Dataset对象,可以通过 tf.data.Dataset.from_tensors()
或 tf.data.Dataset.from_tensor_slices()
等API进行Dataset的创建。
有了Dataset对象后,就可以通过对象的方法链进行数据预处理,并获得新的Dataset对象,如:
Dataset.map()
对每个数据进行处理;Dataset.batch()
对批量数据进行处理;Dataset.reduce()
进行数据集的聚合操作。Dataset对象在python中是可迭代的,可以通过for循环取出其中的值,也可以为之创建一个迭代器:
it_data = iter(dataset)
next(it_data)
Dataset对象中的每个元素都是相同的数据结构,都可以通过tf.TypeSpec
来描述,包括 tf.Tensor
, tf.sparse.SparseTensor
, tf.RaggedTensor
, tf.TensorArray
, or tf.data.Dataset
.
通过 Dataset.element_spec
可以查看Dataset对象中每个组分的类型信息,如:
dataset1 = tf.data.Dataset.from_tensor_slices(tf.random.uniform([4, 10]))
dataset1.element_spec
# TensorSpec(shape=(10,), dtype=tf.float32, name=None)
Dataset.batch()
可以将dataset对象中n个连续的数据放到一个元素中,如:
d1 = tf.data.Dataset.range(100)
d2 = tf.data.Dataset.range(0, -100, -1)
dataset = tf.data.Dataset.zip((d1, d2))
batched_data = dataset.batch(3)
在batch
方法中使用参数drop_remainder=True
可以将最后一个可能无法构成n个元素的batch舍弃。
考虑以下情况:对序列数据进行建模时,序列的长度不一样长,无法确定模型的输入维度。此时就要对较短的序列进行padding
,以使所有数据拥有相同的维度。
通过 Dataset.padded_batch
来实现相应操作:
dataset = tf.data.Dataset.range(100)
dataset = dataset.map(lambda x: tf.fill([tf.cast(x, tf.int32)], x))
dataset = dataset.padded_batch(4, padded_shapes=(None,))
当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一次epoch。
为了方便的进行多代训练,tensorflow提供了 Dataset.repeat()
方法,注意:若repeat方法未给定参数,数据集将会重复无限次
repeat
方法不会在代与代之间进行标识,注意以下两种写法:
dataset.repeat(3).batch(64)
:相当于先将数据集重复三次,构成新的数据集再batch操作dataset.batch(64).repeat(3)
:相等于先batch,再重复三次如果想在每一代训练后进行一些操作,如:计算这一代的数据指标、时间消耗等,最简单的方式是显示地指定代数:
epochs = 3
dataset = titanic_lines.batch(128)
for epoch in range(epochs):
for batch in dataset:
print(batch.shape)
print("End of epoch: ", epoch)
shuffle(
buffer_size, seed=None, reshuffle_each_iteration=None
)
Dataset.shuffle()
可以从固定大小的缓冲区内进行抽样。
x = tf.data.Dataset.range(100)
y = tf.data.Dataset.range(100)
dataset = tf.data.Dataset.zip((x, y))
dataset = dataset.shuffle(buffer_size = 100)
dataset = dataset.batch(20)
n, batch = next(iter(dataset))
print(n.numpy())
batchsize + buffer_size
内取到。预处理过程使用Dataset.map(f)
对数据集中的每个数据应用f函数,进行高效处理。
# Assuming that we have some picture folder paths in a Dataset named list_ds
def parse_image(filename):
parts = tf.strings.split(filename, os.sep)
label = parts[-2]
# 获取图片对象
image = tf.io.read_file(filename)
# 对图片进行解码
image = tf.image.decode_jpeg(image)
# 转换数据类型
image = tf.image.convert_image_dtype(image, tf.float32)
# 改变图片大小
image = tf.image.resize(image, [128, 128])
return image, label
依托tf.py_function()
方法调用外部库或者自定义函数,运用于map
中:
import numpy as np
def abs_add(data):
return np.abs(data) + 1
def tf_abs_add(data):
return tf.py_function(abs_add, [data], [tf.float32])
ds = tf.data.Dataset.from_tensor_slices([-1,-2,-3,-4,-5])
ds = ds.map(tf_abs_add)
for i in ds:
print(i[0].numpy(), end = " ")
# 2.0 3.0 4.0 5.0 6.0
参数说明:
func:python函数,根据官方文档:返回值可以为Tensor列表、单个Tensor或者None,但貌似基本数据类型或者numpy类型也可以
inp:func函数输入参数
Tout:返回值类型,对应func的返回值,可以为列表、单个值或者None,此处为tf中的数据类型