2014-07-18 5 views
7

Ho un'immagine memorizzata come una matrice numerica 2d (possibilmente multi-d).Numpy View Reshape senza copia (2d finestra in movimento/scorrevole, falcate, strutture di memoria mascherate)

Posso creare una vista su quella matrice che riflette una finestra scorrevole 2D, ma quando modifico la finestra in modo che ogni riga sia una finestra appiattita (le righe sono finestre, la colonna è un pixel in quella finestra) python esegue una copia completa . Lo fa perché sto usando il classico trucco del passo e la nuova forma non è contigua nella memoria.

Ho bisogno di questo perché sto passando intere immagini di grandi dimensioni a un classificatore sklearn, che accetta le matrici 2d, dove non c'è alcuna procedura batch/partial fit e la copia espansa completa è troppo grande per la memoria.

La mia domanda: C'è un modo per farlo senza fare una copia completa della vista?

Credo che una risposta sarà (1) qualcosa su strides o gestione della memoria numpy che ho trascurato, o (2) una sorta di struttura di memoria mascherata per python che può emulare un array numpy anche a un pacchetto esterno come sklearn che include cython.

Questo compito di formazione su come spostare finestre di un'immagine 2d in memoria è comune, ma l'unico tentativo che conosco per spiegare direttamente le patch è il progetto Vigra (http://ukoethe.github.io/vigra/).

Grazie per l'aiuto.

>>> A=np.arange(9).reshape(3,3) 
>>> print A 
[[0 1 2] 
[3 4 5] 
[6 7 8]] 
>>> xstep=1;ystep=1; xsize=2; ysize=2 
>>> window_view = np.lib.stride_tricks.as_strided(A, ((A.shape[0] - xsize + 1)/xstep, (A.shape[1] - ysize + 1)/ystep, xsize, ysize), 
...  (A.strides[0] * xstep, A.strides[1] * ystep, A.strides[0], A.strides[1])) 
>>> print window_view 
[[[[0 1] 
    [3 4]] 

    [[1 2] 
    [4 5]]] 


[[[3 4] 
    [6 7]] 

    [[4 5] 
    [7 8]]]] 
>>> 
>>> np.may_share_memory(A,window_view) 
True 
>>> B=window_view.reshape(-1,xsize*ysize) 
>>> np.may_share_memory(A,B) 
False 
+4

penso che questo è impossibile, anche si passa un 'as_strided' array ad un classificatore sklearn, penso che la maggior parte (se non tutti) i classificatori copieranno i tuoi dati se non sono continui. – HYRY

+2

Sì, sono abbastanza sicuro che non si possa fare. Scusate. Se trovi un modo, fammelo sapere;) Inoltre: l'inserimento diretto di un'immagine potrebbe non essere una buona idea e le funzionalità di calcolo potrebbero risolvere il tuo problema. –

+1

Definisci definitivamente il numero (1), 'sklearn.feature_extraction.image.extract_patches' ti dà esattamente la vista di cui stai parlando, e la sua rimodellazione ne farà sicuramente una copia, secondo le regole di Numpy. Sei sicuro di aver bisogno di tutte le patch di molte immagini contemporaneamente? Si consiglia di esaminare gli algoritmi in linea/batch per qualunque sia il tuo obiettivo. Prova 'SGDClassifier' per esempio. – eickenberg

risposta

4

Il vostro compito non è possibile utilizzando solo passi, ma NumPy fa supporto un tipo di array che fa il lavoro. Con passi e masked_array puoi creare la vista desiderata per i tuoi dati. Tuttavia, non tutte le funzioni di NumPy supportano le operazioni con masked_array, quindi è possibile che lo scikit-learn non funzioni bene con queste.

Diamo prima un nuovo sguardo a ciò che stiamo cercando di fare qui. Considera i dati di input del tuo esempio. Fondamentalmente i dati sono solo un array 1-d in memoria, ed è più semplice se pensiamo a le falcate con quello. L'array sembra essere solo 2D, perché abbiamo definito la sua forma . Utilizzando passi, la forma potrebbe essere definito in questo modo:

from numpy.lib.stride_tricks import as_strided 

base = np.arange(9) 
isize = base.itemsize 
A = as_strided(base, shape=(3, 3), strides=(3 * isize, isize)) 

Ora l'obiettivo è quello di impostare tali passi avanti per base che ordina i numeri come nella matrice fine, B. In altre parole, stiamo chiedendo interi a e b tale che

>>> as_strided(base, shape=(4, 4), strides=(a, b)) 
array([[0, 1, 3, 4], 
     [1, 2, 4, 5], 
     [3, 4, 6, 7], 
     [4, 5, 7, 8]]) 

Ma questo è chiaramente impossibile. La vista più vicina che possiamo ottenere come questo è con una finestra mobile su base:

>>> C = as_strided(base, shape=(5, 5), strides=(isize, isize)) 
>>> C 
array([[0, 1, 2, 3, 4], 
     [1, 2, 3, 4, 5], 
     [2, 3, 4, 5, 6], 
     [3, 4, 5, 6, 7], 
     [4, 5, 6, 7, 8]]) 

Ma la differenza qui è che abbiamo colonne e righe in più, che vorremmo sbarazzarsi. Quindi, in effetti, stiamo chiedendo una finestra mobile che non sia contigua e che effettui anche salti a intervalli regolari . Con questo esempio vogliamo che ogni terzo elemento sia escluso dalla finestra e saltare sopra un elemento dopo due righe.

possiamo descrivere questo come un masked_array:

>>> mask = np.zeros((5, 5), dtype=bool) 
>>> mask[2, :] = True 
>>> mask[:, 2] = True 
>>> D = np.ma.masked_array(C, mask=mask) 

Questo array contiene esattamente i dati che vogliamo, ed è solo una vista ai dati originali. Possiamo confermare che i dati sono uguali

>>> D.data[~D.mask].reshape(4, 4) 
array([[0, 1, 3, 4], 
     [1, 2, 4, 5], 
     [3, 4, 6, 7], 
     [4, 5, 7, 8]]) 

Ma come ho detto all'inizio, è molto probabile che scikit-learn non capisce gli array mascherati. Se si converte semplicemente questo ad un array , i dati saranno sbagliato:

>>> np.array(D) 
array([[0, 1, 2, 3, 4], 
     [1, 2, 3, 4, 5], 
     [2, 3, 4, 5, 6], 
     [3, 4, 5, 6, 7], 
     [4, 5, 6, 7, 8]]) 
+0

La tua risposta è arrivata come collegamento correlato a http://stackoverflow.com/a/35805797/901925. L'OP voleva rimodellare una vista a blocchi senza copiare. Il mascheramento è allettante - eccetto che molte funzioni 'ma' funzionano usando' filled' per sostituire i valori mascherati con quelli innocui (ad esempio 'filled (0)' per 'ma.sum'). Questa è una copia temporanea per ogni operazione mascherata. – hpaulj