Argument Tensorflow Strides

115

Próbuję zrozumieć krokami argument w tf.nn.avg_pool, tf.nn.max_pool, tf.nn.conv2d.

Dokumentacja wielokrotnie mówi

strides: lista wartości typu int, które mają długość> = 4. Krok przesuwanego okna dla każdego wymiaru tensora wejściowego.

Moje pytania to:

  1. Co reprezentuje każda z 4+ liczb całkowitych?
  2. Dlaczego muszą mieć strides [0] = strides [3] = 1 dla convnets?
  3. W tym przykładzie widzimy tf.reshape(_X,shape=[-1, 28, 28, 1]). Dlaczego -1?

Niestety przykłady w dokumentacji dotyczące zmiany kształtu przy użyciu -1 nie przekładają się zbyt dobrze na ten scenariusz.

jfbeltran
źródło

Odpowiedzi:

224

Operacje łączenia i konwolucji przesuwają „okno” w poprzek tensora wejściowego. Na tf.nn.conv2dprzykładzie: Jeśli tensor wejściowy ma 4 wymiary [batch, height, width, channels]:, to splot działa na oknie 2D na height, widthwymiarach.

stridesokreśla, o ile przesuwa się okno w każdym z wymiarów. Typowe użycie ustawia pierwszy (partia) i ostatni (głębokość) krok na 1.

Posłużmy się bardzo konkretnym przykładem: uruchomienie splotu dwuwymiarowego na obrazie wejściowym 32x32 w skali szarości. Mówię o odcieniach szarości, ponieważ wtedy obraz wejściowy ma głębię = 1, co pomaga zachować prostotę. Niech ten obraz będzie wyglądał tak:

00 01 02 03 04 ...
10 11 12 13 14 ...
20 21 22 23 24 ...
30 31 32 33 34 ...
...

Uruchommy okno splotu 2x2 na jednym przykładzie (rozmiar wsadu = 1). Damy splotowi głębokość kanału wyjściowego równą 8.

Wejście do splotu ma shape=[1, 32, 32, 1].

Jeśli określisz za strides=[1,1,1,1]pomocą padding=SAME, wyjście filtru będzie [1, 32, 32, 8].

Filtr najpierw utworzy wynik dla:

F(00 01
  10 11)

A potem dla:

F(01 02
  11 12)

i tak dalej. Następnie przejdzie do drugiego wiersza, obliczając:

F(10, 11
  20, 21)

następnie

F(11, 12
  21, 22)

Jeśli określisz krok [1, 2, 2, 1], nie spowoduje to nałożenia okien. Obliczy:

F(00, 01
  10, 11)

i wtedy

F(02, 03
  12, 13)

Stride działa podobnie dla operatorów poolingu.

Pytanie 2: Dlaczego strides [1, x, y, 1] dla konwetów

Pierwsza 1 to partia: zwykle nie chcesz pomijać przykładów w swojej grupie lub nie powinieneś ich uwzględniać w pierwszej kolejności. :)

Ostatnie 1 to głębokość splotu: zwykle nie chcesz pomijać danych wejściowych z tego samego powodu.

Operator conv2d jest bardziej ogólne, więc mógł tworzyć zwoje że przesuń okno wzdłuż innych wymiarów, ale to nie jest typowe zastosowanie w convnets. Typowym zastosowaniem jest użycie ich w przestrzeni.

Dlaczego zmiana kształtu na -1 -1 jest symbolem zastępczym, który mówi „dostosuj w razie potrzeby, aby dopasować rozmiar wymagany dla pełnego tensora”. Jest to sposób na uniezależnienie kodu od rozmiaru wsadu wejściowego, dzięki czemu można zmienić potok i nie trzeba dostosowywać rozmiaru wsadu wszędzie w kodzie.

dga
źródło
5
@derek ponieważ (z tekstu) "Damy splotowi głębokość kanału wyjściowego 8". To coś, co możesz wybrać podczas konfigurowania splotu, a odpowiadający wybrał 8.
etarion
17

Wejścia są 4-wymiarowe i mają postać: [batch_size, image_rows, image_cols, number_of_colors]

Kroki na ogół definiują nakładanie się operacji stosowania. W przypadku conv2d określa, jaka jest odległość między kolejnymi zastosowaniami filtrów splotowych. Wartość 1 w określonym wymiarze oznacza, że ​​stosujemy operator w każdym wierszu / kolumnie, wartość 2 oznacza każdą sekundę i tak dalej.

Ad 1) Wartości, które mają znaczenie dla zwojów to 2 i 3 i reprezentują one nakładanie się filtrów splotowych wzdłuż wierszy i kolumn. Wartość [1, 2, 2, 1] mówi, że chcemy zastosować filtry do co drugiego wiersza i kolumny.

Ad 2) Nie znam ograniczeń technicznych (może to być wymóg CuDNN), ale zazwyczaj ludzie używają kroków wzdłuż wymiarów rzędów lub kolumn. Niekoniecznie ma to sens, jeśli chodzi o wielkość partii. Nie jestem pewien ostatniego wymiaru.

Ad 3) Ustawienie -1 dla jednego z wymiarów oznacza „ustawić wartość dla pierwszego wymiaru tak, aby całkowita liczba elementów w tensorze pozostała niezmieniona”. W naszym przypadku -1 będzie równe batch_size.

Rafał Józefowicz
źródło
11

