tf.data的实质是类似于一个完整的ETL pipeline
1.读取数据
- 从numpy数组读取
如果数据在内存范围内,最好的方法是直接转换成tf.Tensor再通过from_tensorf_slice加载
但是要注意的是这个只适合小数据集,否则有可能会导致内存溢出。
train
![v2-a411b99c6cfd21ac724fdde070a08b5b_b.png](http://img-01.proxy.5ce.com/view/image?&type=2&guid=fceadc8d-da2e-eb11-8da9-e4434bdf6706&url=https://pic4.zhimg.com/v2-a411b99c6cfd21ac724fdde070a08b5b_b.png)
- 从python generator读取
def count(stop):
i = 0
while i<stop:
yield i
i += 1
ds_counter = tf.data.Dataset.from_generator(count, args=[25], output_types=tf.int32, output_shapes = (), )
- 从 TFRecord data读取
TFRecord 是tensorflow中自带的,方便与储存比较大的数据集的数据格式(二进制格式),当内存不足时,我们可以将数据集制作成TFRecord格式的再将其解压读取。
- 从文本数据读取
可以通过自己的设置,从一个directory里读取多个text file,并且可以配合interleave来并行读取每个文件内的内容。这里面还有很多细节的操作,需要大家重点去学习。
directory_url = 'https://storage.googleapis.com/download.tensorflow.org/data/illiad/'
file_names = ['cowper.txt', 'derby.txt', 'butler.txt']
file_paths = [
tf.keras.utils.get_file(file_name, directory_url + file_name)
for file_name in file_names
]
dataset = tf.data.TextLineDataset(file_paths)
- 从CSV数据读取
一种是通过makecsvdataset,类似于estimator中的trainfn,可以自定义feature_column,另一种是CsvDataset可以指定每一列的type
titanic_batches = tf.data.experimental.make_csv_dataset(
titanic_file, batch_size=4,
label_name="survived", select_columns=['class', 'fare', 'survived'])
titanic_types = [tf.int32, tf.string, tf.float32, tf.int32, tf.int32, tf.float32, tf.string, tf.string, tf.string, tf.string]
dataset = tf.data.experimental.CsvDataset(titanic_file, titanic_types , header=True)
for line in dataset.take(10):
print([item.numpy() for item in line])
2.从dataset读取
- 按批量读取
dataset.batch(length, dropped_remainder=False) #需要所有的input x有相同的长度
dataset.padded_batch() #NLP中的场景,许多的x都是不同的长度,这时候需要填充
- 重复的按epochs读取
dataset.repeat()
PS:这里要注意
repeat(),当没有输入确定的epoch时,repeat()方法会无限的读取dataset直到消费完,他不会显式的区别上个epoch的结束和下一个epoch的开始。
dataset.repeat().batch() ---不能区分每个epoch,当batch数量不能刚好被dataset划分时,会导致最后一个batch数量不均匀.
dataset.batch().repeat()---能显式的区分每个epoch,则可以将每个batch均匀分布.
- Shuffle操作
同样的,shuffle操作也不会显式的区分不同的epoch(),他只会把所有的数据给消费完, 因此需要在repeat()后调用shuffle()
3.数据预处理
主要思想是类似于hadoop的 map, reduce 和 filter,对每个dataset的元素映射我们的lambda匿名函数, 还有一种方法是当tf.data中没有合适的函数的时候, 通过tf.py__fuction()函数来封装python的函数。
别的可以自己看tf官方文档的操作,这里详细提一下重采样的操作,在我们实际建模的时候不平衡的数据集是很常见的,这时候我们需要重采样。
- 1.一种做法是,通过filter操作把数据集拆分为两类数据集,再通过sample_from_dataset重新从两个数据集按比例采样。
creditcard_ds
- 2.上面这种操作的缺点是,我们需要重新缓存数据集一次,这样实际上会造成额外的空间开销,因此更好的方法是通过rejection_sample重新采样
这个地方我也不太明白,建议大家看看参考文档详细点。
4.在High-level api上使用
这里的high-level 的api主要是指tf.keras和tf.estimator
- tf.keras的fit evaluate 都支持直接将(feature, label)形式的dataset直接输入
train, test = tf.keras.datasets.fashion_mnist.load_data()
images, labels = train
images = images/255.0
labels = labels.astype(np.int32)
fmnist_train_ds = tf.data.Dataset.from_tensor_slices((images, labels))
fmnist_train_ds = fmnist_train_ds.shuffle(5000).batch(32)
model = tf.keras.Sequential([
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(10)
])
model.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['accuracy'])
model.fit(fmnist_train_ds, epochs=2)
- 但其实更为建议使用estimator,可以更方便的配合tf的别的生态一起使用
这里主要是要将dataset在inputfn中写好需要输出的形式,再将其传入model_fn中,详情可参考tf官方文档
import tensorflow_datasets as tfds
def train_input_fn():
titanic = tf.data.experimental.make_csv_dataset(
titanic_file, batch_size=32,
label_name="survived")
titanic_batches = (
titanic.cache().repeat().shuffle(500)
.prefetch(tf.data.experimental.AUTOTUNE))
return titanic_batches
embark = tf.feature_column.categorical_column_with_hash_bucket('embark_town', 32)
cls = tf.feature_column.categorical_column_with_vocabulary_list('class', ['First', 'Second', 'Third'])
age = tf.feature_column.numeric_column('age')
model = tf.estimator.LinearClassifier(
model_dir=model_dir,
feature_columns=[embark, cls, age],
n_classes=2
)
![v2-90f7a2dd08ebc4ea0107eeed0ba2edf0_180x120.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=fceadc8d-da2e-eb11-8da9-e4434bdf6706&url=https://pic1.zhimg.com/v2-90f7a2dd08ebc4ea0107eeed0ba2edf0_180x120.jpg)