Jaka jest różnica między wypełnieniem „SAME” i „WAŻNE” w tf.nn.max_pool przepływu tensorflow?

309

Jaka jest różnica między „sam” i „skuteczne” w wyściółką tf.nn.max_poolz tensorflow?

Moim zdaniem „WAŻNE” oznacza, że ​​nie będzie zerowania na krawędziach, gdy wykonamy maksymalną pulę.

Według Przewodnika po arytmetyki splotowej dla głębokiego uczenia się , mówi, że operator puli nie będzie wypełniał, tj. Po prostu użyje „WAŻNE” z tensorflow. Ale w czym jest wypełnienie „SAME” maksymalnej puli tensorflow?

karl_TUM
źródło
3
Sprawdź tensorflow.org/api_guides/python/... do szczegółów, to jak TF zrobić.
GabrielChu,
4
Sprawdź te niesamowite gify, aby zrozumieć, jak działa padding i krok. Link
Deepak,
1
@GabrielChu Twój link prawdopodobnie umarł i jest teraz przekierowaniem do ogólnego przeglądu.
mat
Wraz z aktualizacją Tensorflow do 2.0, rzeczy zostaną zastąpione przez Keras i uważam, że informacje o puli można znaleźć w dokumentacji Keras. @matt
GabrielChu,

Odpowiedzi:

163

Podam przykład, aby wyjaśnić:

  • x: obraz wejściowy o kształcie [2, 3], 1 kanał
  • valid_pad: maksymalna pula z jądrem 2x2, krok 2 i WAŻNE wypełnienie.
  • same_pad: maksymalna pula z jądrem 2x2, stride 2 i SAME wypełnienie (jest to klasyczny sposób)

Kształty wyjściowe to:

  • valid_pad: tutaj, bez dopełnienia, więc kształt wyjściowy to [1, 1]
  • same_pad: tutaj dopełniamy obraz do kształtu [2, 4] (za pomocą, -infa następnie stosujemy maksymalną pulę), więc kształt wyjściowy to [1, 2]

x = tf.constant([[1., 2., 3.],
                 [4., 5., 6.]])

x = tf.reshape(x, [1, 2, 3, 1])  # give a shape accepted by tf.nn.max_pool

valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')

valid_pad.get_shape() == [1, 1, 1, 1]  # valid_pad is [5.]
same_pad.get_shape() == [1, 1, 2, 1]   # same_pad is  [5., 6.]

Olivier Moindrot
źródło
603

Jeśli lubisz sztukę ascii:

  • "VALID" = bez wypełnienia:

       inputs:         1  2  3  4  5  6  7  8  9  10 11 (12 13)
                      |________________|                dropped
                                     |_________________|
    
  • "SAME" = z zerowym wypełnieniem:

                   pad|                                      |pad
       inputs:      0 |1  2  3  4  5  6  7  8  9  10 11 12 13|0  0
                   |________________|
                                  |_________________|
                                                 |________________|
    

W tym przykładzie:

  • Szerokość wejściowa = 13
  • Szerokość filtra = 6
  • Krok = 5

Uwagi:

  • "VALID" tylko upuszcza kolumny najbardziej po prawej (lub wiersze o najniższej pozycji).
  • "SAME" próbuje przesunąć równomiernie po lewej i prawej stronie, ale jeśli liczba dodawanych kolumn jest nieparzysta, doda dodatkową kolumnę po prawej stronie, jak ma to miejsce w tym przykładzie (ta sama logika obowiązuje w pionie: może być dodatkowy wiersz zer na dole).

Edytuj :

O nazwie:

  • W przypadku "SAME"paddingu, jeśli użyjesz kroku 1, wyjścia warstwy będą miały takie same wymiary przestrzenne jak jej wejścia.
  • W przypadku "VALID"paddingu nie ma „gotowych” wkładek padding. Warstwa wykorzystuje tylko prawidłowe dane wejściowe.
