Python слишком много памяти - PullRequest
1 голос
/ 01 февраля 2020

Я импортирую разреженные матрицы из файла .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

Здесь вы , 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>

Так что я думаю проблема с созданием объекта при импорте. Есть ли способ избежать этого? Или я что-то не так делаю при импорте разреженных матриц? Спасибо.

Ответы [ 3 ]

1 голос
/ 02 февраля 2020

Создайте разреженную матрицу:

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>

M1 и M3 одинаковы - csr как M для save_npz, csc (формат 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)

Выполняет умножение M*1 для каждого элемента ones - создание 1000 разреженных матриц. Вот куда уходит потребление вашей памяти.

В итоге, при использовании savez он оборачивает каждую разреженную матрицу в массив dtype объекта и выполняет выборку. Поэтому вы не должны использовать `data ['Dx'] напрямую

Dx = data['Dx']  # wrong
Dx = data['Dx'].item()    # right
0 голосов
/ 02 февраля 2020

Расчет хорошо подходит для операций на месте:

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'])

, который не создает дополнительных временных массивов. Если вы также избегаете загрузки других переменных, которые не требуются для этого вычисления c, вы сэкономите дополнительную память. Выполнение работы внутри функции - это хороший способ обеспечить очистку / освобождение памяти после завершения работы. В вашем случае, возможно, лучше заплатить штраф за чтение и просто прочитать данные, необходимые для каждого такого расчета. Хотя, как сказал Хпаульдж, магов c можно найти не намного; это большой набор данных, который потребует много памяти. Любой способ уменьшить размер / разрешение проблемы или работать в меньших блоках?

0 голосов
/ 01 февраля 2020

Мне удалось решить эту проблему с помощью scipy.io.savemat () и scipy.io.loadmat () . Я использовал np.savz () и np.load () раньше, и это занимало слишком много памяти.

...