Reference

tensorflow - Meaning of buffer_size in Dataset.map , Dataset.prefetch and Dataset.shuffle - Stack Overflow

https://www.tensorflow.org/api_docs/python/tf/data/Dataset#shuffle

buffer_size的含义——Dataset.map , Dataset.prefetch and Dataset.shuffle_Eartha1995的博客-CSDN博客_buffer_size

本文就不重复上面3篇文章的代码了。免得大家又用batch()或者next()的角度去解构它,虽然这些解构方式都是正确的。

一、直观生动的代码案例

话不多说,上代码!

dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(2)
print(list(dataset.as_numpy_iterator()))

上面这个代码块,输出为

[1, 2, 3, 0, 5, 6, 7, 4, 8, 9]

而如果把buffer size调为10,输出明显更混乱(如下所见)。

dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(10)
print(list(dataset.as_numpy_iterator()))
# [3, 5, 4, 0, 2, 6, 1, 7, 9, 8]

因此,如果你不想要懂原理,想要真正地、有效地用到这个shuffle方法,直接把size设置为整个数据集大小,或者成倍大小(感觉没必要)。

即使这样确实会增大内存消耗,但是不这样做,打乱效果会很差。

二、详细贴心的原理讲解

首先讲buffer size为2的情况。

dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(2)
print(list(dataset.as_numpy_iterator()))
[1, 2, 3, 0, 5, 6, 7, 4, 8, 9]

这个输出怎么得到的?这真的是手把手、一步步打出来的呀!不能再详细了!

1、按顺序在dataset中先取出buffer size大小的数据,而后存入buffer缓冲区;第一次取的是[0,1]。

2、在缓冲区随机取出一个元素输出到output区中去;第一次输出的是1,所以output的第一个元素是1;于是缓冲区变成了[0, ]。

3、接着,再按顺序把dataset中的2放入buffer缓冲区;于是缓冲区变成了[0, 2]。

4、然后再随机从buffer取一个元素输出,第二次输出2;于是缓冲区变成了[0, ];output的第二个元素是2。

5、接着,把dataset中的3放入buffer缓冲区;于是缓冲区变成了[0, 3]。

6、然后再随机从buffer取一个元素输出,第三次输出3;于是缓冲区变成了[0, ];output的第三个元素是3。

7、接着,把dataset中的4放入buffer缓冲区;于是缓冲区变成了[0, 4]。

8、然后再随机从buffer取一个元素输出,第四次输出0;于是缓冲区变成了[ , 4];output的第四个元素是0。

9、接着,把dataset中的5放入buffer缓冲区;于是缓冲区变成了[5, 4]。

10、然后再随机从buffer取一个元素输出,第五次输出5;于是缓冲区变成了[ , 4];output的第五个元素是5。

11、接着,把dataset中的6放入buffer缓冲区;于是缓冲区变成了[6, 4]。

12、然后再随机从buffer取一个元素输出,第六次输出6;于是缓冲区变成了[ , 4];output的第六个元素是6。

13、接着,把dataset中的7放入buffer缓冲区;于是缓冲区变成了[7, 4]。

14、然后再随机从buffer取一个元素输出,第七次输出7;于是缓冲区变成了[ , 4];output的第七个元素是7。

15、接着,把dataset中的8放入buffer缓冲区;于是缓冲区变成了[8, 4]。

16、然后再随机从buffer取一个元素输出,第八次输出4;于是缓冲区变成了[8,  ];output的第八个元素是4。

17、接着,把dataset中的9放入buffer缓冲区;于是缓冲区变成了[8, 9]。

18、然后再随机从buffer取一个元素输出,第九次输出8;于是缓冲区变成了[ , 9];output的第九个元素是8。

19、最后,buffer区发现dataset区已经被他“掏空了”(可怜巴巴...),于是只好无可奈何用小于buffer size的剩下的元素进行随机输出;第十次输出啥呢?笨蛋,只能输出9 了。

20、于是output区的最后一个元素是9。

三、结合batch进一步理解shuffle

3.1 当reshuffle_each_iteration=None时

如果这个参数不设置,也即为None时,和它为True时效果竟然一样(俺也不知道为啥...不过既然如此,建议手动设置为False)。

如果这个参数为True,那么每一次迭代(比如for循环、list()/tuple()方法、iter()方法)的时候,都会重新乱序。

这样也就导致每一次的迭代输出,结果不一样。

dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(3)
print(list(dataset.as_numpy_iterator()))
dataset = dataset.batch(2)
print(list(dataset))
for ds in dataset:
    print(ds.numpy())
# [0, 2, 1, 4, 5, 3, 8, 7, 9, 6]
# [<tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 3], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([4, 2], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 5], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([7, 6], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([9, 8], dtype=int64)>]
# [1 2]
# [0 5]
# [4 3]
# [8 7]
# [9 6]
dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(3,reshuffle_each_iteration=True)
print(list(dataset.as_numpy_iterator()))
dataset = dataset.batch(2)
print(list(dataset))
for ds in dataset:
    print(ds.numpy())
# [1, 2, 4, 0, 3, 6, 7, 9, 5, 8]
# [<tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([4, 5], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([3, 7], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([6, 8], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([9, 2], dtype=int64)>]
# [1 3]
# [0 2]
# [5 4]
# [7 9]
# [6 8]

