Operacje łączenia i konwolucji przesuwają „okno” w poprzek tensora wejściowego. Na tf.nn.conv2d
przykładzie: Jeśli tensor wejściowy ma 4 wymiary [batch, height, width, channels]
:, to splot działa na oknie 2D na height, width
wymiarach.
strides
okreś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.