interleave
是一种tf.Data.Dataset
方法,可用于将来自多个数据集的元素交错在一起。 tf.contrib.data.parallel_interleave
在apply
的帮助下提供了相同功能的并行版本。
我可以看到,并行版本允许并行读取许多数据集并为它们提供缓冲区将提高吞吐量。但是documentation也可以说明parallel_interleave
如何提高数据吞吐量:
与tf.data.Dataset.interleave不同,它从cycle_length获取元素 并行嵌套数据集,这会增加吞吐量, 特别是在散居者面前。
究竟什么是落后者,为什么parallel_interleave
在他们面前的吞吐量方面效果特别好?
答案 0 :(得分:6)
落后者是一种比平时更长的功能来产生它的输出。这可能是由于网络拥塞或随机性的怪异组合造成的。
interleave
在一个线程上以顺序方式完成所有处理。在以下架构中,让___
表示等待IO / Computation ,<waiting>
表示等待轮到一个元素和{{1 }}表示生成第一个元素(111
)。
假设我们有一个目录1
的数据集,我们从每个目录生成文件ds = [A, B, C, D]
。然后使用1,2,3...
将有点像这样:
r = ds.interleave(cycle_length=3, block_length=2)
您会看到,如果从B散布中生成元素,则所有后续元素都必须等待处理。
A: ___111___222
B: <waiting> ___111___________222
C: <waiting> <waiting> <waiting> ___111___222
R: ____A1____A2____B1____________B2____C1____C2
以两种方式帮助落后者。首先,它以并行的方式启动循环中的每个元素(因此名称)。因此,生产模式变为:
parallel_interleave
这样做有助于通过并行等待减少无用的等待。部分A: ___111___222
B: ___<waiting>111___________222
C: ___<waiting><waiting><waitin>111___222
R: ____A1____A2_B1____________B2_C1____C2|....|
显示我们与顺序版本相比节省了多少。
第二种方式是允许|....|
参数。如果我们将其设置为sloppy
,则允许跳过不可用的元素,直到它可用为止,代价是产生非确定性的顺序。以下是:
True
看看那个节省!!但也要看元素的顺序!
我在代码中重现这些。这是一种丑陋的方式,但它稍微说明了一些差异。
A: ___111___<w>222
B: ___<w>111___________222
C: ___<w><w>111___222
R: ____A1_B1_C1_A2_C2___B2|...................|
这是显示数据集的功能
from time import sleep
DS = tf.data.Dataset
def repeater(val):
def _slow_gen():
for i in range(5):
if i % 2:
sleep(1)
yield i
return DS.from_generator(_slow_gen, tf.int8)
ds = DS.range(5)
slow_ds = ds.interleave(repeater, cycle_length=2, block_length=3)
para_ds = ds.apply(tf.contrib.data.parallel_interleave(
repeater, cycle_length=2, block_length=3)
)
sloppy_ds = ds.apply(tf.contrib.data.parallel_interleave(
repeater, cycle_length=2, block_length=3, sloppy=True)
)
%time apply_python_func(slow_ds, print, sess)
# 10 sec, you see it waiting each time
%time apply_python_func(para_ds, print, sess)
# 3 sec always! you see it burping a lot after the first wait
%time apply_python_func(sloppy_ds, print, sess)
# sometimes 3, sometimes 4 seconds