Tensorflow2.x学习——2.数据管道与预处理

本系列为tensorflow官方教程与文档学习笔记,结合个人理解提取其中的关键内容,便于日后复习。

数据处理与管道

The tf.data API enables you to build complex input pipelines from simple, reusable pieces.

API的用途举例:

  • 从分布式文件系统中聚合数据
  • 对图片做随机扰动
  • 在批处理时进行随机选取

1.1 Dataset对象

1.1.1 基础用法

为了创建并使用输入管道,首先要有一个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)

1.1.2 数据结构

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)

1.2 批处理

1.2.1 基本用法

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舍弃。

1.2.2 在Batch中加入padding操作

考虑以下情况:对序列数据进行建模时,序列的长度不一样长,无法确定模型的输入维度。此时就要对较短的序列进行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,))

1.3 训练工作流

1.3.1 多代训练

当一个完整的数据集通过了神经网络一次并且返回了一次,这个过程称为一次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)

1.3.2 随机打乱数据

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())
  • 为了进行充分的抽样,buffer_size的大小应该大于等于数据集的大小,以保证对每一个数据都有可能抽到。
  • 使用batch后,抽样数据的index将会在batchsize + buffer_size内取到。

1.4 数据预处理

预处理过程使用Dataset.map(f)对数据集中的每个数据应用f函数,进行高效处理。

1.4.1 图片数据预处理

# 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

1.4.2 使用外部库函数

依托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中的数据类型

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值