MachineLearning入门---第7章---TensorFlow的中阶API---数据管道

这篇博客介绍了如何使用TensorFlow构建数据管道,包括从CSV和文本文件中读取数据,应用各种转换如map、filter、zip等,并探讨了提高数据加载效率的方法,如prefetch、interleave和多进程转换。
摘要由CSDN通过智能技术生成

指导教程: https://github.com/lyhue1991/eat_tensorflow2_in_30_days
这一张只是了解了一些知识,只是了解,有个印象而已, 以下代码,也只是书上的代码复现, 贴在这是为了以后方便

# -*- coding: utf-8 -*-
import datetime
import time

import tensorflow as tf
import pandas as pd


def pandas_data_pipeline():
    # excel = pd.read_excel('./data/stock.xlsx')
    # excel = pd.read_csv('./data/stock.csv')
    # excel['date'] = excel['date'].str.replace('-', '')
    # excel = excel.fillna(value=0).astype({'date': 'float64'})
    # #excel.to_csv('stock.csv')

    # slices = tf.data.Dataset.from_tensor_slices(excel)
    # for features, label in slices.take(0):
    #     tf.print(features, label)

    #  从csv⽂件构建数据管道
    ds4 = tf.data.experimental.make_csv_dataset(
        file_pattern=["./data/stock.csv"],  # 多个使用逗号隔开
        batch_size=3,
        label_name="date",
        na_value="",
        num_epochs=1,
        ignore_errors=True)
    for data, label in ds4.take(3):
        print(data, label)

    # 从⽂本⽂件构建数据管道
    ds5 = tf.data.TextLineDataset(
        filenames=["./data/stock.csv"]
    ).skip(1)  # 略去第⼀⾏header
    for line in ds5.take(5):
        print(line)

    # 从⽂件路径构建数据管道
    ds6 = tf.data.Dataset.list_files("./data/*.csv")
    for file in ds6.take(5):
        print(file)


