Передача массива Dask несовместима с разреженными матрицами - PullRequest
0 голосов
/ 23 апреля 2019

Я работаю над алгоритмом, который использует Dask, чтобы избежать ошибок памяти, так как данные кажутся слишком большими для обработки на моем компьютере.На одном из шагов алгоритма я хочу использовать матрицу коэффициентов (и разреженную) coefs с формой (M, N) и выполнить поэлементное умножение на массив T с формой (K, M, N), состоящей из K MxN матриц.Поскольку coef является разреженной матрицей, я хотел бы принять это во внимание вместо работы с плотным массивом.

Я использую следующую конфигурацию:

  • PythonВерсия: 3.7.3
  • Версия Numpy: 1.16.2
  • Версия Dask: 1.2.0
  • Версия Scipy: 1.2.1
  • Редкая версия:0.7.0

Я испробовал три различных варианта.

Версия 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()

Код выдаст ошибку, если параметр, переданный в func_test, будет coef_2 или coef_3.

Если параметр coef_2 Python вызывает значение 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 для измерения времени выполнения:

  • С coef_1: 869 ms ± 52.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • С coef_2: 322 ms ± 3.98 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • С coef_3: 249 ms ± 2.82 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

Мой вопрос: возможно ли выполнять операции, используя N-мерные массивы Dask с разреженными матрицами?Назначение на место

T *= coef

, кажется, экономит много времени.

Некоторые заметки

Я пытался использовать

T = coef.multiply(coef_2)

, ноэто увеличивает время выполнения:

4.65 s ± 173 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
  • Значения M и N будут больше, чем показанные в коде, отсюда и требование к dask.

  • Я использую Dask, но предложения приветствуются.В частности, операция:

T = P3[:, None, None] * (P1[:, :, None] @ P2[:, None, :])

вызывает MemoryError на моем компьютере, когда матрицы слишком велики.

...