Python占用太多内存

Python taking too much of memory

我正在从 .npz 文件导入稀疏矩阵。下面是代码的脚本。稀疏矩阵 (Dx, Dy, ..., M) 的大小为 373248x373248,存储了 746496 个元素。

if runmode == 2:
        data = np.load('Operators2.npz', allow_pickle=True)

    Dx = data['Dx']
    Dy = data['Dy']
    Dz = data['Dz']
    Dxx = data['Dxx']
    Dyy = data['Dyy']
    Dzz = data['Dzz']
    Dxp = data['Dxp']
    Dyp = data['Dyp']
    Dzp = data['Dzp']
    M = data['M']
    del data

如果我打印变量之一,例如 Dx,我得到以下输出:

array(<373248x373248 sparse matrix of type '<class 'numpy.float64'>'
    with 746496 stored elements in Compressed Sparse Column format>,
      dtype=object)

但是我的系统内存增加了,程序崩溃了。当我执行下面的代码行时,程序崩溃了。我没有收到任何错误,但程序崩溃了。

DIV = Dx*u+Dy*v+Dz*w

即使我执行以下代码行,内存消耗也会增加,程序会崩溃

DIV = data['Dx']*u+data['Dy']*v+data['Dz']*w

这里 u,v,w 的形状是 373248x1。 DIV 的形状是 373248x1。由于Dx、Dy、Dz是稀疏矩阵,所以Dx*u做矩阵向量乘法,给出一个向量。

如果在同一个代码中,我实际计算Dx,Dy,...,M内存是没有问题的。如果我正在计算 Dx,那么输出如下:

<373248x373248 sparse matrix of type '<class 'numpy.float64'>'
    with 746496 stored elements in Compressed Sparse Column format>

所以我认为在导入时创建对象存在问题。有没有办法避免这种情况?或者,我在导入稀疏矩阵时做错了什么? 谢谢你。

我使用 scipy.io.savemat() and scipy.io.loadmat() 解决了这个问题。我之前使用 np.savz() 和 np.load() 并且占用了太多内存。

制作一个稀疏矩阵:

In [38]: M = sparse.random(1000,1000,.2,'csr')                                                 

3 种不同的保存方式:

In [39]: from scipy import io                                                                  
In [40]: np.savez('Msparse.npz', M=M)                                                          
In [41]: sparse.save_npz('M1sparse',M)                                                         

In [43]: io.savemat('Msparse.mat', {'M':M})                                                    

文件大小:

In [47]: ll M1spa* Mspar*                                                                      
-rw-rw-r-- 1 paul 1773523 Feb  1 12:40 M1sparse.npz
-rw-rw-r-- 1 paul 2404208 Feb  1 12:41 Msparse.mat
-rw-rw-r-- 1 paul 2404801 Feb  1 12:39 Msparse.npz

加载 3 个矩阵:

In [48]: M1=sparse.load_npz('M1sparse.npz')                                                    
In [49]: M2=np.load('Msparse.npz',allow_pickle=True)['M']                                      
In [50]: M3=io.loadmat('Msparse.mat')['M']                                                     
In [51]: M1                                                                                    
Out[51]: 
<1000x1000 sparse matrix of type '<class 'numpy.float64'>'
    with 200000 stored elements in Compressed Sparse Row format>
In [52]: M2                                                                                    
Out[52]: 
array(<1000x1000 sparse matrix of type '<class 'numpy.float64'>'
    with 200000 stored elements in Compressed Sparse Row format>,
      dtype=object)
In [53]: M3                                                                                    
Out[53]: 
<1000x1000 sparse matrix of type '<class 'numpy.float64'>'
    with 200000 stored elements in Compressed Sparse Column format>

M1M3 是相同的 - csr 就像 M 对于 save_npzcsc(MATLAB 格式)对于 .mat.

M2 有一个对象 dtype 包装器。

In [54]: (M1*np.ones((1000,1))).shape                                                          
Out[54]: (1000, 1)
In [55]: (M3*np.ones((1000,1))).shape                                                          
Out[55]: (1000, 1)

这花了很多时间;结果差点不敢看

In [56]: (M2*np.ones((1000,1))).shape                                                          
Out[56]: (1000, 1)

如果我从对象数组中提取矩阵,乘法很快

In [57]: (M2.item()*np.ones((1000,1))).shape                                                   
Out[57]: (1000, 1)
In [58]: (M2.item()*np.ones((1000,1))).dtype                                                   
Out[58]: dtype('float64')
In [59]: (M3*np.ones((1000,1))).dtype                                                          
Out[59]: dtype('float64')

仔细观察 M2 乘法:

In [60]: (M2*np.ones((1000,1))).dtype                                                          
Out[60]: dtype('O')
In [61]: (M2*np.ones((1000,1)))[:2,:]                                                          
Out[61]: 
array([[<1000x1000 sparse matrix of type '<class 'numpy.float64'>'
    with 200000 stored elements in Compressed Sparse Row format>],
       [<1000x1000 sparse matrix of type '<class 'numpy.float64'>'
    with 200000 stored elements in Compressed Sparse Row format>]],
      dtype=object)

它对 ones 的每个元素执行 M*1 乘法 - 生成 1000 个稀疏矩阵。那就是你的内存消耗的去向。

总之,当使用 savez 时,它将每个稀疏矩阵包装在一个对象 dtype 数组中,并进行 pickle。所以你不应该直接使用`data['Dx']

Dx = data['Dx']  # wrong
Dx = data['Dx'].item()    # right

该计算非常适合就地操作:

np.multiply(data['Dx'], u, out=data['Dx']
np.multiply(data['Dy'], v, out=data['Dy']
np.multiply(data['Dz'], w, out=data['Dz']
numpy.add(data['Dx'], data['Dy'], out=data['Dx'])
numpy.add(data['Dx'], data['Dz'], out=data['Dx'])

这不会创建额外的临时数组。如果您还避免加载此特定计算不需要的其他变量,您将节省额外的内存。在函数内部完成工作是确保工作完成后清理/释放内存的好方法。在您的情况下,最好支付阅读罚款并只读​​入每次此类计算所需的特定数据。尽管就像 hpaulj 所说的那样,您找不到更多的魔法;这是一个大数据集,需要大量内存。有什么方法可以减小问题的大小/分辨率,或者在更小的块中解决它?