2014-07-18 13 views
7

Mam obraz zapisany jako tablica 2d numpy (prawdopodobnie multi-d).Funkcja Numpy View Reshape Without Copy (2d ruchome/przesuwne okno, kroki, zamaskowane struktury pamięci)

mogę się widok na tej tablicy, która odzwierciedla 2d okno przesuwne, ale kiedy zmienią się tak, że każdy wiersz jest spłaszczony okno (wiersze są okna, kolumna jest piksel w tym oknie) python tworzy pełną kopię . Robi to, ponieważ używam typowej sztuczki krokowej, a nowy kształt nie jest ciągły w pamięci.

Potrzebuję tego, ponieważ przechodzę całe duże obrazy do klasyfikatora sklearn, który akceptuje matryce 2d, gdzie nie ma procedury partii/częściowego dopasowania, a pełna rozszerzona kopia jest zbyt duża dla pamięci.

Moje pytanie: Czy istnieje sposób na wykonanie tej czynności bez wykonania pełnej kopii widoku?

Wierzę, że odpowiedź będzie albo (1) coś o krokach albo numpy zarządzania pamięcią, które przeoczyłem, albo (2) jakiejś maskowanej struktury pamięci dla Pythona, która może emulować tablicę numpy nawet do zewnętrznego pakietu jak sklearn, który obejmuje cyton.

To zadanie polegające na przeszkoleniu ruchomych okien obrazu 2d w pamięci jest powszechne, ale jedyną próbą, którą znam, aby bezpośrednio objaśnić poprawki, jest projekt Vigra (http://ukoethe.github.io/vigra/).

Dzięki za pomoc.

>>> 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

myślę, że to jest niemożliwe, nawet Ci zdać 'as_strided' tablicę do klasyfikatora sklearn, myślę, że większość (jeśli nie wszystkie) klasyfikatory skopiują twoje dane, jeśli nie są ciągłe. – HYRY

+2

Tak, jestem prawie pewien, że nie da się tego zrobić. Przepraszam. Jeśli znajdziesz sposób, daj mi znać;) Ponadto: bezpośrednie wprowadzanie obrazu może nie być dobrym pomysłem, a funkcje obliczeniowe mogą rozwiązać Twój problem. –

+1

Zdecydowanie wykluczyć numer (1), "sklearn.feature_extraction.image.extract_patches" daje dokładnie ten widok, o którym mówisz, a jego zmiana na pewno spowoduje wykonanie kopii zgodnie z zasadami numpy. Czy na pewno potrzebujesz wszystkich poprawek wielu obrazów naraz? Możesz zajrzeć do algorytmów online/bating dla dowolnego celu. Spróbuj na przykład 'SGDClassifier'. – eickenberg

Odpowiedz

4

Twoim zadaniem nie jest możliwe przy użyciu tylko postępy, ale NumPy obsługuje jeden rodzaj tablicy, która spełnia swoje zadanie. Dzięki krokom i masked_array możesz stworzyć pożądany widok dla swoich danych. Jednak nie wszystkie funkcje NumPy obsługują operacje z masked_array, więc możliwe jest, że uczenie się scikit również nie będzie z nimi dobrze współpracować.

Przyjrzyjmy się najpierw temu, co próbujemy tutaj zrobić. Rozważ dane wejściowe swojego przykładu. Zasadniczo dane te to tylko tablica 1-D w pamięci i jest to prostsze, jeśli pomyślimy o tym, że jest to krok naprzód. Tablica wydaje się być 2-d, ponieważ my zdefiniowaliśmy jej kształt. Korzystanie postępy, kształt może być zdefiniowana tak:

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

Teraz celem jest stworzenie takich kroków do base że zamawia numery jak w tablicy czołowej, B. Innymi słowy, jesteśmy z prośbą o całkowitymi a i b takie, że

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

Ale to jest oczywiście niemożliwe. Najbliższy widok możemy osiągnąć jak to jest z wałkiem oknie nad 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]]) 

Ale różnica jest taka, że ​​mamy dodatkowych kolumn i wierszy, które chcielibyśmy pozbyć. Tak więc, skutecznie pytamy o okno rolowane, które nie jest ciągłe, a także wykonuje skoki w regularnych przedziałach . W tym przykładzie chcemy, aby co trzeci element został wykluczony z okna i przeskoczył nad jednym elementem po dwóch wierszach.

Możemy opisać to jako masked_array:

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

Tablica ta zawiera dokładnie te dane, które chcemy, i to tylko widok z oryginalnymi danymi. Możemy potwierdzić, że dane jest równa

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

Ale jak powiedziałem na początku, to jest całkiem prawdopodobne, że scikit-learn nie rozumie zamaskowanych tablic. Jeśli jest to po prostu konwertuje do tablicy, dane będzie źle:

>>> 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

Twoja odpowiedź pojawiła się jako powiązany link do strony http://stackoverflow.com/a/35805797/901925. OP chciał zmienić kształt widoku bloku bez kopiowania. Twoje maskowanie jest kuszące - z wyjątkiem wielu funkcji 'ma' działają, używając' filled' do zastąpienia maskowanych wartości niewinnymi (np. 'Filled (0)' for 'ma.sum'). To jest tymczasowa kopia dla każdej zamaskowanej operacji. – hpaulj