tf.data.Dataset

概述

表示 一系列元素,其中每个元素包含一个或多个 Tensor 类型的对象

注意: Tensor是tensorflow内置对象

一句话解释: Dataset 相当于集合(其元素是 tensor),将读入的数据放入Dataset对象中,便于tensorflow训练、预测

官方网址:
https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/data/Dataset

优点

tf.data.Dataset,更方便的读取数据,而支持 多线程(进程) ,也在效率上获得了一定程度的提高。

使用tf.data.Dataset模块的pipline机制,可实现CPU多线程处理输入的数据,如读取图片和图片的一些的预处理,这样 GPU可以专注于训练过程,而 CPU去准备数据

注意

在使用Dataset时,由于Dataset无法获取内部数据的数量,所以模型调用fit()方法训练时,必须设置参数steps_per_epoch
如果有验证集,必须设置参数validation_steps

创建

语法:

tf.data.Dataset.from_tensor_slices(variant_tensor)
参数:
  • variant_tensor :可以是list、dict、numpy
返回值
  • Dataset对象

例子:通过一维list创建

dataset=tf.data.Dataset.from_tensor_slices([1,2,3,4,5,6,7])

print(dataset)

# item是tensor类型
for item in dataset:
    print(item)

执行结果如下:

<TensorSliceDataset shapes: (), types: tf.int32>

tf.Tensor(1, shape=(), dtype=int32)
tf.Tensor(2, shape=(), dtype=int32)
tf.Tensor(3, shape=(), dtype=int32)
tf.Tensor(4, shape=(), dtype=int32)
tf.Tensor(5, shape=(), dtype=int32)
tf.Tensor(6, shape=(), dtype=int32)
tf.Tensor(7, shape=(), dtype=int32)
tensor类型转换成numpy类型
for item in dataset:
    print(item.numpy())

执行结果如下:

1
2
3
4
5
6
7

例子:通过2个list创建

dataset=tf.data.Dataset.from_tensor_slices(([1,2,3,4,5,6,7],["赤","橙","黄","绿","青","蓝","紫"]))

for i,j in dataset:
    print(i,"-",j,"-",j.numpy().decode("utf-8"))

例子:通过二维list创建

dataset=tf.data.Dataset.from_tensor_slices([[1,2],[3,4],[5,6]])

print(dataset)

执行结果如下:

<TensorSliceDataset shapes: (2,), types: tf.int32>

表示里面元素的长度是2

遍历元素,tensor类型:

for item in dataset:
    print(item)

遍历元素,numpy类型:

for item in dataset:
    print(item.numpy())

例子:通过dict创建

dataset=tf.data.Dataset.from_tensor_slices({
    'a':[1,2,3],
    'b':[4,5,6],
    'c':[7,8,9]
})
print(dataset)

执行结果:

<TensorSliceDataset shapes: {a: (), b: (), c: ()}, types: {a: tf.int32, b: tf.int32, c: tf.int32}>
遍历
for item in dataset:
    print(item)

执行结果如下:

{'a': <tf.Tensor: id=205, shape=(), dtype=int32, numpy=1>, 'b': <tf.Tensor: id=206, shape=(), dtype=int32, numpy=4>, 'c': <tf.Tensor: id=207, shape=(), dtype=int32, numpy=7>}
{'a': <tf.Tensor: id=211, shape=(), dtype=int32, numpy=2>, 'b': <tf.Tensor: id=212, shape=(), dtype=int32, numpy=5>, 'c': <tf.Tensor: id=213, shape=(), dtype=int32, numpy=8>}
{'a': <tf.Tensor: id=217, shape=(), dtype=int32, numpy=3>, 'b': <tf.Tensor: id=218, shape=(), dtype=int32, numpy=6>, 'c': <tf.Tensor: id=219, shape=(), dtype=int32, numpy=9>}

注意:遍历dict时,不能转换成numpy,否则报错

例子:通过numpy创建

# 通过ndarry创建
import numpy as np

database=tf.data.Dataset.from_tensor_slices(np.array([1,2,3,4,5,6,7]))
print(database)
for item in database:
    print(item.numpy())

例子:复杂参数

train_ds=tf.data.Dataset.from_tensor_slices((train_names,(train_labels,train_acs,train_fms)))

例子中,参数更加复杂,传入tuple,第一个元素是 train_names,list类型;第二个元素也是tuple(称之为sec),该 sec 含有3个元素,每个元素也是list类型

详见:
https://www.malaoshi.top/show_1EF5NUEm0T3B.html

take()

根据当前dataset,创建一个dataset,新的dataset 包含 前count个元素

语法

dataset.take(count)
参数说明
  • count:新的dataset包含前count个元素
返回值
  • dataset对象

例子:

database=tf.data.Dataset.from_tensor_slices(np.array([1,2,3,4,5,6,7]))

for item in dataset.take(4):
    print(item)

