达斯克(Dask):凸矩阵优化

时间:2019-11-14 16:43:19

标签: dask

我目前正在尝试实现Dask进行凸矩阵优化。目标是对内存不足矩阵执行矩阵优化(分解)。以一个高矩阵为输入,以两个高矩阵为输出,以及一些参数(例如收敛等),我使用dask数组对原始矩阵和中间/输出矩阵进行分块。最后,在将先前迭代的输出用作新迭代的输入的意义上,这些迭代是顺序的(请参见下面的简单示例)。

在每次迭代中,必须计算两个条件并检查其收敛性(最终if语句)。但是,如果执行如下所示的代码,我会发现Dask会计算标准(由if语句强制执行),但随后会在每次迭代中重新计算其他矩阵:例如,迭代1,标准已正确计算,迭代2不使用先前找到的A和E,而是重新计算它们,从而得到两次SVD评估,依此类推。 Dask似乎没有认识到A_hat和E_hat在上一次迭代中已经计算过的事实,然后从头开始重新计算这些值。反之亦然,它会重新计算该条件的所有步骤。

在内存中保留这些矩阵也不是一种选择,因为它们会随着时间在内存中累积。我在博客文章(https://matthewrocklin.com/blog/work/2017/03/22/dask-glm-1http://matthewrocklin.com/blog/work/2017/04/19/dask-glm-2)中看到了类似的优化,但是似乎每次迭代都有可能将结果存储在内存中,而对于我的优化则是不可​​能的。我尝试了不同的设置,在其中设置了一些值,或者使用了同步和异步的持久性和计算功能。

因此,我的问题是,如何在每次迭代结束时不对矩阵(A和E,以及扩展名为Y)进行计算并将其放置在内存中,同时又如何对它们进行一些计算呢?我有一些使用期货的想法,或者明确地延迟所有单个步骤。其中一种解决方案可以解决我的问题,还是有更有效的方法?

预先感谢

罗杰

def PCP(D, lambda_i, kmax):
    
    # Initialize norms
    normD = (norm(D, 'fro')).compute()
    normD2 = (norm(D, 2)).compute()
    normDinf = (norm(D.ravel(), np.inf)).compute()

    # Initialize Y
    Y = (1/np.maximum(normD2, (1/lambda_i)*normDinf))*D

    # Initialize A and A_hat
    A = da.zeros_like(D)
    A_hat = da.zeros_like(D)
    
    # Initialize E and E_hat
    E = da.zeros_like(D)
    E_hat = da.zeros_like(D)

    # Initialize mu: mu_0 > 0
    mu = 1.25/normD2 # Convergence Rate

    # Initialize rho: rho > 1
    rho = 1.6 # Convergence Rate

    runAlgorithm = True
    k = 0
    while runAlgorithm:
        
        # Estimate E_hat
        E_hat = da.maximum((D-A+(1/mu)*Y)-(1/mu)*lambda_i, 0)+da.minimum((D-A+(1/mu)*Y)+(1/mu)*lambda_i, 0)
        
        # Estimate A_hat
        Q = da.linalg.svd(D-E_hat+(1/mu)*Y)
        svp = (Q[1] - 1/mu).clip(0)
        A_hat = (Q[0]*svp)@Q[2]
        
        # Update Y
        Y = Y+mu*(D-A_hat-E_hat)
        
        # Calculate stopping criteria
        crit1 = norm(D-A_hat-E_hat, 'fro')/normD
        crit2 = norm(E-E_hat, 'fro')/normD
        
        # Update A and E
        A = A_hat
        E = E_hat
        
        # Check if Converged
        if k == kmax or crit1 < 0.01 or crit2 < 0.01:
            runAlgorithm = False
    
        k = k + 1
        

    return  A, E, k, crit1, crit2

我使用以下快捷分布式设置:

from dask.distributed import Client, progress
client = Client(threads_per_worker=4,
            n_workers=1, memory_limit='4GB')

1 个答案:

答案 0 :(得分:0)

我不确定我是否完全理解您的问题,但是在这里我会说一些您可能已经知道的一般性事情。

如果可以在内存中放入一些结果,则应考虑在这些部分上调用persist以避免重复工作。如果您无法将它们容纳在内存中,那么我不确定在这里可以做什么。使高效的算法像您上面描述的那样,在很大程度上涉及确定需要将计算的哪些部分保持为小状态,以及每次都需要重新计算哪些部分。

例如,您可能想看看matrix algorithms in dask-glm,它可以有效地执行此舞蹈。