指导教程: 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()