Я работаю над алгоритмом, который использует 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
на моем компьютере, когда матрицы слишком велики.