我正在研究一个基本归结为求解矩阵方程的项目
A.dot(x) = d
其中A
是一个尺寸大约为10 000 000到2000年的矩阵(我想最终在两个方向上增加这个)。
A
显然不适合内存,所以必须并行化。我通过解决A.T.dot(A).dot(x) = A.T.dot(d)
来做到这一点。 A.T
的维度为2000到2000.可以通过将A
和d
划分为块A_i
和d_i
,沿着行计算{{} { 1}}和A_i.T.dot(A_i)
,并总结这些。非常适合并行化。我已经能够使用多处理模块实现这一点,但是由于内存使用,1)很难进一步扩展(在两个维度中增加A_i.T.dot(d_i)
),2)不漂亮(因此不容易保持)。
Dask似乎是一个非常有前途的解决这两个问题的库,我做了一些尝试。我的A
矩阵计算起来很复杂:它基于大约15个不同的数组(大小等于A
中的行数),有些用于迭代算法来评估相关的勒让德函数。当块很小(10000行)时,构建任务图需要很长时间,并且需要大量内存(内存增加与对迭代算法的调用一致)。当块较大(50000行)时,计算前的内存消耗要小得多,但在计算A
时会很快耗尽。我尝试过使用A.T.dot(A)
,但它会大大减慢计算速度。
任务图必须非常大且复杂 - 调用cache.Chest
崩溃。使用更简单的A._visualize()
矩阵,它可以直接执行此操作(请参阅@MRocklin的响应)。有没有办法让我简化它?
如何解决这个问题的任何建议都将受到高度赞赏。
作为一个玩具示例,我尝试了
A
这也失败了,只耗尽了只有一个核心处于活动状态的所有内存。使用A = da.ones((2e3, 1e7), chunks = (2e3, 1e3))
(A.T.dot(A)).compute()
,所有核心几乎立即启动,但{1}在1秒内出现(我当前计算机上有15 GB)。 chunks = (2e3, 1e5)
更有希望,但最终消耗了所有内存。 击>
编辑: 我突破了玩具示例测试,因为尺寸错误,并修正了其余部分的尺寸。正如@MRocklin所说,它确实适用于正确的尺寸。我添加了一个我现在认为与我的问题更相关的问题。
EDIT2:
这是我试图做的一个简化的例子。我认为,问题在于定义MemoryError
中的列所涉及的递归。
chunks = (2e3, 1e4)
这似乎导致了一个非常复杂的任务图,它在计算开始之前占用了大量内存。
我现在通过将递归放在一个带有A
数组的函数中来解决这个问题,并且或多或少做import dask.array as da
N = 1e6
M = 500
x = da.random.random((N, 1), chunks = 5*M)
# my actual
A_dict = {0:x}
for i in range(1, M):
A_dict[i] = 2*A_dict[i-1]
A = da.hstack(tuple(A_dict.values()))
A = A.rechunk((M*5, M))
ATA = A.T.dot(A)
。
作为第二个注释,一旦我有numpy
矩阵任务图,直接计算A = x.map_blocks(...)
似乎会给出一些内存问题(内存使用不是很稳定)。因此,我以块为单位明确地计算它,并对结果求和。即使有这些解决方法,dask在速度和可读性方面也有很大的不同。
答案 0 :(得分:1)
你的输出非常大。
>>> A.T.dot(A).shape
(10000000, 10000000)
也许你打算用另一个方向的转置计算这个?
>>> A.dot(A.T).shape
(2000, 2000)
这仍然需要一段时间(这是一个很大的计算)但它确实完成了。