解决稀疏的线性方程组时,为什么会出现内存错误?

时间:2019-05-20 12:36:43

标签: python matlab numpy scipy sparse-matrix

当尝试从下面求解大型的稀疏线性方程组时,我只得到了MemoryError:。我该如何解决这个问题?

此外,该代码基于Matlab的实现,应该可以正常运行。在原始版本中,M是一个三维矩阵,我不知道是否由于修改将M转换为二维scipy.sparse.lil_matrix(而不是{ {1}})st我可以迭代地填写coo

M

这是我得到的错误的回溯:

def dectrans(features, faces, template):
    """
    Decode transformation matrix.

    features : shape (3*N) numpy.ndarray
    faces : (Nx3) array
    template : (Nx3) array
    """
    ftrs = features

    weight = 1

    fixvertex = 1
    fixto = np.zeros((3))

    # M shape originally (len(template), len(template), 10 * len(template))
    M = scipy.sparse.lil_matrix((len(template)+fixvertex, len(template) * 10 * len(template)))
    dx = scipy.sparse.lil_matrix((len(template)+fixvertex,3))

    # build laplacian system
    for i in range(len(faces)):
        v = faces[i,:]
        ...
        M[v][:,v] = M[v][:,v] + WIJ # WIJ some 3x3 matrix
        dx[v,:] = dx[v,:] + WIJ.dot(x.T)

    weight = np.ones((fixvertex)) * weight

    for i in range(fixvertex):
        M[len(template)+i, fixvertex-1] = weight[i]

    dx[len(template):len(template),:] = fixto.dot(np.tile(weight, (3))) 

    M = np.real(M)
    dx = np.real(dx)
    Mt = M.T
    model = scipy.sparse.linalg.spsolve(Mt @ M, Mt.dot(dx)) # here I get the error

    return model

1 个答案:

答案 0 :(得分:2)

回溯应该显示问题是出在spsolve上还是在创建一个或两个自变量Mt@MMt.dot(dx)时。

具有Mdx形状的((6891, 474721000)(6891, 3)

 Mt@M
 (474721000,6891) + (6891, 474721000) => (474721000, 474721000)
 Mt.dot(dx)   # why not Mt@dx?
 (474721000,6891) + (6891, 3) => (474721000, 3)

取决于这些变量中的非零结构,@乘积可能比M具有更多的非零,这可能会产生内存错误。一个或另一个的追溯可能有助于我们进行诊断。

更常见的是,内存错误是由于尝试从稀疏数组创建密集数组而引起的,但在这里似乎确实如此。但是再次,追溯可以帮助排除这种情况。

如果逐步填充矩阵值,建议使用

lil格式。 csr用于矩阵乘积,但是sparse可以根据需要将lil转换为csr。所以这不应该是一个问题。

===

使用1个非零元素创建稀疏矩阵:

In [263]: M=sparse.lil_matrix((1000,100000))                                 
In [264]: M                                                                  
Out[264]: 
<1000x100000 sparse matrix of type '<class 'numpy.float64'>'
    with 0 stored elements in LInked List format>
In [265]: M[0,0]=1                                                           
In [266]: M                                                                  
Out[266]: 
<1000x100000 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in LInked List format>

@不会产生内存错误,并且如预期的那样,结果只有1个非零项。但是运行此程序存在明显的延迟,这表明它正在进行大量计算:

In [267]: M.T@M                                                              
Out[267]: 
<100000x100000 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in Compressed Sparse Row format>

在等效的@上执行相同的csr不会造成时间延迟:

In [268]: M1=M.tocsr()                                                       
In [269]: M1.T@M1                                                            
Out[269]: 
<100000x100000 sparse matrix of type '<class 'numpy.float64'>'
    with 1 stored elements in Compressed Sparse Column format>

===

您提到了MATLAB中的3d稀疏矩阵。您必须使用某种第三方扩展或变通方法,因为MATLAB稀疏限制为2d(至少是我几年前在FEM工作中使用它的时候)。

scipy.sparse csc格式类似于MATLAB的内部稀疏格式。实际上,这就是通过savescipy.io.loadmat传输矩阵所得到的。 csr与之类似,但具有行方向。

当我在MATLAB中创建FEM刚度矩阵时,我使用了scipy coo输入的等效项。也就是说,创建datarowcol的3个数组。将coo转换为csr时,将添加重复元素,从而巧妙地处理FEM元素的子矩阵重叠。 (此行为在scipy和MATLAB中是相同的。

按照您的要求反复添加lil矩阵(如果索引正确的话),但是我希望它会慢得多。