MiniQuark
źródło
Czy słusznie jest powiedzieć, że „SAME” oznacza „użyj wypełnienia zerami, aby upewnić się, że rozmiar filtra nie musi się zmieniać, jeśli szerokość obrazu nie jest wielokrotnością szerokości filtra lub wysokość obrazu nie jest wielokrotnością wysokości filtra „? Jak w „pad z zerami do wielokrotności szerokości filtra”, jeśli problemem jest szerokość?
StatsSorceress
2
Odpowiadając na moje pytanie poboczne: NIE, to nie jest punkt zerowania. Wybierasz rozmiar filtra do pracy z wejściem (w tym wypełnienie zerami), ale nie wybierasz wypełnienia zerami po rozmiarze filtra.
StatsSressress
Nie rozumiem twojej własnej odpowiedzi @StatsSorceress. Wydaje mi się, że dodajesz wystarczającą liczbę zer (w możliwie najbardziej symetryczny sposób), aby wszystkie dane wejściowe były objęte jakimś filtrem, prawda?
guillefix 11.01.19
2
Świetna odpowiedź, wystarczy dodać: W przypadku, gdy wartości tensora mogą być ujemne, dopełnienie dla max_pooling jest -inf.
Tones29
Co jeśli szerokość wejściowa jest liczbą parzystą, gdy ksize = 2, stride = 2 i przy takim samym wypełnieniu? ... to nie powinno być zerowane, prawda? ... Mówię to, gdy patrzę na repo kodu darkflow , używają SAMEGO padu, stride = 2, ksize = 2 dla maxpool .... po zmniejszeniu szerokości obrazu maxpool do 208 pikseli z 416 pikseli. Czy ktoś może to wyjaśnić?
K.vindi
161

Kiedy stridejest 1 (bardziej typowy dla splotu niż łączenia), możemy pomyśleć o następującym rozróżnieniu:

  • "SAME": rozmiar wyjściowy jest taki sam jak rozmiar wejściowy. Wymaga to, aby okno filtra wyślizgnęło się poza mapę wprowadzania, stąd potrzeba wypełnienia.
  • "VALID": Okno filtru pozostaje w prawidłowej pozycji na mapie wejściowej, więc rozmiar wyjściowy zmniejsza się o filter_size - 1. Nie występuje padding.
YvesgereY
źródło
65
To w końcu jest pomocne. Do tej pory wydawało się, że SAMEi VALIDmoże równie dobrze zostały nazwane fooibar
omatai
7
Myślę, że „wielkość wyjściowa jest taka sama jak wielkość wejściowego” jest prawdziwe tylko wtedy, gdy długość kroku jest 1.
omsrisagar
92

Przykład TensorFlow Convolution zawiera przegląd różnic między SAMEi VALID:

  • W przypadku SAMEwypełnienia wysokość i szerokość wyjściowa są obliczane jako:

    out_height = ceil(float(in_height) / float(strides[1]))
    out_width  = ceil(float(in_width) / float(strides[2]))
    

I

  • W przypadku VALIDwypełnienia wysokość i szerokość wyjściowa są obliczane jako:

    out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
    out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))
    
RoyaumeIX
źródło
46

Wypełnianie to operacja polegająca na zwiększeniu rozmiaru danych wejściowych. W przypadku danych 1-wymiarowych po prostu dodajesz / dodajesz tablicę ze stałą, w 2-dim otaczasz macierz tymi stałymi. W n-dim otaczasz hipersześcian n-dim stałą. W większości przypadków stała ta wynosi zero i nazywa się ją wypełnianiem zerowym.

Oto przykład wypełnienia zerowego p=1zastosowanego do tensora 2-d: wprowadź opis zdjęcia tutaj


Możesz użyć dowolnego wypełnienia dla swojego jądra, ale niektóre wartości wypełnienia są używane częściej niż inne:

  • WAŻNE wypełnienie . Najłatwiejszy przypadek oznacza brak wyściółki. Po prostu zostaw swoje dane takie same.
  • SAME wypełnienie czasami nazywane wypełnieniem POŁOWY . Nazywa się to SAMO, ponieważ dla splotu z krokiem = 1 (lub w puli) powinien generować dane wyjściowe tego samego rozmiaru co dane wejściowe. Nazywa się to PÓŁ, ponieważ dla jądra wielkościk wprowadź opis zdjęcia tutaj
  • WYPEŁNIENIE to maksymalne wypełnienie, które nie powoduje splotu tylko wyściełanych elementów. W przypadku jądra wielkości kta wypełnienie jest równa k - 1.

Aby użyć dowolnego wypełnienia w TF, możesz użyć tf.pad()