# 应⽤数据转换
def data_change():
    '''
    map: 将转换函数映射到数据集每⼀个元素。
    flat_map: 将转换函数映射到数据集的每⼀个元素,并将嵌套的Dataset压平。
    interleave: 效果类似flat_map,但可以将不同来源的数据夹在⼀起。
    filter: 过滤掉某些元素。
    zip: 将两个⻓度相同的Dataset横向铰合。
    concatenate: 将两个Dataset纵向连接。
    reduce: 执⾏归并操作。
    batch : 构建批次,每次放⼀个批次。⽐原始数据增加⼀个维度。 其逆操作为unbatch。
    padded_batch: 构建批次,类似batch, 但可以填充到相同的形状。
    window :构建滑动窗⼝,返回Dataset of Dataset.
    shuffle: 数据顺序洗牌。
    repeat: ᯿复数据若⼲次,不带参数时,᯿复⽆数次。
    shard: 采样,从某个位置开始隔固定距离采样⼀个元素。
    take: 采样,从开始位置取前⼏个元素
    '''
    # map:将转换函数映射到数据集每⼀个元素
    ds = tf.data.Dataset.from_tensor_slices(["hello world", "hello China", "hello Beijing"])
    # 按空格拆分
    ds_map = ds.map(lambda x: tf.strings.split(x, " "))
    for x in ds_map:
        print(x)
        # tf.Tensor([b'hello' b'world'], shape=(2,), dtype=string)
    print("\n")

    # flat_map:将转换函数映射到数据集的每⼀个元素,并将嵌套的Dataset压平
    ds_flatmap = ds.flat_map(lambda x: tf.data.Dataset.from_tensor_slices(tf.strings.split(x, " ")))
    for x in ds_flatmap:
        print(x)
        # tf.Tensor(b'hello', shape=(), dtype=string)
    print("\n")

    # interleave: 效果类似flat_map,但可以将不同来源的数据夹在⼀起。
    ds_interleave = ds.interleave(lambda x: tf.data.Dataset.from_tensor_slices(tf.strings.split(x, " ")))
    for x in ds_interleave:
        print(x)
        # tf.Tensor(b'hello', shape=(), dtype=string)
    print("\n")

    # filter:过滤掉某些元素。
    # 找出含有字⺟a或B的元素
    ds_filter = ds.filter(lambda x: tf.strings.regex_full_match(x, ".*[a|B].*"))
    for x in ds_filter:
        print(x)

    print("\n")

    # zip:将两个⻓度相同的Dataset横向铰合。
    ds1 = tf.data.Dataset.range(0, 3)
    ds2 = tf.data.Dataset.range(3, 6)
    ds3 = tf.data.Dataset.range(6, 9)
    print(ds1)
    print(ds2)
    print(ds3)
    ds_zip = tf.data.Dataset.zip((ds1, ds2, ds3))
    for x, y, z in ds_zip:
        print(x.numpy(), y.numpy(), z.numpy())
    print("\n")

    # condatenate:将两个Dataset纵向连接。
    ds_concat = tf.data.Dataset.concatenate(ds1, ds2)
    for x in ds_concat:
        print(x)
    print('\n')

    # reduce:执⾏归并操作。
    ds = tf.data.Dataset.from_tensor_slices([1, 2, 3, 4, 5.0])
    result = ds.reduce(0.0, lambda x, y: tf.add(x, y))
    print(result)
    print('\n')

    # batch:构建批次,每次放⼀个批次。⽐原始数据增加⼀个维度。 其逆操作为unbatch。
    ds = tf.data.Dataset.range(12)
    ds_batch = ds.batch(4)
    for x in ds_batch:
        print(x)
    print('\n')

    # padded_batch:构建批次,类似batch, 但可以填充到相同的形状。
    elements = [[1, 2], [3, 4, 5], [6, 7], [8]]
    ds = tf.data.Dataset.from_generator(lambda: iter(elements), tf.int32)
    ds_padded_batch = ds.padded_batch(2, padded_shapes=[4, ])
    for x in ds_padded_batch:
        print(x)

    # window返回的是Dataset of Dataset,可以⽤flat_map压平'
    ds = tf.data.Dataset.range(12)
    ds_window = ds.window(3, shift=1).flat_map(lambda x: x.batch(3, drop_remainder=True))
    for x in ds_window:
        print(x)
    print('\n')

    # shuffle:数据顺序洗牌。
    ds = tf.data.Dataset.range(12)
    ds_shuffle = ds.shuffle(buffer_size=5)
    for x in ds_shuffle:
        print(x)
    print('\n')

    # repeat:᯿复数据若⼲次,不带参数时,᯿复⽆数次。
    ds = tf.data.Dataset.range(3)
    ds_repeat = ds.repeat(3)
    for x in ds_repeat:
        print(x)

    # shard:采样,从某个位置开始隔固定距离采样⼀个元素。
    ds = tf.data.Dataset.range(12)
    ds_shard = ds.shard(3, index=1)
    for x in ds_shard:
        print(x)

    # take:采样,从开始位置取前⼏个元素。
    ds = tf.data.Dataset.range(12)
    ds_take = ds.take(3)
    data_list = list(ds_take.as_numpy_iterator())
    print(data_list)


