使用dask进行3D体积处理

时间:2017-03-21 22:49:57

标签: python multidimensional-array filtering convolution dask

我现在正在使用dask使用一些简单的模板来探索3D交互式卷卷积。 让我解释一下我的意思:

  • 假设您有想要通过Sobel Transform处理的3D数据(例如,获取L1或L2渐变)。
  • 然后将输入的3D图像划分为子体积(有一些重叠的边界 - 对于3x3x3模板Sobel,它将需要+2个样本重叠/填充)
  • 现在让我们假设您在整个3D体积上创建了Sobel 3D变换的延迟计算 - 但尚未执行。

现在是最重要的部分:

  • 我想写一个函数,它将从虚拟转换的数据中提取一些特定的2D部分。
  • 最后让dask一切来计算:
    • 但我需要做的就是不为我计算整个变换然后提供一个部分。
      • 我需要它只执行计算特定2D变换图像切片所需的那些任务。

您认为 - 这可能吗?

为了用图像解释它 - 请考虑这是一个3D域分解(这是来自DWT - 但很适合插图from here):

illistration of domain decomposition

并假设有一个函数使用dask计算整个卷的3D变换。 但我想得到的 - 例如 - 是转换后的3D数据的2D图像,它包含LLL1,LLH1,HLH1,HLL1平面(基本上是单个切片

重要的部分不是计算整个子多维数据集 - 但是让dask以某种方式自动跟踪计算图中的依赖关系并仅评估那些。

请不要担心计算vs.复制时间。 假设它具有完美的比例。

如果需要进一步澄清,请告诉我! 谢谢你的帮助!

2 个答案:

答案 0 :(得分:2)

我听到了几个问题。我会单独回答每个

  • Dask可以跟踪输出子集所需的任务,只计算那些任务吗?

是。 Lazy Dask操作生成依赖图。在dask.arrays的情况下,这个图是每个块。如果您的输出仅依赖于图形的子集,那么Dask将删除不必要的任务。对此的深入文档特别是herecull优化。

作为一个例子,考虑这个100,000乘100,000的数组

>>> x = da.random.random((100000, 100000), chunks=(1000, 1000))

让我说我从中添加了几个1d切片

>>> y = x[5000, :] + x[:, 5000].T

生成的优化图仅足以计算输出

>>> graph = y._optimize(y.dask, y._keys())  # you don't need to do this
>>> len(graph)                              # it happens automatically
301

我们可以很快地计算结果:

In [8]: %time y.compute()
CPU times: user 3.18 s, sys: 120 ms, total: 3.3 s
Wall time: 936 ms
Out[8]: 
array([ 1.59069994,  0.84731881,  1.86923216, ...,  0.45040813,
        0.86290539,  0.91143427])

现在,这并不完美。它确实必须生成我们的两个切片触及的所有1000x1000块。但是你可以控制粒度。

简短回答:Dask会自动检查图表,只运行评估输出所需的那些任务。你不需要做任何特别的事情来做这件事。

  • 使用dask.array进行重叠数组计算是个好主意吗?

也许。相关文档页面位于Overlapping Blocks with Ghost Cells。 Dask.array具有便利功能,可以轻松记录下来。但是它会创建内存中的副本。你职位的很多人发现记忆太慢了。 Dask通常不支持就地计算,因此我们不能像正确的MPI代码那样高效。我会把性能问题留给你。

答案 1 :(得分:1)

不要减损来自@MRocklin的精心设计的答案,但要添加更多内容。

我还经常发现自己需要对大规模阵列数据进行边缘检测和其他图像处理技术。由于Dask是一个非常好的库,用于构建和探索大型数据上的此类计算工作流,因此在一个名为dask-image的GitHub组织中为一些常见的图像处理技术组合了一些实用程序库。它们主要用于模仿SciPy的ndimage API。

对于使用带有Dask的Sobel运算符,可以使用sobel中的dask-ndfilters函数(允许许可)在Dask数组上执行此操作。它处理引擎盖下方块上正确的晕圈,返回一个新的Dask阵列。

由于SciPy的sobel函数(以及dask-ndfilters' sobel)在一个维度上运行,因此需要在每个轴上进行映射并堆叠以获得完整索贝尔算子结果。也就是说,这很简单。下面是一个简短的片段,展示了如何在随机Dask数组上执行此操作。还包括沿着XZ平面切片。虽然可以轻松地采取任何其他切片或对数据执行其他操作。

希望这会有所帮助。 :)

import dask.array as da
import dask_ndfilters as da_ndfilt

d = da.random.random((100, 120, 140), chunks=(25, 30, 35))
ds = da.stack([da_ndfilt.sobel(d, axis=i) for i in range(d.ndim)])
dsp = ds[:, :, 0, :]
asp = dsp.compute()