Salvador Dali
źródło
32

Szybkie wyjaśnienie

VALID: Nie stosuj żadnego dopełnienia, tzn. Załóż, że wszystkie wymiary są prawidłowe, aby obraz wejściowy był w pełni objęty przez filtr i krok określony przez Ciebie.

SAME: Zastosuj dopełnienie do danych wejściowych (w razie potrzeby), aby obraz wejściowy został w pełni pokryty przez określony filtr i krok. W kroku 1 zapewni to, że rozmiar obrazu wyjściowego będzie taki sam jak na wejściu.

Notatki

  • Dotyczy to zarówno warstw konwekcyjnych, jak i maksymalnych warstw puli
  • Termin „ważny” jest trochę mylący, ponieważ rzeczy nie stają się „nieprawidłowe”, jeśli upuścisz część obrazu. Czasem możesz tego chcieć. Powinno to prawdopodobnie zostać wywołane NO_PADDING.
  • Termin „ten sam” jest również mylący, ponieważ ma sens tylko dla kroku 1, gdy wymiar wyjściowy jest taki sam jak wymiar wejściowy. Na przykład dla kroku 2 wymiary wyjściowe będą na przykład o połowę mniejsze. Powinno to prawdopodobnie zostać wywołane AUTO_PADDING.
  • W SAME(tj. W trybie automatycznego padu) Tensorflow będzie próbował równomiernie rozłożyć wypełnienie zarówno po lewej, jak i po prawej stronie.
  • W VALID(tj. Bez trybu wypełniania), Tensorflow spadnie w prawo i / lub dolne komórki, jeśli twój filtr i krok nie pokrywają w pełni obrazu wejściowego.
Shital Shah
źródło
19

Cytuję tę odpowiedź z oficjalnych dokumentów tensorflow https://www.tensorflow.org/api_guides/python/nn#Convolution W przypadku wypełnienia „SAME” wysokość i szerokość wyjściowa są obliczane jako:

out_height = ceil(float(in_height) / float(strides[1]))
out_width  = ceil(float(in_width) / float(strides[2]))

a wypełnienie u góry i po lewej stronie jest obliczane jako:

pad_along_height = max((out_height - 1) * strides[1] +
                    filter_height - in_height, 0)
pad_along_width = max((out_width - 1) * strides[2] +
                   filter_width - in_width, 0)
pad_top = pad_along_height // 2
pad_bottom = pad_along_height - pad_top
pad_left = pad_along_width // 2
pad_right = pad_along_width - pad_left

W przypadku wypełnienia „WAŻNE” wysokość i szerokość wyjściowa są obliczane jako:

out_height = ceil(float(in_height - filter_height + 1) / float(strides[1]))
out_width  = ceil(float(in_width - filter_width + 1) / float(strides[2]))

a wartości wypełnienia są zawsze równe zero.

Vaibhav Dixit
źródło
1
Szczerze mówiąc, jest to jedyna ważna i kompletna odpowiedź, nie ograniczająca się do kroku 1. I wystarczy cytat z dokumentów. +1
P-Gn
1
Bardzo przydatne jest, aby mieć tę odpowiedź, szczególnie dlatego, że wskazany link już nie działa i wydaje się, że Google usunął te informacje ze strony internetowej TF!
Daniel
12

Istnieją trzy opcje wypełnienia: prawidłowe (bez wypełnienia), takie same (lub pół), pełne. Wyjaśnienia (w Theano) znajdziesz tutaj: http://deeplearning.net/software/theano/tutorial/conv_arithmetic.html

  • Prawidłowe wypełnienie lub brak:

Prawidłowe wypełnienie nie obejmuje wypełniania zerami, więc obejmuje tylko prawidłowe dane wejściowe, nie licząc sztucznie wygenerowanych zer. Długość wyjścia wynosi ((długość wejścia) - (k-1)) dla rozmiaru jądra k, jeśli krok s = 1.

  • Ta sama lub połowa wypełnienia:

To samo wypełnienie sprawia, że ​​wielkość wyjściowa jest taka sama jak wielkość wejściowa, gdy s = 1. Jeśli s = 1, liczba zerowanych dopełnień wynosi (k-1).

  • Pełne wypełnienie:

