shuffle函数中的参数buffer_size

学习tensorflow的时候,在加载数据集部分(tf.data.Dataset)遇到了一个打乱数据集的函数shuffle,里面有一个参数buffer_size。官方文档描述为:
参数buffer_size:
一个 tf.int64 标量 tf.张量,表示此数据集中新数据集将从中采样的元素数
官方文档说明:
This dataset fills a buffer with elements, then randomly samples elements from this buffer, replacing the selected elements with new elements. For perfect shuffling, a buffer size greater than or equal to the full size of the dataset is required
此数据集用元素填充缓冲区,然后从此缓冲区中随机采样元素,用新元素替换所选元素。为了进行完美的随机排序,需要缓冲区大小大于或等于数据集的完整大小。

For instance, if your dataset contains 10,000 elements but is set to 1,000, then will initially select a random element from only the first 1,000 elements in the buffer. Once an element is selected, its space in the buffer is replaced by the next (i.e. 1,001-st) element, maintaining the 1,000 element buffer
例如,如果您的数据集包含 10,000 个元素,但设置为 1,000 个,则最初将仅从缓冲区中的前 1,000 个元素中选择一个随机元素。选择元素后,其在缓冲区中的空间将被替换为下一个(即 1,001-st)元素,从而保留 1,000 元素缓冲区。

函数为:
shuffle(
buffer_size, seed=None, reshuffle_each_iteration=None, name=None
)

buffer_size个人理解:
先看官方文档说明,‘a buffer size greater than or equal to the full size of the dataset is required’这句话说参数 buffer size需要大于或等于数据集的大小,但是用例里面, buffer size<数据集的大小,貌似有些许的冲突

eg1:buffer size小于数据集
我们有5个球命名为1-5,按顺序放置在一个有5个格子的盒子A里(全量数据),我们需要打乱它,取出3个球作为训练集,首先要准备另一个3个格子的盒子B(缓冲区)然后进行以下操作:
1.从A取1-3号球放置在盒子B;
2.随机从B中取出一个球,假设是2号;
3.4号球放置在盒子B的2号位,此时盒子B填充满(球编号为1-4-3),再随机取出一个球,比如1号球。
4.5号球放置在盒子B的1号位,此时盒子B填充满(球编号为5-4-3),再随机取出一个球,比如5号球。
5.随机抽取从B(3-4)中抽取3号;
6.随机抽取从B(4)中抽取4号;
7.最终会形成一个新的序列,即2-1-5-3-4

eg2:buffer size大于数据集
可以看作,每次随机不放回的抽走一个球,最终排出一个新的序列,少了顺序插值替换这一步

下面进行三组测试查看一下区别

##测试1
buffer_size=3 #盒子B大小为3
data = np.array([1, 2, 3, 4, 5]) #五个球排排坐
label = np.array([1, 1, 1, 0, 0]) #随便搞得标签
dataset = tf.data.Dataset.from_tensor_slices((data, label))
dataset = dataset.shuffle(buffer_size)
it = dataset.__iter__()
for i in range(5):
   x, y = it.next()
   print(x, y)

输出为:


tf.Tensor(2, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(5, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)
tf.Tensor(3, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(4, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)

测试2:buffer_size=6
某次运行结果


tf.Tensor(5, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)
tf.Tensor(4, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)
tf.Tensor(3, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(2, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)

测试3:buffer_size=1
运行结果:

tf.Tensor(1, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(2, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(3, shape=(), dtype=int64) tf.Tensor(1, shape=(), dtype=int64)
tf.Tensor(4, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)
tf.Tensor(5, shape=(), dtype=int64) tf.Tensor(0, shape=(), dtype=int64)

总结
1.在shuffle中,buffer size是一个必要的参数,查了一些博客,一般来说都是将buffer size设置为小于数据集大小,即和官方用例相同。(测试1)
2.尽管官方文档有冲突,但是如果buffer size需要大于数据集,就等于是一个普通的不放回抽样(测试2)
3.上述二者最明显的区别:测试2中,4和5号球可能会被首次抽中,而测试1则不行。
4.buffer 不能太小,比如测试3,极端情况下,数据等于没打乱。
猜测(无证明):
增加一个buffer的意义在于
1.数据量足够大时,有了buffer 之后可以增加随机性,随着数据的抽取,buffer 会变得越来越混乱,新的序列也会越来越混乱
2.还有一个是从打乱数据的储存来着手,即eg1中,第一次取出的2号小球放在哪里,第一种是放在新的数据集的第一个位置,第二种就是放在原数据集的1号位置,即放在盒子A的一号位,因为此时盒子A前三个储存位置是空置的。个人更倾向于第二种情况,因为这样避免了生成一个空置的新序列,也就是说将buffer作为一个置换空间。

这部分的疑惑来自官方文档用例和描述的矛盾,期待有更专业的答案0.0

这部分来自我学习过程中的一个小实验
学习项目链接

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

爱挠静香的下巴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值