Zacznijmy od tego, co robi stride w przypadku 1-dim.

Załóżmy, że twój input = [1, 0, 2, 3, 0, 1, 1]i kernel = [2, 1, 3]wynik splotu jest [8, 11, 7, 9, 4]obliczany przez przesuwanie jądra po danych wejściowych, mnożenie elementów i sumowanie wszystkiego. W ten sposób :

  • 8 = 1 * 2 + 0 * 1 + 2 * 3
  • 11 = 0 * 2 + 2 * 1 + 3 * 3
  • 7 = 2 * 2 + 3 * 1 + 0 * 3
  • 9 = 3 * 2 + 0 * 1 + 1 * 3
  • 4 = 0 * 2 + 1 * 1 + 1 * 3

Tutaj przesuwamy się o jeden element, ale nic Cię nie powstrzyma, używając innej liczby. Ta liczba to Twój krok. Możesz o tym myśleć jako o zmniejszaniu częstotliwości próbkowania wyniku 1-krokowego splotu, po prostu biorąc każdy s-ty wynik.

Znając rozmiar wejściowy i , rozmiar jądra k , krok s i wypełnienie p , możesz łatwo obliczyć rozmiar wyjściowy splotu jako:

wprowadź opis obrazu tutaj

Tutaj || operator oznacza obsługę sufitu. Dla warstwy puli s = 1.


Obudowa N-dim.

Znajomość matematyki dla przypadku 1-dim jest łatwa, gdy zobaczysz, że każdy dim jest niezależny. Więc po prostu przesuń każdy wymiar osobno. Oto przykład dla 2-d . Zauważ, że nie musisz mieć tego samego kroku na wszystkich wymiarach. Więc dla wejścia / jądra N-dim należy podać N kroków.


Więc teraz łatwo jest odpowiedzieć na wszystkie pytania:

  1. Co reprezentuje każda z 4+ liczb całkowitych? . conv2d , pula informuje, że ta lista przedstawia postępy między każdym wymiarem. Zauważ, że długość listy kroków jest taka sama jak ranga tensora jądra.
  2. Dlaczego muszą mieć strides [0] = strides 3 = 1 dla convnets? . Pierwszy wymiar to wielkość partii, ostatni to kanały. Nie ma sensu pomijać ani partii, ani kanału. Więc robisz je 1. Dla szerokości / wysokości możesz coś pominąć i dlatego mogą nie być 1.
  3. tf.reshape (_X, kształt = [- 1, 28, 28, 1]). Dlaczego -1? tf.reshape ma to dla Ciebie:

    Jeśli jeden składnik kształtu ma specjalną wartość -1, rozmiar tego wymiaru jest obliczany tak, aby całkowity rozmiar pozostał stały. W szczególności kształt [-1] spłaszcza się do 1-D. Co najwyżej jeden składnik kształtu może wynosić -1.

Salvador Dali
źródło
2

@dga wykonał wspaniałą pracę, wyjaśniając i nie mogę być wystarczająco wdzięczny, jak bardzo był pomocny. W podobny sposób chciałbym podzielić się moimi odkryciami na temat tego, jak stridedziała splot 3D.

Zgodnie z dokumentacją TensorFlow na conv3d, kształt wejścia musi być w następującej kolejności:

[batch, in_depth, in_height, in_width, in_channels]

Wyjaśnijmy zmienne od skrajnej prawej do lewej na przykładzie. Zakładając, że kształt wejściowy to input_shape = [1000,16,112,112,3]

input_shape[4] is the number of colour channels (RGB or whichever format it is extracted in)
input_shape[3] is the width of the image
input_shape[2] is the height of the image
input_shape[1] is the number of frames that have been lumped into 1 complete data
input_shape[0] is the number of lumped frames of images we have.

Poniżej znajduje się podsumowująca dokumentacja dotycząca sposobu wykorzystania kroku.

strides: lista wartości typu int, które mają długość> = 5. 1-D tensor długości 5. Skok przesuwanego okna dla każdego wymiaru wejścia. Muszę miećstrides[0] = strides[4] = 1

Jak wskazano w wielu pracach, kroki oznaczają po prostu, o ile kroków okno lub jądro odskakuje od najbliższego elementu, czy to ramki danych, czy piksela (jest to parafrazowane).

Z powyższej dokumentacji krok w 3D będzie wyglądał następująco: strides = (1, X , Y , Z , 1).

Dokumentacja to podkreśla strides[0] = strides[4] = 1.

strides[0]=1 means that we do not want to skip any data in the batch 
strides[4]=1 means that we do not want to skip in the channel 

strides [X] oznacza, ile przeskoków powinniśmy wykonać w skupionych klatkach. Na przykład, jeśli mamy 16 klatek, X = 1 oznacza użycie każdej klatki. X = 2 oznacza użycie co drugiej klatki i trwa i trwa

strides [y] i strides [z] postępują zgodnie z wyjaśnieniem @dga, więc nie będę powtarzał tej części.

Jednak w kerasach wystarczy określić krotkę / listę 3 liczb całkowitych, określając skoki splotu wzdłuż każdego wymiaru przestrzennego, gdzie wymiar przestrzenny to krok [x], kroki [y] i kroki [z]. strides [0] i strides [4] ma już domyślną wartość 1.

Mam nadzieję, że ktoś uzna to za pomocne!

rocksyne
źródło