# 打印时间分割线
@tf.function
def printbar():
    today_ts = tf.timestamp() % (24 * 60 * 60)
    hour = tf.cast(today_ts // 3600 + 8, tf.int32) % tf.constant(24)
    minite = tf.cast((today_ts % 3600) // 60, tf.int32)
    second = tf.cast(tf.floor(today_ts % 60), tf.int32)

    def timeformat(m):
        if tf.strings.length(tf.strings.format("{}", m)) == 1:
            return tf.strings.format("0{}", m)
        else:
            return tf.strings.format("{}", m)

    timestring = tf.strings.join([timeformat(hour), timeformat(minite),
                                  timeformat(second)], separator=":")
    tf.print("==========" * 8 + timestring)


# 数据准备和参数迭代两个过程默认情况下是串行的。

# 模拟数据准备 准备数据需要20秒
def generator():
    for i in range(10):
        # 假设每次准备数据需要2s
        time.sleep(2)
        yield i


# 模拟参数迭代
def train_step():
    # 假设每一步训练需要1s
    time.sleep(1)

    '''
    以下是⼀些构建⾼效数据管道的建议。
    1,使⽤ prefetch ⽅法让数据准备和参数迭代两个过程相互并⾏。
    2,使⽤ interleave ⽅法可以让数据读取过程多进程执⾏,并将不同来源数据夹在⼀起。
    3,使⽤ map 时设置num_parallel_calls 让数据转换过程多进⾏执⾏。
    4,使⽤ cache ⽅法让数据在第⼀个epoch后缓存到内存中,仅限于数据集不⼤情形。
    5,使⽤ map转换时,先batch, 然后采⽤向量化的转换⽅法对每个batch进⾏转换。
    '''


# 使⽤ prefetch ⽅法让数据准备和参数迭代两个过程相互并⾏
def improve_pipeline1():
    tf.print(tf.constant("start training... 训练过程预计耗时 10*2+10*1 = 30s"))
    ds = tf.data.Dataset.from_generator(generator, output_types=(tf.int32))
    for x in ds:
        train_step()
    printbar()
    tf.print(tf.constant("end training..."))

    printbar()
    tf.print(tf.constant("使用 prefetch 方法让数据准备和参数迭代两个过程相互并行。"))
    tf.print(tf.constant("start training with prefetch.. 训练过程预计耗时 max(10*2,10*1) = 20s."))
    # tf.data.experimental.AUTOTUNE 可以让程序自动选择合适的参数
    for x in ds.prefetch(buffer_size=tf.data.experimental.AUTOTUNE):
        train_step()
    printbar()
    tf.print(tf.constant("end training..."))


# 使⽤ interleave ⽅法可以让数据读取过程多进程执⾏,并将不同来源数据夹在⼀起。
def improve_pipeline2():
    ds_files = tf.data.Dataset.list_files("./data/*.csv")
    ds = ds_files.flat_map(lambda x: tf.data.TextLineDataset(x).skip(1))
    for line in ds.take(4):
        print(line)


# 使用 map 时设置num_parallel_calls 让数据转换过程多进行执行
ds = tf.data.Dataset.list_files("./data/train/*/*.jpg")


def load_image(img_path, size=(32, 32)):
    label = 1 if tf.strings.regex_full_match(img_path, ".*/automobile/.*") else 0
    img = tf.io.read_file(img_path)
    img = tf.image.decode_jpeg(img)  # 注意此处为jpeg格式
    img = tf.image.resize(img, size)
    return img, label


# 使用 map 时设置num_parallel_calls 让数据转换过程多进行执行。
def improve_pipeline3():
    tf.print(tf.constant("start transformation...  单进程转换"))
    printbar()
    ds_map = ds.map(load_image)
    for _ in ds_map:
        pass
    printbar()
    tf.print(tf.constant("end transformation..."))

    printbar()
    tf.print(tf.constant("start parallel transformation...  多进程转换"))
    ds_map_parallel = ds.map(load_image, num_parallel_calls=tf.data.experimental.AUTOTUNE)
    for _ in ds_map_parallel:
        pass
    printbar()
    tf.print(tf.constant("end parallel transformation..."))


# 使用 map转换时,先batch, 然后采用向量化的转换方法对每个batch进行转换。
def improve_pipeline4():
    # 先map后batch
    ds = tf.data.Dataset.range(100000)
    ds_map_batch = ds.map(lambda x: x ** 2).batch(20)
    printbar()
    tf.print(tf.constant("start scalar transformation..."))
    for x in ds_map_batch:
        pass
    printbar()
    tf.print(tf.constant("end scalar transformation..."))


    # 先batch后map
    ds = tf.data.Dataset.range(100000)
    ds_batch_map = ds.batch(20).map(lambda x:x**2)
    printbar()
    tf.print(tf.constant("start vector transformation..."))
    for x in ds_batch_map:
        pass
    printbar()
    tf.print(tf.constant("end vector transformation..."))


if __name__ == '__main__':
    print(123)
    # pandas_data_pipeline()
    # data_change()
    improve_pipeline3()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值