tf.data.Dataset

    科技2022-07-14  118

    目录

    1.dataset from tensor(dataset.from_)

    (1)from_tensors

    (2)from_tensor_slices

    (3)from_generator

    2.dataset apply function(dataset.apply(func)/map)

    3.dataset as numpy iterator(dataset.as_numpy_iterator())

    4.dataset.filter(func)

    5.batch

    6.flat_map

    7.enumerate

    8.reduce

    9.repeat

    10.shard

    11.shuffle

    12.skip

    13.take

    14.unbatch


    创建Dataset的三个关键步骤或用法:

      1. Create a source dataset from your input data.     根据输入数据创建源dataset   2. Apply dataset transformations to preprocess the data.     应用transformations处理数据   3. Iterate over the dataset and process the elements.     迭代处理dataset与elements

    Iteration happens in a streaming fashion, so the full dataset does not need to fit into memory.

    迭代以流方式进行,因此整个数据集不需要放入内存中。

    1.dataset from tensor(dataset.from_)

    (1)from_tensors

    dataset_tensor = tf.data.Dataset.from_tensors([[1,2,3,4],[2,3,4,5]]) print(dataset_tensor) """ <TensorDataset shapes: (2, 4), types: tf.int32> """ for i in dataset_tensor: print("-"*10) print(i) """ ---------- tf.Tensor( [[1 2 3 4] [2 3 4 5]], shape=(2, 4), dtype=int32) """

    (2)from_tensor_slices

    dataset_tensor_slices = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[2,3,4,5]]) print(dataset_tensor_slices) """ <TensorSliceDataset shapes: (4,), types: tf.int32> """ for i in dataset_tensor_slices: print("-"*10) print(i) """ ---------- tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) ---------- tf.Tensor([2 3 4 5], shape=(4,), dtype=int32) """

    从这里可以看出差别:

    from_tensors:组合输入并将数据集与单个元素一起返回

    from_tensor_slices:为输入张量的每一行创建一个带有单独元素的数据集

    而我们一般用第二种——from_tensor_slices

    (3)from_generator

    from_generator( generator, output_types, output_shapes=None, args=None)

    def tensor_generator(): tensor = tf.constant([[1,2,3,4],[2,3,4,5]]) for i in tensor: yield i dataset_generator = tf.data.Dataset.from_generator(tensor_generator,(tf.uint8)) list(dataset_generator) """ [<tf.Tensor: shape=(4,), dtype=uint8, numpy=array([1, 2, 3, 4], dtype=uint8)>, <tf.Tensor: shape=(4,), dtype=uint8, numpy=array([2, 3, 4, 5], dtype=uint8)>] """

    结果好像与直接iter一样:但from_generator可以指定type与shape

    tensor = tf.constant([[1,2,3,4],[2,3,4,5]]) tensor_iter = iter(tensor) list(tensor_iter) """ [<tf.Tensor: shape=(4,), dtype=int32, numpy=array([1, 2, 3, 4], dtype=int32)>, <tf.Tensor: shape=(4,), dtype=int32, numpy=array([2, 3, 4, 5], dtype=int32)>] """

    2.dataset apply function(dataset.apply(func)/map)

    dataset = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[2,3,4,5]]) for i in dataset: print(i) """ tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) tf.Tensor([2 3 4 5], shape=(4,), dtype=int32) """ def func(dataset): return dataset.map(lambda x:x**2) dataset = dataset.apply(func) for i in dataset: print(i) """ tf.Tensor([ 1 4 9 16], shape=(4,), dtype=int32) tf.Tensor([ 4 9 16 25], shape=(4,), dtype=int32) """

    也可以直接map

    dataset = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[2,3,4,5]]) for i in dataset_tensor_slices: print(i) """ tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) tf.Tensor([2 3 4 5], shape=(4,), dtype=int32) """ dataset = map(lambda x:x**2,dataset) for i in dataset: print(i) """ tf.Tensor([ 1 4 9 16], shape=(4,), dtype=int32) tf.Tensor([ 4 9 16 25], shape=(4,), dtype=int32) """ dataset = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[2,3,4,5]]) dataset = dataset.map(lambda x:x**2) list(dataset) """ [<tf.Tensor: shape=(4,), dtype=int32, numpy=array([ 1, 4, 9, 16], dtype=int32)>, <tf.Tensor: shape=(4,), dtype=int32, numpy=array([ 4, 9, 16, 25], dtype=int32)>] """

    3.dataset as numpy iterator(dataset.as_numpy_iterator())

    dataset = tf.data.Dataset.from_tensor_slices([1,2,3]) dataset = dataset.as_numpy_iterator() print(dataset) """ <tensorflow.python.data.ops.dataset_ops._NumpyIterator object at 0x13f8be0f0> """ # 先取出了一个数据 print(next(dataset)) """ 1 """ # 再取一个数据 print(type(next(dataset))) """ <class 'numpy.int32'> """ # 剩余的数据 print(list(dataset)) """ [3] """

    4.dataset.filter(func)

    下面是官网的代码:

    dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.filter(lambda x: x < 3) list(dataset.as_numpy_iterator()) # `tf.math.equal(x, y)` is required for equality comparison def filter_fn(x): return tf.math.equal(x, 1) dataset = dataset.filter(filter_fn) list(dataset.as_numpy_iterator()) """ [1] """

    注意到,这里只是进行了一维的判断,当我试着进行二维判断的时候,出现了许许多多错误,简直要抓狂了,发现dataset与tensor还不是那么一回事,有许许多多的问题,现在还不是很了解,以后如果有见解的话在这里继续补充(反正面对各种报错,简直是要疯了!!)。

    但事是必须要去完成的。

    回头来再度filter的使用要求,重新审视了一下Return:

    The Dataset containing the elements of this dataset for which predicate is True.

    返回dataset中elements符合predicate的元素!

    是elements中符合的元素!

    当dataset是一维的时候,elements为tensor,当二维时,elements 同样是tensor:

    一维:

    x = tf.data.Dataset.from_tensor_slices([1,2,3,4]) for i in x: print(i) print(i==1) print(tf.math.equal(i,1)) """ tf.Tensor(1, shape=(), dtype=int32) tf.Tensor(True, shape=(), dtype=bool) tf.Tensor(True, shape=(), dtype=bool) tf.Tensor(2, shape=(), dtype=int32) tf.Tensor(False, shape=(), dtype=bool) tf.Tensor(False, shape=(), dtype=bool) tf.Tensor(3, shape=(), dtype=int32) tf.Tensor(False, shape=(), dtype=bool) tf.Tensor(False, shape=(), dtype=bool) tf.Tensor(4, shape=(), dtype=int32) tf.Tensor(False, shape=(), dtype=bool) tf.Tensor(False, shape=(), dtype=bool) """

    二维:

    x = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[1,2,3,4]]) for i in x: print(i) print(i==1) print(tf.math.equal(i,1)) """ tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) tf.Tensor([ True False False False], shape=(4,), dtype=bool) tf.Tensor([ True False False False], shape=(4,), dtype=bool) tf.Tensor([1 2 3 4], shape=(4,), dtype=int32) tf.Tensor([ True False False False], shape=(4,), dtype=bool) tf.Tensor([ True False False False], shape=(4,), dtype=bool) """

    这里面单独测试都没问题,但是直接将能够返回多维的predicate传入到filter中,就会出错。

    也就是说,filter每次只接收关于单独element的bool逻辑谓词。

    在return内部无法做for循环,只能在外面先将dataset分解,逐个element传入filter:

    x = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[1,2,3,4]]) def func(x): return tf.math.equal(x,1) l = [] for i in x: i = tf.data.Dataset.from_tensor_slices(i) a = i.filter(func) b = a.as_numpy_iterator() l.append(list(b)) """ l:[[1], [1]] """

    主要是自己对tensor与dataset的分别不是太清楚,tensor可以直接返回多维的bool,这里不行,只能逐个进行,预计关于filter的其他逻辑函数也是如此,这里暂且记下,如果后续有更多的了解,再进行补全,如果你有更好的做法,告诉我一下也行!

    5.batch

    将数据进行分割,每部分有batch个数据,是否抛弃最后不足的部分由

    drop_remainder=True/False  决定

    这个很简单,但是在使用过程中,发现了一个问题:

    ([1,2,3],[2,3,4])与[[1,2,3],[2,3,4]]在创建dataset中是不一样的,但是在创建tensor中是一样的。

    dataset认为([1,2,3],[2,3,4])是两个张量,[[1,2,3],[2,3,4]]是一个张量

    tensor认为二者都是一个张量

    dataset = tf.data.Dataset.from_tensor_slices([[1,2,3,4],[2,3,4,5],[2,3,4,5]]) dataset = dataset.batch(2,drop_remainder=False) list(dataset.as_numpy_iterator()) """ [array([[1, 2, 3, 4], [2, 3, 4, 5]], dtype=int32), array([[2, 3, 4, 5]], dtype=int32)] """ dataset = tf.data.Dataset.from_tensor_slices(([1,2,3,4],[2,3,4,5],[2,3,4,5])) dataset = dataset.batch(2,drop_remainder=False) list(dataset.as_numpy_iterator()) """ 结果是多通道的batch(如本例的3维,3通道,取3通道的Batch数据) [(array([1, 2], dtype=int32), array([2, 3], dtype=int32), array([2, 3], dtype=int32)), (array([3, 4], dtype=int32), array([4, 5], dtype=int32), array([4, 5], dtype=int32))] """

    所以,tensorflow就很烦~

    6.flat_map

    映射展平

    dataset = tf.data.Dataset.from_tensor_slices( [[1, 2, 3], [4, 5, 6], [7, 8, 9]]) dataset = dataset.flat_map(lambda x: Dataset.from_tensor_slices(x)) list(dataset.as_numpy_iterator())

    7.enumerate

    dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.enumerate(start=5) for element in dataset.as_numpy_iterator(): print(element)

    8.reduce

    reduce(     initial_state, reduce_func )

    tf.data.Dataset.range(5).reduce(np.int64(0), lambda x, _: x + 1).numpy() """ 5 """ tf.data.Dataset.range(5).reduce(np.int64(0), lambda x, y: x + y).numpy() """ 10 """

    9.repeat

    dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3]) dataset = dataset.repeat(3) list(dataset.as_numpy_iterator()) """ [1,2,3,1,2,3,1,2,3] """

    10.shard

    Creates a Dataset that includes only 1/num_shards of this dataset.

    A = tf.data.Dataset.range(10) B = A.shard(num_shards=3, index=0) list(B.as_numpy_iterator()) """ [0,3,6,9] """ C = A.shard(num_shards=3, index=1) list(C.as_numpy_iterator()) """ [1,4,7] """ D = A.shard(num_shards=3, index=2) list(D.as_numpy_iterator()) """ [2,5,8] """

    11.shuffle

    shuffle(     buffer_size, seed=None, reshuffle_each_iteration=None ) buffer_size:每次生成的数据量 seed:指定随机种子 reshuffle_Each_iteration:每次是否重新随机

    Randomly shuffles the elements of this dataset.

    dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=True) dataset = dataset.repeat(2) # doctest: +SKIP """ 不指定种子,每次不同 [1,0,2,1,2,0] """ dataset = tf.data.Dataset.range(3) dataset = dataset.shuffle(3, reshuffle_each_iteration=False) dataset = dataset.repeat(2) # doctest: +SKIP """ 不指定种子,每次相同 [1,0,2,1,0,2] """

    12.skip

    Creates a Dataset that skips count elements from this dataset.

    dataset = tf.data.Dataset.range(10) dataset = dataset.skip(7) list(dataset.as_numpy_iterator()) """ [7,8,9] """

    13.take

    Creates a Dataset with at most count elements from this dataset.

    我看起来像是从头开始算count

    dataset = tf.data.Dataset.range(10) dataset = dataset.take(3) list(dataset.as_numpy_iterator()) """ [0,1,2] """

    14.unbatch

    Splits elements of a dataset into multiple elements.

    类似于展平,flatten?

    elements = [ [1, 2, 3], [1, 2], [1, 2, 3, 4] ] dataset = tf.data.Dataset.from_generator(lambda: elements, tf.int64) dataset = dataset.unbatch() list(dataset.as_numpy_iterator()) """ [1,2,3,1,2,1,2,3,4] """

     

    Processed: 0.012, SQL: 8