首页 > 解决方案 > Dask 数组广播似乎与稀疏矩阵不兼容

问题描述

我正在研究一种使用 Dask 来避免内存错误的算法,因为数据似乎太大而无法在我的计算机上处​​理。在算法的一个步骤中,我想使用一个带有 shape 的系数(和稀疏)矩阵,coefs并对一个带有 shape(M, N) 的数组执行逐元素乘法,该数组由矩阵组成。由于是一个稀疏矩阵,我想考虑到这一点,而不是使用密集数组。T(K, M, N)K MxNcoef

我正在使用以下配置:

我尝试了三种不同的可能性。

版本 1

系数矩阵只是一个numpy.ndarray矩阵。

版本 2

系数矩阵是一个scipy.sparse.csr.csr_matrix矩阵。

版本 3

系数矩阵是一个sparse.coo.core.COO矩阵。

参考:https ://sparse.pydata.org/en/latest/


import numpy as np
import dask.array as da
import scipy.sparse as sp
import sparse

def func_test(coef):

    K, M, N, tol = 10, 2000, 800, 1e-7

    # Starting values
    P1 = np.random.rand(K,M)
    P1 /= P1.sum(1)[:, None]
    P2 = np.random.rand(K, N)
    P2 /= P2.sum(1)[:, None]
    P3 = np.random.rand(K)
    P3 /= P3.sum()

    # Convert arrays to dask
    P2 = da.from_array(P2, chunks=(1000))
    P3 = da.from_array(P3, chunks=(1000))

    # Threshold
    P1[P1 < tol] = tol
    P2[P2 < tol] = tol

    for iter_number in range(20):
        T = P3[:, None, None] * (P1[:, :, None] @ P2[:, None, :])
        T *= coef # Problematic line
        P1 = T.sum(2) / T.sum((1,2))[:,None]  # (K, M)
        P2 = T.sum(1) / T.sum((1,2))[:,None]
        P3 = T.sum((1,2)) / T.sum()
        # Threshold
        P1[P1 < tol] = tol
        P2[P2 < tol] = tol
    return T, P1, P2, P3

if __name__ == "__main__":
    # coef is a numpy.ndarray
    M, N = 2000, 800
    coef_1 = np.random.random((M, N))
    # Make it sparse
    coef_1[coef_1 < 0.92] = 0
    # coef is a scipy.sparse matrix
    coef_2 = sp.csr_matrix(coef_1)
    # coef is a sparse COO matrix
    coef_3 = sparse.COO.from_numpy(coef_1)

    T, P1, P2, P3 = func_test(coef_1)

    T = T.compute()

coef_2如果传递给 func_test 的参数是或,代码将引发错误coef_3

如果参数是coef_2Python,则会引发 ValueError:

ValueError: could not interpret dimensions

如果是coef_3,它会引发另一个 ValueError:

ValueError: Please make sure that the broadcast shape of just the sparse arrays is the same as the broadcast shape of all the operands.

%timeit在 IPython 上使用过来测量执行时间:

我的问题是:是否可以使用具有稀疏矩阵的 Dask N 维数组执行操作?就地分配

T *= coef

似乎可以节省很多时间。

一些笔记

我试过用

T = coef.multiply(coef_2)

但它增加了执行时间:

4.65 s ± 173 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
T = P3[:, None, None] * (P1[:, :, None] @ P2[:, None, :])

MemoryError当矩阵太大时,会在我的计算机上导致 a 。

标签: pythonnumpyscipydask

解决方案


推荐阅读