首页 文章

Scipy稀疏矩阵 - 密集向量乘法性能 - 块与大矩阵

提问于
浏览
7

我有一些scipy稀疏矩阵(目前是CSR格式),我需要与密集的numpy 1D向量相乘 . 该向量称为 G

print G.shape, G.dtype
(2097152,) complex64

每个稀疏矩阵都具有形状 (16384,2097152) 并且非常稀疏 . 密度约为4.0e-6 . 我有一个名为 spmats 的100个稀疏矩阵的列表 .

我可以很容易地将每个矩阵乘以 G ,如下所示:

res = [spmat.dot(G) for spmat in spmats]

这导致形状 (16384,) 的密集矢量列表如预期的那样 .

我的应用程序是相当性能的,所以我尝试了另一种方法,即首先将所有稀疏矩阵连接成一个大的sparce矩阵,然后只使用一次 dot() 调用,如下所示:

import scipy.sparse as sp
SPMAT = sp.vstack(spmats, format='csr')
RES = SPMAT.dot(G)

这导致一个长向量 RES 具有形状 (1638400,) ,并且是上面 res 中所有结果向量的连接版本,如预期的那样 . 我检查过结果是一样的 .

也许我关心连接稀疏矩阵所需的时间,只关心计算结果的时间 . 但是根据 %timeit

%timeit res = [spmat.dot(G) for spmat in spmats]
10 loops, best of 3: 91.5 ms per loop
%timeit RES = SPMAT.dot(G)
1 loops, best of 3: 389 ms per loop

我已经检查过,在任何一个操作中我都没有内存不足,似乎没有任何可疑的事情发生 . 我疯了,还是真的很奇怪?这是否意味着所有稀疏矩阵向量乘积应该以块为单位,一次几行,以使它们更快?据我所知,具有密集向量的稀疏矩阵乘法时间在非零元素的数量上应该是线性的,在上述两种情况下不变 . 有什么可以产生这样的差异?

我使用EPD7.3运行在4GB内存的单核linux机器上运行

编辑:

这是一个为我重现问题的小例子:

import scipy.sparse as sp
import numpy as n

G = n.random.rand(128**3) + 1.0j*n.random.rand(128**3)

spmats = [sp.rand (128**2, 128**3, density = 4e-6, format = 'csr', dtype=float64) for i in range(100)]
SPMAT = sp.vstack(spmats, format='csr')

%timeit res = [spmat.dot(G) for spmat in spmats]
%timeit RES = SPMAT.dot(G)

我明白了:

1 loops, best of 3: 704 ms per loop
1 loops, best of 3: 1.34 s per loop

在这种情况下的性能差异不如我自己的具有某种结构的稀疏矩阵(可能是因为缓存)那么大,但是连接矩阵仍然更糟 .

我尝试了scipy 10.1和12.0 .

1 回答

  • 4

    我没有找到问题中提到的奇怪行为的原因,但是我找到了一种方法来显着加快我的计算速度,这可能对其他人有用 .

    因为在我的特定情况下,我正在计算float32稀疏矩阵和complex64密集向量的乘积,我可以分别乘以实部和虚部 . 这为我提供了4倍的加速 .

    这需要2.35秒 SPMAT.shape == (16384000, 2097152)

    RES = SPMAT.dot(G)
    

    虽然这只需要541毫秒:

    RES = n.zeros((SPMAT.shape[0],),dtype=complex64)
    RES.real = SPMAT.dot(G.real); RES.imag = SPMAT.dot(G.imag)
    

    结果是一样的 . 我想也许 n.zeros 预分配可能不是必要的,但我不知道如何做到这一点 .

相关问题