3.2 当reshuffle_each_iteration=False时

dataset = tf.data.Dataset.range(10)
dataset = dataset.shuffle(3,reshuffle_each_iteration=False)
print(list(dataset.as_numpy_iterator()))
dataset = dataset.batch(2)
print(list(dataset))
for ds in dataset:
    print(ds.numpy())
# 输出如下:
# [0, 2, 1, 5, 4, 7, 3, 9, 6, 8]
# <BatchDataset shapes: (None,), types: tf.int64>
# [<tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 2], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([1, 5], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([4, 7], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([3, 9], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([6, 8], dtype=int64)>]
# [0 2]
# [1 5]
# [4 7]
# [3 9]
# [6 8]

3.3 batch本身是不会乱序的,以原序按批次分割

dataset = tf.data.Dataset.range(10)
# dataset = dataset.shuffle(3)
print(list(dataset.as_numpy_iterator()))
dataset = dataset.batch(2)
print(list(dataset))
for ds in dataset:
    print(ds.numpy())
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# [<tf.Tensor: shape=(2,), dtype=int64, numpy=array([0, 1], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([2, 3], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([4, 5], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([6, 7], dtype=int64)>, <tf.Tensor: shape=(2,), dtype=int64, numpy=array([8, 9], dtype=int64)>]
# [0 1]
# [2 3]
# [4 5]
# [6 7]
# [8 9]
在此数据集的元素之间映射map_func。 此转换将map_func应用于此数据集的每个元素,并返回一个新的数据集,该数据集包含转换后的元素,顺序与它们在输入出现的顺序相同。 a = Dataset.range(1, 6) # ==> [ 1, 2, 3, 4, 5 ] a.map(lambda x: x + 1) # ==> [ 2, 3, 4, 5, 6 ] map_func的输入签名由这个数据集每个元素的结构决定。 例如: # NOTE: The foll
Dataset数据对象 Dataset可以用来表示输入管道元素集合(张量的嵌套结构)和“逻辑计划“对这些元素的转换操作。在Dataset元素可以是向量,元组或字典等形式。 另外,Dataset需要配合另外一个类Iterator进行使用,Iterator对象是一个迭代器,可以对Dataset的元素进行迭代提取。 Dataset方法 2.1 .from_tensor_slices from_tensor_slices 用于创建dataset,其元素是给定张量的切片的元素。 函数形式:from_tensor
1.shuffle(buffer_size) tensorflow的数据集类Dataset有一个shuffle方法,用来打乱数据集数据顺序,训练时非常常用。其shuffle方法有一个参数buffer_size,文档的解释如下: dataset.shuffle(buffer_size, seed=None, reshuffle_each_iteration=None) Randomly shuffles the elements of this dataset. This dataset f.
buffer_size参数,指元素的个数,最完美的shuffle是所有数据一起shuffle,但是避免内存不够,每次选buffer_size个数据进行shuffle。 比如Dataset一共10000个元素,buffer_size=1000, ...
本文翻译自stackoverflow网友的回答,某些地方可能有些生硬甚至错误,翻译成文(为尽可能保留原义有的词没翻译)也是便于自己日后再次查看,仅供参考。(读完其实也还没弄太明白,了解的大神或者有相同困惑的小伙伴可以一起讨论下) 源地址https://stackoverflow.com/questions/46444018/meaning-of-buffer-size-in-dataset-m...
我给buffer_size = 1,发现没有shuffle的作用。所以想知道到底是如何shuffle的。 函数内部设置 首先,Dataset会取所有数据的前buffer_size数据项,填充 buffer,如下图: 然后,从buffer随机选择一条数据输出,比如这里随机选了item 7,那么bufferitem 7对应的位置就空出来了。 然后,从Dataset顺序选择最新的一条数据填充到buffer,这里是item 10。 然后在从Buffer
话不多说,看代码 代码git链家:https://github.com/lankuohsing/TensorFlowStudy/blob/master/dataset_usage/shuffle_batch_repeat.py # -*- coding: utf-8 -*- Created on Fri Dec 4 21:08:13 2020 @author: lankuohsing import tensorflow as tf import numpy as np # In[]
f = plt.figure(figsize=(12, 7)) f.suptitle('Label Counts for a Sample of Clients') row = 2 col = 3 for i in range(row * col): client_dataset = dataset.shuffle(buffer_size=len(train_images)) client_dataset = dataset.batch(batch_size=10) example = next(iter(client_dataset)) label = example['label'].numpy() unique_values, value_counts = np.unique(label, return_counts=True) plt.subplot(row, col, i+1) plt.bar(unique_values, value_counts) plt.title('Client {}'.format(i)) plt.show()该段代码如何实现每幅直方图的每一列颜色不一致
可以在每个子图使用不同的颜色来绘制每个标签的条形。将颜色列表作为参数传递给plt.bar()函数即可,例如: colors = ['r', 'g', 'b', 'c', 'm', 'y'] for i in range(row * col): client_dataset = dataset.shuffle(buffer_size=len(train_images)) client_dataset = dataset.batch(batch_size=10) example = next(iter(client_dataset)) label = example['label'].numpy() unique_values, value_counts = np.unique(label, return_counts=True) plt.subplot(row, col, i+1) plt.bar(unique_values, value_counts, color=colors[:len(unique_values)]) plt.title('Client {}'.format(i)) plt.show()