对于大小大于(M,N)的大于内存的dask数组:如何从块=(1,N)重新块为块=(M,1)?

时间:2019-03-24 14:31:14

标签: dask dask-distributed

例如,为了沿整个轴应用以Numpy / Numba编码的IIR过滤器,我需要将size=(M, N)快数组从chunks=(m0, n0)换成{{1} }和chunks=(m1, N)

由于Dask避免重复执行任务,因此在rechunk-split / rechunk-merge期间,它将在内存中存储值得m1 < m0(x 2?)的数据。有没有一种优化图的方法来避免这种行为?

我知道从哪里可以找到有关优化Dask图的信息。但是,有没有一种方法可以调整调度策略以允许重复执行任务,或者(自动)重新安排图形以最大程度地减少重新绑定期间的内存使用?

这是一个最小的示例(对于(m0, N)chunks=(M, 1)的极端情况):

chunks=(1, N)

2 个答案:

答案 0 :(得分:2)

不幸的是,您处在最坏的情况下,您需要计算每个输入块,然后才能获得单个输出块。

Dask的重分块操作相当不错,并且在过渡期间它们会将它们重新分组为中等大小的块,因此这可能会在内存不足的情况下起作用,但是您肯定会把事情写到磁盘上。

简而言之,原则上您不需要做任何额外的事情。理论上,Dask的重分配算法应该可以解决这个问题。如果您愿意,可以使用threshold=block_size_limit=关键字重新组合。

答案 1 :(得分:0)

通过block_size_limit=关键字可以找到一种解决方案。

(下面,我使用一个较小的阵列,因为我没有80GB的磁盘可溢出。)

from dask import array as da
from dask.distributed import Client

# limit memory to 1 GB
client = Client(n_workers=1, threads_per_worker=1, memory_limit=1e9)

# Create 3.2 GB array
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))

# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph")  # 2000 nodes

# Compute
print(arr.mean().compute())  # Takes 11.9 seconds. Doesn't spill.

# re-create array and rechunk with block_size_limit=1e3
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))
arr = arr.rechunk((2e1, 2e4), block_size_limit=1e3)

# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph")  # 32539 nodes

# Compute
print(arr.mean().compute())  # Takes 140 seconds, spills ~5GB to disk.

# re-create array and rechunk with default kwargs
arr = da.random.uniform(-1, 1, size=(2e4, 2e4), chunks=(2e4, 1e1))
arr = arr.rechunk((2e1, 2e4))

# Check graph size
print(len(arr.__dask_graph__()), "nodes in graph")  # 9206 nodes

# Compute
print(arr.mean().compute())  # Worker dies at 95% memory use