2017-05-01 110 views
2

我试图计算一个矩阵X的大小为10,000 * 800,000的矩阵乘积Y = XX^T。矩阵X存储在磁盘上的一个h5py文件中。生成的Y应该是存储在同一个h5py文件中的10,000 * 10,000矩阵。这是一个可重现的示例代码。dask核心外矩阵乘法调度

import dask.array as da 
from blaze import into 

into("h5py:///tmp/dummy::/X", da.ones((10**4, 8*10**5), chunks=(10**4,10**4))) 
x = into(da.Array, "h5py:///tmp/dummy::/X", chunks=(10**4,10**4))) 
y = x.dot(x.T) 
into("h5py:///tmp/dummy::/Y", y) 

我预计计算,以顺利进行,因为每个(10,000 * 10,000)块应单独换位,后面跟着一个点的产品,然后总结出最终结果。但是,运行此计算会填充我的RAM和交换内存,直到进程最终被终止。

这里是计算图的绘制样品与dot_graph:Computation graph sample

按照SHEDULING文件,让HTTP://dask.pydata.org/en/latest/scheduling-policy.html 我期望一旦个体计算出来,上面的tensordot中间结果被一个一个地总结为最后的总和结果。这将释放这些tensordot中间结果的记忆,以便我们不会面对记忆错误。

用较小的玩具如玩周围:

from dask.diagnostics import Profiler, CacheProfiler, ResourceProfiler 

# Experiment on a (1,0000 * 5,000) matrix X split into 500 chunks of size (1,000 * 10) 
x = into(da.Array, "h5py:///tmp/dummy::/X", chunks=(10**3,10)))[:10**3,5000] 
y = x.T.dot(x) 
with Profiler() as prof, CacheProfiler() as cprof, ResourceProfiler() as rprof: 
    into("h5py:///tmp/dummy::/X", y) 
rprof.visualize() 

我得到以下显示: Ressource profiler

凡绿条代表和操作,而黄色和紫色柱代表分别get_array和tensordot操作。这似乎表明总和操作在总结它们之前等待所有中间tensordot操作被执行。这也将解释我的流程耗尽内存并被杀死。

所以我的问题是:

  • 是该和操作的正常行为?
  • 有没有办法强制它计算所有中间产品tensordot产品计算并保存在内存中的中间和?
  • 如果没有,是否有解决方案不涉及溢出到磁盘?

任何帮助非常感谢!

回答

0

一般来说,在小空间中执行密集矩阵乘法很难。这是因为每个中间块都会被几个输出块使用。

按照SHEDULING文件,让HTTP://dask.pydata.org/en/latest/scheduling-policy.html我希望上tensordot中间结果由一个概括一个到最后一笔只要他们已经被单独计算,结果。

你已经显示的图有很多输入到总和函数。在运行求和函数之前,Dask将等待所有这些输入完成。任务调度程序不知道总和是关联的并且可以一个一个地运行。缺乏语义信息是您使用像Dask这样的通用任务调度系统而不是专门的线性代数库所支付的代价。如果你的目标是尽可能有效地执行密集的线性代数,那么你可能想看看其他地方;这是一个很好的领域。书面

所以你的内存需求至少8e5 * 1e4 * dtype.itemsize,假设在完全正确的顺序DASK收益(它应该大多做)。

你可以尝试以下操作:

  1. 沿非承包尺寸
  2. 使用版本DASK晚于0.14.1(0.14.2应该由5月5日发布,2017年减少CHUNKSIZE ),我们在图中明确地将这些大数据调用分解为许多较小的调用。
  3. 使用分布式调度程序,它可以更有效地处理将数据写入磁盘。

    from dask.distributed import Client 
    client = Client(processes=False) # create a local cluster in this process 
    
+0

非常感谢@MRocklin! – Grin

+0

关于选项3,我遇到了https://github.com/dask/distributed/issues/927中提到的问题。 Hdf5序列化阵列似乎不适合分布式调度器。修复它可以让我使用分布式调度程序的实时诊断/监视工具,这在这种情况下非常有用。另外,您是否知道pydata/python生态系统中的专门ooc线性代数库?我最初开始使用dask是因为它的核心线性代数特性与Numpy API结合在一起。 – Grin