Topic: numpy array e big data: Memory error!  (Letto 169 volte)

0 Utenti e 1 Visitatore stanno visualizzando questo topic.

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
numpy array e big data: Memory error!
« il: Giugno 23, 2019, 17:51 »
Buona sera,
sono nuovo del forum. Mi sto approcciando alla programmazione in Python per analizzare immagini di risonanza magnetica per la mia tesi. Ho bisogno di trattare migliaia di immagini in un singolo programma. Ogni immagine è 3D ed ha 260*311*260=21 milioni di pixel circa.
 Per motivi computazionali il mio codice necessita di implementare una matrice con 21 milioni di righe e migliaia di colonne. Per ora sto iniziando con un centinaio di immagini, per cui è sufficiente una matrice (21 milioni) x (100). La mia memoria RAM da 16 gb è messa a dura prova.


Ogni volta che provo a fare il reshape di una singola immagine in un vettore colonna con 21 milioni di elementi, il programma mi dà Memory error. Riesce a gestire al massimo 7 immagini di questo tipo in forma matriciale. Ho controllato la gestione applicazioni mentre il programma viene eseguito e in realtà la memoria RAM occupata non supera in toto gli 8 gb (durante tale esecuzione). Esiste un modo per gestire la memoria ram allocabile in un interprete python?

Forse in questo caso potrei cavarmela utilizzando le matrici sparse, ma questo metodo è oneroso dal punto di vista computazionale. E comunque questo problema si potrebbe ripresentare in seguito, nel caso in cui debba utilizzare una mole di dati maggiore.

Qualcuno di voi può darmi una mano? voi come lo risolvereste questo problema?

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #1 il: Giugno 23, 2019, 20:31 »
Non ci hai detto quanti bit per pixel usi. Io ad esempio sto lavorando su immagini da 12 bit per pixel (che opencv mi scala a 16 all'apertura).
Inoltre, stai usando qualche compressione? Lossy or lossless?

Inoltre, 260^2 * 311 * 4 byte (assumendo siano float32) / 1024 /1024 fa circa 80 MB a immagine. Confermi?
Questa cifra e' ancora gestibile, direi.
Ora ..

> Per motivi computazionali il mio codice necessita di implementare una matrice con 21 milioni di righe e migliaia di colonne
Qua pero' non si capisce ogni colonna di questa matrice cosa e'.
1) una immagine delle N? Quindi hai una unica matrice di P pixel x N immagini (righe x colonne)?
2) Oppure le altre colonne dopo la prima sono altri dati associati all'immagine? Perche' se e' questo il caso, ossia le altre colonne sono metadati, probabilmente non saranno dense, quindi una matrice sparsa potrebbe aiutare; dipende sempre pero' da cosa devi farci dopo pero'.

Nel caso 1 della singola matrice, e' semplice: lavora temporaneamente a blocchi, ossia su sottomatrice P x M, dove M immagini < N, in modo che la singola matrice ci stia tutta in memoria, e poi ti sposti alle M immagini seguenti finche' non hai macinato tutte le N immagini.

Nel caso 2, avrai N matrici; lavora su M matrici < N immagini.


> Esiste un modo per gestire la memoria ram allocabile in un interprete python?
Cosa intendi con questo? Python da solo continua a chiedere memoria al sistema operativo, finche' questo non gli risponde picche quando l'ha finita.

> Forse in questo caso potrei cavarmela utilizzando le matrici sparse, ma questo metodo è oneroso dal punto di vista computazionale
Certo, lavorarci sopra e' oneroso, ma e' meglio che non poterci lavorare perche' vai OOM, convieni?

Io cercherei di ridurre in ogni caso le dimensioni del problema.
Magari usando un'immagine a minore qualita'?
Oppure riducendo le colonne della/e matrice/i?

Oppure scalando in verticale, se pensi che il problema possa stare dentro limiti di macchine moderne (esistono macchine con 1 TB di ram che puoi usare su aws, se devi solo lavorarci sopra poche ore costa un paio di euro -- dai un occhio anche alle spot instances), oppure puoi scalare in orizzontale su piu' nodi, usando cose tipo spark o layer di comunicazione tipo MPI (ma qua puo' diventare complessa la cosa). Il vantaggio dello scalare in verticale e' che se hai tutto in memoria eviti di dover caricare ogni volta da disco e sprecare preziosi cicli CPU.

