【问题标题】:Numpy matrix product - sparse matricesNumpy 矩阵乘积 - 稀疏矩阵
【发布时间】:2017-07-20 23:19:15
【问题描述】:

让我们将矩阵 A 视为对角矩阵,将矩阵 B 视为随机矩阵,两者的大小均为 N x N。 我们想利用矩阵 A 的稀疏特性来优化点积,即 dot(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 秒,系统:8 毫秒,总计:3.52 秒 挂起时间:3.74 秒

CPU 时间:用户 348 毫秒,系统:0 纳秒,总计:348 毫秒 挂墙时间:230 毫秒

如何正确做?

【问题讨论】:

  • %time csr_matrix(B).dot(A) 首先将B 转换为csr_matrix。你也想计时吗?
  • 但是 B 不是稀疏矩阵。 csr_matrix 应该只应用于稀疏矩阵。
  • 我会说只有在矩阵非常大且非常稀疏时才使用稀疏矩阵方法。 np.dot 在正常情况下效率极高。
  • 可能我没有正确解释我的问题。我想利用 A 稀疏来做 np.dot(B,A)。
  • 查看我的答案以获得更详细的解释。

标签: python numpy sparse-matrix


【解决方案1】:

做得对,稀疏点更快 - 如果矩阵确实是稀疏的。但是您不能只将数组放入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 矩阵的矩阵乘积可以更快。我将使用Bs.dot(As) 表单,因为它更清晰。 Bs*As 和 np.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

【讨论】:

    【解决方案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 毫秒
    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 毫秒
    csr_matrix.dot(Bsparse, Asparse):10 循环,最佳 3:每循环 28 毫秒

    正如您所看到的,在A 采用稀疏矩阵格式的所有情况下,稀疏点积要快得多,这使dot 意识到A 是稀疏的这一事实。在您的时间里,该函数实际上是将B 转换为稀疏格式,然后是具有密集矩阵A 的点积。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-04
      • 2013-11-10
      • 2018-01-18
      • 1970-01-01
      • 2016-08-15
      • 2014-03-06
      • 2021-11-25
      相关资源
      最近更新 更多