Pełne wypełnienie oznacza, że ​​jądro przebiega przez wszystkie dane wejściowe, więc na końcach jądro może spełniać tylko jedno wejście, a pozostałe zero. Liczba dopełnianych zer wynosi 2 (k-1), jeśli s = 1. Długość wyjścia wynosi ((długość wejścia) + (k-1)), jeżeli s = 1.

Dlatego liczba wypełnień: (ważna) <= (ta sama) <= (pełna)

Zmienić świat
źródło
8

Padding on / off. Określa efektywny rozmiar danych wejściowych.

VALID:Bez wyściółki. Operacje zwojowe itp. Są wykonywane tylko w miejscach, które są „ważne”, tj. Niezbyt blisko granic tensora.
Z jądrem 3x3 i obrazem 10x10, wykonałbyś splot na obszarze 8x8 wewnątrz granic.

SAME:Wypełnienie jest zapewnione. Ilekroć twoja operacja odwołuje się do sąsiedztwa (bez względu na to, jak duże), wartości zerowe są podawane, gdy sąsiedztwo wystaje poza pierwotny tensor, aby umożliwić tej operacji działanie również na wartościach granicznych.
Z jądrem 3x3 i obrazem 10x10 wykonujesz splot na pełnym obszarze 10x10.

Laine Mikael
źródło
8

WAŻNE wypełnienie: jest to wypełnienie zerowe. Mam nadzieję, że nie ma zamieszania.

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
valid_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='VALID')
print (valid_pad.get_shape()) # output-->(1, 2, 1, 1)

SAME wypełnienie: Jest to trochę trudne do zrozumienia w pierwszej kolejności, ponieważ musimy rozważyć dwa warunki oddzielnie, jak wspomniano w oficjalnych dokumentach .

Weźmy dane wejściowe jako , dane wyjściowe jako , wypełnienie jako , krok jako i rozmiar jądra jako (rozważany jest tylko jeden wymiar)

Przypadek 01 :

Przypadek 02 :

oblicza się w taki sposób, aby minimalną wartość, jaką można przyjąć dla wypełnienia. Ponieważ wartość jest znana, wartość można znaleźć za pomocą tego wzoru .

Opracujmy ten przykład:

x = tf.constant([[1., 2., 3.], [4., 5., 6.],[ 7., 8., 9.], [ 7., 8., 9.]])
x = tf.reshape(x, [1, 4, 3, 1])
same_pad = tf.nn.max_pool(x, [1, 2, 2, 1], [1, 2, 2, 1], padding='SAME')
print (same_pad.get_shape()) # --> output (1, 2, 2, 1)

Tutaj wymiar x wynosi (3,4). Następnie, jeśli zostanie przyjęty kierunek poziomy (3):

Jeśli zostanie wybrany kierunek pionowy (4):

Mam nadzieję, że pomoże to zrozumieć, w jaki sposób SAME wypełnienie działa w TF.

GPrathap
źródło
7

W oparciu o wyjaśnienie tutaj i po odpowiedzi Tristana zwykle używam tych szybkich funkcji do sprawdzania rozsądku.

# a function to help us stay clean
def getPaddings(pad_along_height,pad_along_width):
    # if even.. easy..
    if pad_along_height%2 == 0:
        pad_top = pad_along_height / 2
        pad_bottom = pad_top
    # if odd
    else:
        pad_top = np.floor( pad_along_height / 2 )
        pad_bottom = np.floor( pad_along_height / 2 ) +1
    # check if width padding is odd or even
    # if even.. easy..
    if pad_along_width%2 == 0:
        pad_left = pad_along_width / 2
        pad_right= pad_left
    # if odd
    else:
        pad_left = np.floor( pad_along_width / 2 )
        pad_right = np.floor( pad_along_width / 2 ) +1
        #
    return pad_top,pad_bottom,pad_left,pad_right