Consiglio di implementare una strategia di checkpointing, perche' vuoi evitare di ricalcolare cose gia' fatte.

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re:numpy array e big data: Memory error!
« Risposta #2 il: Giugno 23, 2019, 22:30 »
Non ci hai detto quanti bit per pixel usi. Io ad esempio sto lavorando su immagini da 12 bit per pixel (che opencv mi scala a 16 all'apertura).
Inoltre, stai usando qualche compressione? Lossy or lossless?

Inoltre, 260^2 * 311 * 4 byte (assumendo siano float32) / 1024 /1024 fa circa 80 MB a immagine. Confermi?
Questa cifra e' ancora gestibile, direi.
Ora ..

> Per motivi computazionali il mio codice necessita di implementare una matrice con 21 milioni di righe e migliaia di colonne
Qua pero' non si capisce ogni colonna di questa matrice cosa e'.
1) una immagine delle N? Quindi hai una unica matrice di P pixel x N immagini (righe x colonne)?
2) Oppure le altre colonne dopo la prima sono altri dati associati all'immagine? Perche' se e' questo il caso, ossia le altre colonne sono metadati, probabilmente non saranno dense, quindi una matrice sparsa potrebbe aiutare; dipende sempre pero' da cosa devi farci dopo pero'.

Nel caso 1 della singola matrice, e' semplice: lavora temporaneamente a blocchi, ossia su sottomatrice P x M, dove M immagini < N, in modo che la singola matrice ci stia tutta in memoria, e poi ti sposti alle M immagini seguenti finche' non hai macinato tutte le N immagini.

Nel caso 2, avrai N matrici; lavora su M matrici < N immagini.


> Esiste un modo per gestire la memoria ram allocabile in un interprete python?
Cosa intendi con questo? Python da solo continua a chiedere memoria al sistema operativo, finche' questo non gli risponde picche quando l'ha finita.

> Forse in questo caso potrei cavarmela utilizzando le matrici sparse, ma questo metodo è oneroso dal punto di vista computazionale
Certo, lavorarci sopra e' oneroso, ma e' meglio che non poterci lavorare perche' vai OOM, convieni?

Io cercherei di ridurre in ogni caso le dimensioni del problema.
Magari usando un'immagine a minore qualita'?
Oppure riducendo le colonne della/e matrice/i?

Oppure scalando in verticale, se pensi che il problema possa stare dentro limiti di macchine moderne (esistono macchine con 1 TB di ram che puoi usare su aws, se devi solo lavorarci sopra poche ore costa un paio di euro -- dai un occhio anche alle spot instances), oppure puoi scalare in orizzontale su piu' nodi, usando cose tipo spark o layer di comunicazione tipo MPI (ma qua puo' diventare complessa la cosa). Il vantaggio dello scalare in verticale e' che se hai tutto in memoria eviti di dover caricare ogni volta da disco e sprecare preziosi cicli CPU.

Consiglio di implementare una strategia di checkpointing, perche' vuoi evitare di ricalcolare cose gia' fatte.
grazie mille per la risposta, mi hai dato tante informazioni utili.
Il formato dei file è di tipo nifti. Credo che la compressione sia senza perdita, ma non ne sono sicuro.
Per il momento vorrei evitare di buttare via parte dei dati, perché vorrei capire come si comporta l'algoritmo che devo implementare con il dato completo.

 Le immagini le ho impostate in float32. Anche a me questo sembra un problema trattabile, infatti non capisco perché mi dia MemoryError.
 La struttura dati che desidero creare è la seguente: Voglio "vettorizzare" ogni singola immagine, farla diventare un enorme vettore colonna. Poi voglio mettere insieme tutti questi vettori colonna in un'unica matrice e lavorare direttamente con quest'ultima. Siccome ho già verificato che queste immagini sono piene di zeri, forse conviene lavorare direttamente con le matrici sparse.
