scipy.sparse.csr_matrix.toarray()的内存占用较大

4

我有一个相当大的稀疏矩阵 A,它是一个scipy.sparse.csr_matrix类型。 它具有以下属性:

A.shape: (77169, 77169)
A.nnz: 284811011
A.dtype: dtype('float16')

现在我需要使用.toarray()将其转换为稠密数组。我对内存使用的估计是

77169**2 * (16./8.) / 1024.**3 = 11.09... GB

由于我的计算机有约48GB的内存,因此这应该是可行的。事实上,如果我创建a=np.ones((77169, 77169), dtype=np.float16),那么这个操作可以正常工作,而且a.nbytes/1024.**3 = 11.09...。然而,当我在稀疏矩阵上运行A.toarray()时,它会占用所有内存并开始使用交换空间(它不会引发MemoryError)。这里出了什么问题?难道它不应该轻松地适合我的内存吗?


你使用的是哪个版本的scipy?可以通过import scipy; print(scipy.__version__)来检查。 - Warren Weckesser
哦,对了,我忘了:SciPy版本是0.15.1。 - obachtos
1个回答

1
对于 csrtoarray() 的作用是将其转换为数组形式。
self.tocoo(copy=False).toarray(order=order, out=out)

你可以继续跟踪coo.toarray,但我怀疑它最终会使用编译后的代码。但我认为它最终会执行以下操作:

In [715]: M=sparse.random(10,10,.2,format='csr')
In [717]: M=M.astype(np.float16)
In [718]: A = np.zeros(M.shape, M.dtype)
In [719]: Mo=M.tocoo()
In [720]: A[Mo.row, Mo.col] = Mo.data

奇怪的是,如果我执行

操作。
In [728]: Mo.toarray()
     ...
    257         coo_todense(M, N, self.nnz, self.row, self.col, self.data,
--> 258                     B.ravel('A'), fortran)
    259         return B
...
ValueError: Output dtype not compatible with inputs.

这里遇到了 float16 的问题。使用 Mo.astype(float).toarray() 没有问题。即使使用 float16 输出的 toarray(out=out) 也会出现错误,这让我怀疑 coo_todense 只编译了几个 dtype 选项。也许我稍后会深入研究。

In [741]: scipy.__version__
Out[741]: '0.18.1'

Warren的错误报告中的一条评论

但是xxx_todense函数实际上是A += X,

表明从Mo.dataA[]的复制比所示的更加复杂。toarray会合并重复项,就像使用Mo.tocsr()Mo.sum_duplicates()一样。


FYI:我在Scipy的Github存储库中创建了一个问题,以解决这个错误:https://github.com/scipy/scipy/issues/7408 - Warren Weckesser
1
“float16”不受支持的评论引发了一个问题,即这种数据类型与哪些其他操作能够正常工作或不能正常工作。 “M*M”可以正常工作,但会产生一个“float32”。显然,在将数组传递给编译代码之前,它会转换数据类型。 - hpaulj
好的,这让我有两个解决方法:(1)使用float32的csr_matrix,转换为dense,然后再转换为float16;或者(2)使用float16的csr_matrix,并像你上面建议的那样手动转换为dense。它们似乎都可以工作,但前者似乎是更安全的选择,正如@WarrenWeckesser在问题中所述:“我认为float16不是一种受支持的稀疏矩阵类型”。谁知道还会出现什么其他问题.... - obachtos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接