# strides [image index, y, x, depth]
# padding 'SAME' or 'VALID'
# bottom and right sides always get the one additional padded pixel (if padding is odd)
def getOutputDim (inputWidth,inputHeight,filterWidth,filterHeight,strides,padding):
    if padding == 'SAME':
        out_height = np.ceil(float(inputHeight) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth) / float(strides[2]))
        #
        pad_along_height = ((out_height - 1) * strides[1] + filterHeight - inputHeight)
        pad_along_width = ((out_width - 1) * strides[2] + filterWidth - inputWidth)
        #
        # now get padding
        pad_top,pad_bottom,pad_left,pad_right = getPaddings(pad_along_height,pad_along_width)
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'total pad along height' , pad_along_height
        print 'total pad along width' , pad_along_width
        print 'pad at top' , pad_top
        print 'pad at bottom' ,pad_bottom
        print 'pad at left' , pad_left
        print 'pad at right' ,pad_right

    elif padding == 'VALID':
        out_height = np.ceil(float(inputHeight - filterHeight + 1) / float(strides[1]))
        out_width  = np.ceil(float(inputWidth - filterWidth + 1) / float(strides[2]))
        #
        print 'output height', out_height
        print 'output width' , out_width
        print 'no padding'


# use like so
getOutputDim (80,80,4,4,[1,1,1,1],'SAME')
Ahmedhosny
źródło
6

Podsumowując, „prawidłowe” wypełnienie oznacza brak wypełnienia. Rozmiar wyjściowy warstwy splotowej kurczy się w zależności od rozmiaru wejściowego i rozmiaru jądra.

Przeciwnie, „to samo” wypełnienie oznacza użycie wypełnienia. Gdy krok jest ustawiony na 1, rozmiar wyjściowy warstwy splotowej zachowuje się jak rozmiar wejściowy, dodając pewną liczbę „granicy 0” wokół danych wejściowych podczas obliczania splotu.

Mam nadzieję, że ten intuicyjny opis pomoże.

Frederick HONG
źródło
5

Formuła ogólna

Tutaj W i H oznaczają szerokość i wysokość wejścia, F to wymiary filtra, P to rozmiar wypełnienia (tj. Liczba wierszy lub kolumn do wypełnienia)

W przypadku SAMEGO wypełnienia:

SAMO Padding

W przypadku ważnego wypełnienia:

WAŻNE wypełnienie

Shivam Kushwaha
źródło
2

Uzupełniając świetną odpowiedź YvesgereY, ta wizualizacja okazała się niezwykle pomocna:

Wizualizacja paddingu

Padding „ valid ” to pierwsza cyfra. Okno filtru pozostaje wewnątrz obrazu.

Padding „ same ” to trzecia cyfra. Dane wyjściowe są tego samego rozmiaru.


Znalazłem to w tym artykule .

zmx
źródło
0

Odpowiedź zgodna z Tensorflow 2.0 : powyżej podano szczegółowe objaśnienia dotyczące „Ważnego” i „tego samego” wypełnienia.

Jednak Tensorflow 2.x (>= 2.0)z korzyścią dla społeczności określę różne funkcje łączenia i ich odpowiednie polecenia .

Funkcje w 1.x :

tf.nn.max_pool

tf.keras.layers.MaxPool2D

Average Pooling => None in tf.nn, tf.keras.layers.AveragePooling2D

Funkcje w wersji 2.x :

tf.nn.max_pooljeśli jest używany w wersji 2.x i tf.compat.v1.nn.max_pool_v2lub tf.compat.v2.nn.max_pool, jeśli migrowany z wersji 1.x do wersji 2.x.

tf.keras.layers.MaxPool2D jeśli używany w 2.xi

tf.compat.v1.keras.layers.MaxPool2Dlub tf.compat.v1.keras.layers.MaxPooling2Dlub tf.compat.v2.keras.layers.MaxPool2Dlub tf.compat.v2.keras.layers.MaxPooling2D, w przypadku migracji z wersji 1.x do wersji 2.x.

Average Pooling => tf.nn.avg_pool2dlub tf.keras.layers.AveragePooling2Djeśli jest używany w TF 2.x i

tf.compat.v1.nn.avg_pool_v2lub tf.compat.v2.nn.avg_poollub tf.compat.v1.keras.layers.AveragePooling2Dlub tf.compat.v1.keras.layers.AvgPool2Dlub tf.compat.v2.keras.layers.AveragePooling2Dlub tf.compat.v2.keras.layers.AvgPool2D, w przypadku migracji z wersji 1.x do wersji 2.x.

Więcej informacji na temat migracji z Tensorflow 1.x do 2.x można znaleźć w niniejszym przewodniku migracji .

Obsługa Tensorflow
źródło