skip

根据当前dataset,创建一个dataset,新的dataset 跳过 count个元素

语法

skip(count)
参数
  • count:整型
返回值
  • dataset对象

shuffle()

随机重新排列此数据集的元素

语法:

shuffle(buffer_size)
参数
  • buffer_size:将多少个元素打乱顺序。
    一般设置为该dataset数据的个数
返回
  • Dataset对象

例子

size=20
dataset=tf.data.Dataset.from_tensor_slices(list(range(size)))
dataset=dataset.shuffle(size)
for item in dataset:
    print(item.numpy())

repeat()

将整个序列重复n次
一般用于训练模型时,epoch循环的次数

注意:一般在 shuffle()后面执行

语法

repeat(count=None)
参数
  • count:可选,tf.int64标量tf.Tensor,表示应重复数据集的 次数。
    默认为None,为 None 或 -1 表示无限重复
返回
  • Dataset对象

例子

size=10
dataset=tf.data.Dataset.from_tensor_slices(list(range(size)))
dataset=dataset.repeat(2)
for item in dataset:
    print(item.numpy())

batch()

将 batch_size 个元素组合成每一个batch

调用此方法返回的 dataset 类型会改变
shape会改变 ,增加1个维度,表示 数量

在读取图片时,由于图片体积较大,不可能一次将所有图片读入到内存中,而是 分批次 的读取

语法

batch(batch_size)
参数
  • batch_size:每一批次 合并的元素数量。
    根据机器内存大小和数据进行设置
返回值

Dataset 对象

例子

size=10
dataset=tf.data.Dataset.from_tensor_slices(list(range(size)))
print(dataset)
# 每3个元素组成一个batch
dataset2=dataset.batch(3)
print(dataset2)
for item in dataset2:
    print(item.numpy())

执行结果:

<TensorSliceDataset shapes: (), types: tf.int32>
<BatchDataset shapes: (None,), types: tf.int32>
[0 1 2]
[3 4 5]
[6 7 8]
[9]

执行batch()后,dataset的类型改变了,shape改变了

map()

map接收一个函数,Dataset中的每个元素都会被当作这个函数的输入,并将函数返回值 组成 新的Dataset

该方法支持 多个CPU并行 预处理。通过参数num_parallel_calls指定并行数量

python内置函数map() 功能相同

语法

map(map_func,num_parallel_calls=None)
参数
  • map_func:函数,dataset中的每一个元素传入到该函数中,并将返回结果放回到dataset中
  • num_parallel_calls:整型数字。表示要并行异步处理的线程数
    • 如果未指定,则将按顺序处理元素。
    • 如果设置成tf.data.experimental.AUTOTUNE,根据可用的CPU,自动设置并行的数量。

num_parallel_calls参数是为了提高map()方法的处理速度, 使用并行处理,tf.data.experimental.AUTOTUNE可以让程序自动的选择最优的线程并行个数

返回值
  • Dataset对象

例子:将原始元素放大二倍

def fun(x):
    return x*2

size=10
dataset=tf.data.Dataset.from_tensor_slices(list(range(size)))
dataset=dataset.map(fun)
for item in dataset:
    print(item.numpy())

zip()

此功能与python内置的zip()函数一样

将2个dataset,对应元素打包成一个元祖

语法

@staticmethod
zip(datasets)
参数
  • datasets:dataset对象
返回值
  • Dataset对象

例子

size=10
dataset1=tf.data.Dataset.from_tensor_slices(list(range(size)))

dataset2=tf.data.Dataset.from_tensor_slices(list(range(size,20)))

dataset=tf.data.Dataset.zip((dataset1,dataset2))
for item in dataset:
    print(item[0].numpy(),item[1].numpy())

prefetch()

效率问题

执行训练时,先提取、处理数据,然后在GPU(TPU)上训练模型。

当 CPU 正在准备数据时,GPU(TPU)则处于空闲状态。
当GPU(TPU)训练模型时,CPU 则处于空闲状态。

因此,训练步骤时间是 CPU 预处理时间和加速器训练时间的总和。
如下图:

Pipeline机制

使用 pipelining 技术后,空闲时间显著减少

prefetch()

该方法提供了 software pipelining 机制。该函数解耦了 数据产生的时间 和 数据消耗的时间。

该函数有 一个后台线程 和 一个内部缓存区,在数据被请求前,就从 dataset 中 预加载一些数据(进一步提高性能)。

注意: prefech() 一般作为 最后一个转换

语法

prefetch(buffer_size)
参数
  • buffer_size:整数或tf.int64的tf.Tensor,预先提取元素的数量
    如果设置成 tf.data.experimental.AUTOTUNE,根据可用的CPU,自动设置最佳数量。
返回
  • Dataset

感谢:
https://blog.csdn.net/guyuealian/article/details/85106012


原文出处:/show_1EF47ZxC4RYZ.html