Numpy矩阵乘积 - 稀疏矩阵

时间:2017-03-01 14:55:47

标签: python numpy sparse-matrix

让我们将矩阵A视为对角矩阵,将矩阵B视为随机矩阵,两者的大小均为N×N。 我们希望使用矩阵A的稀疏属性来优化点积,即点(B,A)。

但是,如果我们使用矩阵A的稀疏性来计算产品,我们就看不到任何优势(而且速度要慢得多)。

import numpy as np
from scipy.sparse import csr_matrix
# Matrix sizes
N = 1000

#-- matrices generation --
A = np.zeros((N,N), dtype=complex)
for i in range(N):
    A[i][i] = np.random.rand()
B = np.random.rand(N,N)

#product
%time csr_matrix(B).dot(A)
%time np.dot(B,A)

结果:

CPU时间:用户3.51秒,sys:8毫秒,总计:3.52秒 壁挂时间:3.74秒

CPU时间:用户348 ms,sys:0 ns,总计:348 ms 壁挂时间:230毫秒

如何正确地做到这一点?

2 个答案:

答案 0 :(得分:3)

如果矩阵确实稀疏,则向右,稀疏点更快。但是你不能只是将数组抛入csr_matrix.dot函数。

In [68]: N=1000
In [69]: from scipy import sparse
In [70]: A=np.eye(N)         # the diagonal is more interesting than all zeros
In [71]: B=np.random.rand(N,N)

基础案例 - 密集矩阵产品

In [72]: timeit np.dot(B,A)
10 loops, best of 3: 98.8 ms per loop

对于所有相同大小的数组(例如dot(B,B)dot(A,A)),此时间相同。

从两者中制作稀疏矩阵。 As有很多零,Bs没有,但格式稀疏

In [73]: As=sparse.csr_matrix(A)
In [74]: Bs=sparse.csr_matrix(B)

请注意转换时间;它们不是微不足道的

In [101]: timeit sparse.csr_matrix(A)
100 loops, best of 3: 13.8 ms per loop
In [102]: timeit sparse.csr_matrix(B)
10 loops, best of 3: 50.1 ms per loop

使用csr矩阵的Matrix产品可以更快。我将使用Bs.dot(As)表单,因为它更清晰。 Bs*Asnp.dot(Bs,As)是等效的。但请勿尝试np.dot(Bs,A)

In [107]: timeit Bs.dot(As)
100 loops, best of 3: 19 ms per loop

In [112]: timeit sparse.csr_matrix(B).dot(sparse.csr_matrix(A)).A
10 loops, best of 3: 94.1 ms per loop

明显优于密集版本,但如果我们包含转换时间则稍微好一些。

但请注意,时间差异很大,取决于矩阵的稀疏性

In [108]: timeit As.dot(Bs)
100 loops, best of 3: 10 ms per loop
In [109]: timeit As.dot(B)
100 loops, best of 3: 5.82 ms per loop
In [110]: timeit As.dot(As)
1000 loops, best of 3: 215 µs per loop
In [111]: timeit Bs.dot(Bs)
1 loop, best of 3: 3.83 s per loop

答案 1 :(得分:2)

差异源于你在时间(次要影响)期间将B转换为稀疏矩阵的事实,更糟糕的是,dot并未意识到A稀疏。如果您要在点积之前进行转换,则稀疏点积实际上更快:

import numpy as np
from scipy.sparse import csr_matrix
# Matrix sizes
N = 1000

#-- matrices generation --
A = np.zeros((N,N), dtype=complex)
for i in range(N):
    A[i][i] = np.random.rand()
B = np.random.rand(N,N)

Asparse = csr_matrix(A)
Bsparse = csr_matrix(B)

%timeit np.dot(B, A)
%timeit csr_matrix(B).dot(A)
%timeit Bsparse.dot(A)
%timeit csr_matrix.dot(B, Asparse)
%timeit csr_matrix.dot(Bsparse, Asparse)

给出:
np.dot(B, A):1循环,最佳3:414 ms每循环
csr_matrix(B).dot(A):1循环,最佳3:2.22秒每循环
Bsparse.dot(A):1循环,最佳3:每循环2.17秒 csr_matrix.dot(B, Asparse):10个循环,最佳3:32.5 ms每循环
csr_matrix.dot(Bsparse, Asparse):10个循环,最好是每个循环3:28毫秒

正如您所看到的,稀疏点产品在A处于稀疏矩阵格式且使dot意识到这一事实的所有情况下都快得多,A是稀疏的。在您的计时中,该函数实际上将B转换为稀疏格式,然后转换为具有密集矩阵A的点积。