Il mio problema però si verifica prima che riesca a rendere sparsa la matrice densa della singola immagine. Allora, io riesco a caricare tutte le immagini (che compresse sono di 12 Mb l'una), poi prendo una sola immagine, riesco a caricare la matrice 3D corrispondente a tale immagine. Dopodiché l'interprete mi dà memoryError quando provo a vettorizzare l'immagine, utilizzando numpy.reshape. Non capisco perché. Ho tenuto d'occhio le prestazioni della RAM in gestione applicazioni, mentre il programma girava. In pratica la memoria utilizzata passava da 7 gb a 8 gb, dopodiché il programma si stoppava e mi dava l'errore. Mi sembra strana questa cosa. Forse non viene usata tutta la ram disponibile. Non è così?

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #3 il: Giugno 24, 2019, 12:18 »
Okay, quindi vuoi creare una singola matrice con P righe (num pixel) e N colonne (num immagini), ma il programma va in oom non appena provi a cambiare shape alla prima immagine.
Il fatto e' che stai usando 80 MB per un'immagine non compressa, ma dici che vai a saturare la memoria di 16 GB. Ci dev'essere qualche casino prima del reshape. Tieni aperto un terminale con un top o htop, e tieni d'occhio l'uso di ram e swap; magari non lo vedi, ma per passare 8 GB a 16 GB basta un attimo.

> Forse non viene usata tutta la ram disponibile. Non è così?
No. Ripeto, se python ha bisogno, la prende. Non ci sono dei limiti esterni, python (o meglio, cpython, che e' quello che viene usato al 99%) e' un normale eseguibile C, che chiede al OS finche' ha bisogno.


Cosi' ad intuito direi che fai qualche altra operazione che non ci hai detto oltre al "leggo da file e faccio il reshape", e quasi sicuramente ci sara' una duplicazione di dati da qualche parte.
Probabilmente la matrice di cui cerchi di fare un reshape non e' in realta' una matrice ma una lista di liste, e il reshape e' costretto a farla diventare una matrice prima di poterci lavorare?
Perche' l'azione del reshape e' "Gives a new shape to an array without changing its data.", quindi non dovrebbe toccare i dati, se sono gia' in forma di array, ma se la funzione o libreria che usi per caricare l'immagine te la carica ad es come lista di liste, potrebbe essere un problema per la manipolazione seguente.

Riesci a creare un esempio riproducibile *minimale*?
Qua ad esempio ho trovato un test dataset che potresti usare per , se non vuoi rendere pubbliche le tue immagini; https://nifti.nimh.nih.gov/nifti-1/data

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re:numpy array e big data: Memory error!
« Risposta #4 il: Giugno 25, 2019, 15:52 »
Okay, quindi vuoi creare una singola matrice con P righe (num pixel) e N colonne (num immagini), ma il programma va in oom non appena provi a cambiare shape alla prima immagine.
Il fatto e' che stai usando 80 MB per un'immagine non compressa, ma dici che vai a saturare la memoria di 16 GB. Ci dev'essere qualche casino prima del reshape. Tieni aperto un terminale con un top o htop, e tieni d'occhio l'uso di ram e swap; magari non lo vedi, ma per passare 8 GB a 16 GB basta un attimo.

> Forse non viene usata tutta la ram disponibile. Non è così?
No. Ripeto, se python ha bisogno, la prende. Non ci sono dei limiti esterni, python (o meglio, cpython, che e' quello che viene usato al 99%) e' un normale eseguibile C, che chiede al OS finche' ha bisogno.


Cosi' ad intuito direi che fai qualche altra operazione che non ci hai detto oltre al "leggo da file e faccio il reshape", e quasi sicuramente ci sara' una duplicazione di dati da qualche parte.
Probabilmente la matrice di cui cerchi di fare un reshape non e' in realta' una matrice ma una lista di liste, e il reshape e' costretto a farla diventare una matrice prima di poterci lavorare?
Perche' l'azione del reshape e' "Gives a new shape to an array without changing its data.", quindi non dovrebbe toccare i dati, se sono gia' in forma di array, ma se la funzione o libreria che usi per caricare l'immagine te la carica ad es come lista di liste, potrebbe essere un problema per la manipolazione seguente.

Riesci a creare un esempio riproducibile *minimale*?
Qua ad esempio ho trovato un test dataset che potresti usare per , se non vuoi rendere pubbliche le tue immagini; https://nifti.nimh.nih.gov/nifti-1/data
Sono abbastanza sicuro che python non prelevi la memoria che richiede l'interprete. Infatti ho provato a fare un'analoga operazione con Matlab ed il software non mi dà problemi fino a 50-60 immagini.
Posto un esempio di codice per far capire cosa sto facendo

import nilearn as ni
import nibabel as nib
import numpy as np
def vettorizza_dati(database_path,dati_brain):#va preso un elemento alla volta della lista dati_brain
    #organizziamo i dati in una matrice X, le cui colonne rappresentino le immagini ordinate in maniera vettoriale

    immagine=nib.load(database_path+'\\'+dati_brain)
    #n=immagine.shape[0]*immagine.shape[1]*immagine.shape[2]
    n=311*260*260
    matrice_immagine=immagine.get_fdata().reshape((1,n))
    print('ok')
    return matrice_immagine

...
...
#main prima parte


Matrici_immagini=np.zeros((260*311*260,2))
i=0
for elemento in dati_brain[i:i+2]:
    Matrici_immagini[:,i]=vettorizza_dati(database_path,elemento)
    i+=1


con questo codice a volte dà memory error anche semplicemente per np.zeros, mentre con matlab riesco a costruire matrici (260*311*260,50). Non so, forse c'è un problema con le librerie che utilizzo?

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #5 il: Giugno 26, 2019, 16:26 »
Purtroppo il codice che hai postato non e' riproducibile, quindi non posso confermare quale sia il problema.

> questo codice a volte dà memory error anche semplicemente per np.zeros

Eh, non penso che si arrabbi "solo" per np.zeros, ci sara' qualcos'altro prima che satura la memoria, e np.zeros non ne puo' piu' chiedere e si pianta.
E comunque quel np.zeros che mostri sono gia' 320 MB di dati che vanno in memoria.
Cosi' senza poter vedere un pezzo di codice riproducibile non possiamo dirti quale sia il problema. Probabilmente starai caricando male in memoria le tue immagini.

Il fatto che da task manager/top/htop tu non veda l'utilizzo della memoria arrivare a 16 GiB non e' causato da python che e' "limitato"; puoi provarlo facilmente con:
>>> np.zeros(10000000000000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError


Il memory error appare quando python chiede memoria al tuo sistema operativo, e questo non ne ha abbastanza per allocarla. Non e' che il SO inizia ad occuparne fino a saturare e poi da errore, semplicemente fa (memoria libera - memoria richiesta) < 0 --> memory error.

NON ci sono "limitazioni" a quanta memoria puo' usare python, non c'e' una VM tipo java di mezzo, e' un "semplice" programma, scritto in C e compilato. L'ho usato per farci calcolo scientifico su macchine carrozzate da qualche centinaio di GB di memoria.

Puoi controllare la memoria libera nel sistema con una system call a 'free -m' o qualcosa del genere su windows: https://stackoverflow.com/questions/41931787/how-to-use-all-available-memory
Vedrai che quando si rompera' il programma, sara' perche' hai chiesto troppa memoria rispetto a quella totale disponibile, anche se fosse solo 1 byte di troppo.

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re:numpy array e big data: Memory error!
« Risposta #6 il: Giugno 26, 2019, 20:14 »
Purtroppo il codice che hai postato non e' riproducibile, quindi non posso confermare quale sia il problema.

> questo codice a volte dà memory error anche semplicemente per np.zeros

Eh, non penso che si arrabbi "solo" per np.zeros, ci sara' qualcos'altro prima che satura la memoria, e np.zeros non ne puo' piu' chiedere e si pianta.
E comunque quel np.zeros che mostri sono gia' 320 MB di dati che vanno in memoria.
Cosi' senza poter vedere un pezzo di codice riproducibile non possiamo dirti quale sia il problema. Probabilmente starai caricando male in memoria le tue immagini.

Il fatto che da task manager/top/htop tu non veda l'utilizzo della memoria arrivare a 16 GiB non e' causato da python che e' "limitato"; puoi provarlo facilmente con:
>>> np.zeros(10000000000000)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
MemoryError


Il memory error appare quando python chiede memoria al tuo sistema operativo, e questo non ne ha abbastanza per allocarla. Non e' che il SO inizia ad occuparne fino a saturare e poi da errore, semplicemente fa (memoria libera - memoria richiesta) < 0 --> memory error.

NON ci sono "limitazioni" a quanta memoria puo' usare python, non c'e' una VM tipo java di mezzo, e' un "semplice" programma, scritto in C e compilato. L'ho usato per farci calcolo scientifico su macchine carrozzate da qualche centinaio di GB di memoria.

Puoi controllare la memoria libera nel sistema con una system call a 'free -m' o qualcosa del genere su windows: https://stackoverflow.com/questions/41931787/how-to-use-all-available-memory
Vedrai che quando si rompera' il programma, sara' perche' hai chiesto troppa memoria rispetto a quella totale disponibile, anche se fosse solo 1 byte di troppo.
Grazie per la risposta.
Dall'ultima volta ho fatto progressi. Ho capito che la libreria nibabel mette di default in cache le matrici che estrae dai dati. Ovviamente anche jupyter notebook va liberato prima di un nuovo run.
Comunque ho rinunciato per il momento a creare un'unica matrice. Sto lavorando con i cicli for, file per file. Questo implica comunque un dispendio di tempo maggiore e non mi permette di sfruttare numpy al massimo delle sue potenzialità. Pazienza, proverò almeno a presentare un algoritmo funzionante, poi col tempo lo modificherò.
Comunque ho provato un codice semplicissimo su jupyter.


import numpy as np
D=np.zeros((20000000,50))

mi dà il seguente errore:

---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-4-29b0f700e80f> in <module>
      1 import numpy as np
----> 2 D=np.zeros((20000000,50),dtype=np.int)

ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size.


A parità di condizioni, apro matlab e scrivo 'zeros(20000000,50)' e funziona. Alloca la memoria, lasciando 250 Mb liberi. Mi piacerebbe capire come mai. Forse il modulo numpy pesa più di 250 Mb?
(e non sto contando la memoria che succhia matlab di suo)

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #7 il: Giugno 26, 2019, 22:26 »
Ah ma non ci avevi mai detto che stavi girando in un jupyter notebook.
Occhio che talvolta ci sono dei memory leak in jupyter o dipendenze, e se il jupyter server viene lasciato girare per tanto tempo, tende a non restituire piu' la memoria; ad es questa e' una vecchia issue di una dipendenza https://github.com/jupyter/notebook/issues/642

Prova anche jupyterlab (pip install jupyterlab), e' la nuova versione di jupyter nb.

Infine: il fatto che quando provi ad allocare qualcosa di grosso e ti dica: "ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size." anziche' OOM, potrebbe essere causato dal fatto che stai usando un sistema a 32bit (difficile oggigiorno), oppure (molto piu' facilmente) una build di python a 32bit; proviamo a vedere (preso da qua: https://stackoverflow.com/questions/1405913/) se c'e' un 32bit di mezzo:
$ python -c 'import sys;print("%x" % sys.maxsize, sys.maxsize > 2**32)'
$ python -c 'import struct;print( 8 * struct.calcsize("P"))'


In 32bit un processo puo' gestire al max 2^32 indirizzi in memoria, circa 4 GiB, e questo potrebbe spiegare molte cose.

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re:numpy array e big data: Memory error!
« Risposta #8 il: Giugno 27, 2019, 18:32 »
Ah ma non ci avevi mai detto che stavi girando in un jupyter notebook.
Occhio che talvolta ci sono dei memory leak in jupyter o dipendenze, e se il jupyter server viene lasciato girare per tanto tempo, tende a non restituire piu' la memoria; ad es questa e' una vecchia issue di una dipendenza https://github.com/jupyter/notebook/issues/642

Prova anche jupyterlab (pip install jupyterlab), e' la nuova versione di jupyter nb.

Infine: il fatto che quando provi ad allocare qualcosa di grosso e ti dica: "ValueError: array is too big; `arr.size * arr.dtype.itemsize` is larger than the maximum possible size." anziche' OOM, potrebbe essere causato dal fatto che stai usando un sistema a 32bit (difficile oggigiorno), oppure (molto piu' facilmente) una build di python a 32bit; proviamo a vedere (preso da qua: https://stackoverflow.com/questions/1405913/) se c'e' un 32bit di mezzo:
$ python -c 'import sys;print("%x" % sys.maxsize, sys.maxsize > 2**32)'
$ python -c 'import struct;print( 8 * struct.calcsize("P"))'


In 32bit un processo puo' gestire al max 2^32 indirizzi in memoria, circa 4 GiB, e questo potrebbe spiegare molte cose.
ho provato a girare in vari modi, non solo con jupyter.
Jupyter lab è molto migliorato rispetto al notebook, grazie. Comunque si, sto girando con una build  a 32bit. Il problema è che ho provato a modificare questa cosa ma non ci sono riuscito. Puoi darmi un consiglio su come fare? io ho installato python usando il pacchetto a 64bit, non capisco perché di default sia a 32 bit

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #9 il: Giugno 28, 2019, 09:35 »
Su che sistema operativo sei? Come hai installato python? O l'hai trovato gia' installato?

Offline mimmo1988

  • python unicellularis
  • *
  • Post: 6
  • Punti reputazione: 0
    • Mostra profilo
Re:numpy array e big data: Memory error!
« Risposta #10 il: Giugno 28, 2019, 10:42 »
Su che sistema operativo sei? Come hai installato python? O l'hai trovato gia' installato?
ok, grazie mille. Ho risolto. Ci ho messo molto tempo perché ho dovuto eliminare tutte le dipendenze. Ora funziona tutto. Con Python in 64 bit il problema non si ripropone. Sei stato gentilissimo, grazie

Offline bebo

  • python erectus
  • ***
  • Post: 238
  • Punti reputazione: 0
    • Mostra profilo
    • bebo_sudo's personal homepage
Re:numpy array e big data: Memory error!
« Risposta #11 il: Giugno 28, 2019, 11:50 »
Aiuta anche i futuri lettori. Come hai risolto?