Patrzyłem na dokumentację tensorflow o tf.nn.conv2d
tutaj . Ale nie mogę zrozumieć, co to robi ani co próbuje osiągnąć. W dokumentach jest napisane,
# 1: spłaszcza filtr do matrycy 2-D z kształtem
[filter_height * filter_width * in_channels, output_channels]
.
Co to teraz robi? Czy jest to mnożenie elementarne, czy po prostu zwykłe mnożenie macierzy? Też nie mogłem zrozumieć pozostałych dwóch punktów wymienionych w dokumentach. Napisałem je poniżej:
# 2: Wyodrębnia łaty obrazu z wejściowego tensora, aby utworzyć wirtualny tensor kształtu
[batch, out_height, out_width, filter_height * filter_width * in_channels]
.# 3: Dla każdego obszaru mnoży się w prawo macierz filtra i wektor wstawki obrazu.
Byłoby naprawdę pomocne, gdyby ktoś mógł podać przykład, może fragment kodu (niezwykle pomocny) i wyjaśnić, co się tam dzieje i dlaczego tak się dzieje.
Próbowałem zakodować małą część i wydrukować kształt operacji. Wciąż nie mogę tego zrozumieć.
Próbowałem czegoś takiego:
op = tf.shape(tf.nn.conv2d(tf.random_normal([1,10,10,10]),
tf.random_normal([2,10,10,10]),
strides=[1, 2, 2, 1], padding='SAME'))
with tf.Session() as sess:
result = sess.run(op)
print(result)
Rozumiem bity i fragmenty konwolucyjnych sieci neuronowych. Studiowałem je tutaj . Ale implementacja na tensorflow nie jest tym, czego się spodziewałem. Więc to wywołało pytanie.
EDYCJA : Więc zaimplementowałem znacznie prostszy kod. Ale nie mogę dowiedzieć się, co się dzieje. Mam na myśli, jakie są takie wyniki. Byłoby niezwykle pomocne, gdyby ktokolwiek mógł mi powiedzieć, jaki proces daje taki wynik.
input = tf.Variable(tf.random_normal([1,2,2,1]))
filter = tf.Variable(tf.random_normal([1,1,1,1]))
op = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
print("input")
print(input.eval())
print("filter")
print(filter.eval())
print("result")
result = sess.run(op)
print(result)
wynik
input
[[[[ 1.60314465]
[-0.55022103]]
[[ 0.00595062]
[-0.69889867]]]]
filter
[[[[-0.59594476]]]]
result
[[[[-0.95538563]
[ 0.32790133]]
[[-0.00354624]
[ 0.41650501]]]]
źródło
tf.nn.conv2d()
, więc omawiana metoda nie jest w ogóle używana, gdy używamy TF z obsługą GPU, chyba że zostanieuse_cudnn_on_gpu=False
to wyraźnie określone.Odpowiedzi:
Splot 2D jest obliczany w podobny sposób, jak można obliczyć splot 1D : przesuwasz jądro po wejściu, obliczasz mnożenia według elementów i sumujesz je. Ale zamiast jądra / wejścia będącego tablicą, tutaj są to macierze.
W najbardziej podstawowym przykładzie nie ma dopełnienia, a krok = 1. Załóżmy, że jesteś
input
ikernel
jesteś:Kiedy używasz jądra, otrzymasz następujący wynik:, który jest obliczany w następujący sposób:
Funkcja conv2d TF oblicza zwoje w partiach i używa nieco innego formatu. Dla wejścia jest to
[batch, in_height, in_width, in_channels]
dla jądra[filter_height, filter_width, in_channels, out_channels]
. Dlatego musimy podać dane w odpowiednim formacie:Następnie splot jest obliczany ze wzoru:
I będzie równa tej, którą obliczyliśmy ręcznie.
Na przykładach z wyściółką / krokami, warto tu zapoznać .
źródło
Ok, myślę, że to najprostszy sposób, aby to wszystko wyjaśnić.
Twój przykład to 1 obraz, rozmiar 2x2, z 1 kanałem. Masz 1 filtr o rozmiarze 1x1 i 1 kanał (rozmiar to wysokość x szerokość x kanały x liczba filtrów).
W tym prostym przypadku wynikowy obraz 2x2,1 kanału (rozmiar 1x2x2x1, liczba obrazów x wysokość x szerokość xx kanałów) jest wynikiem pomnożenia wartości filtru przez każdy piksel obrazu.
Teraz wypróbujmy więcej kanałów:
Tutaj obraz 3x3 i filtr 1x1 mają po 5 kanałów. Wynikowy obraz będzie 3x3 z 1 kanałem (rozmiar 1x3x3x1), gdzie wartość każdego piksela jest iloczynem skalarnym w kanałach filtru z odpowiadającym mu pikselem w obrazie wejściowym.
Teraz z filtrem 3x3
Tutaj otrzymujemy obraz 1x1, z 1 kanałem (rozmiar 1x1x1x1). Wartość jest sumą 9, 5-elementowych iloczynów skalarnych. Ale możesz po prostu nazwać to 45-elementowym iloczynem skalarnym.
Teraz z większym obrazem
Na wyjściu jest 1-kanałowy obraz 3x3 (rozmiar 1x3x3x1). Każda z tych wartości jest sumą 9, 5-elementowych iloczynów skalarnych.
Każde wyjście jest tworzone przez wyśrodkowanie filtra na jednym z 9 środkowych pikseli obrazu wejściowego, tak aby żaden filtr nie odstał. Poniższe
x
symbole przedstawiają środki filtrów dla każdego piksela wyjściowego.Teraz z dopełnieniem „SAME”:
Daje to obraz wyjściowy 5x5 (rozmiar 1x5x5x1). Odbywa się to poprzez wyśrodkowanie filtra w każdej pozycji obrazu.
Każdy z 5-elementowych iloczynów skalarnych, w których filtr wystaje poza krawędź obrazu, otrzymuje wartość zero.
Zatem rogi są tylko sumami 4, 5-elementowych iloczynów skalarnych.
Teraz z wieloma filtrami.
To nadal daje obraz wyjściowy 5x5, ale z 7 kanałami (rozmiar 1x5x5x7). Gdzie każdy kanał jest wytwarzany przez jeden z filtrów w zestawie.
Teraz z krokami 2,2:
Teraz wynik nadal ma 7 kanałów, ale ma tylko 3x3 (rozmiar 1x3x3x7).
Dzieje się tak, ponieważ zamiast wyśrodkować filtry w każdym punkcie obrazu, filtry są wyśrodkowane w każdym innym punkcie obrazu, wykonując kroki (kroki) o szerokości 2. Poniższe
x
poniżej przedstawiają środek filtru dla każdego piksela wyjściowego, na obraz wejściowy.I oczywiście pierwszym wymiarem danych wejściowych jest liczba obrazów, więc można je zastosować do partii 10 obrazów, na przykład:
Wykonuje tę samą operację niezależnie dla każdego obrazu, dając w rezultacie stos 10 obrazów (rozmiar 10x3x3x7)
źródło
Must have strides[0] = strides[3] = 1. For the most common case of the same horizontal and vertices strides, strides = [1, stride, stride, 1].
the 3x3 image and the 1x1 filter each have 5 channels
uważam, że wynik różni się od obliczonego ręcznie iloczynu skalarnego .Aby dodać do innych odpowiedzi, powinieneś pomyśleć o parametrach w
jako „5”, co odpowiada liczbie kanałów w każdym filtrze. Każdy filtr to sześcian 3D o głębokości 5. Głębokość filtra musi odpowiadać głębi obrazu wejściowego. Ostatni parametr, 7, należy traktować jako liczbę filtrów w partii. Po prostu zapomnij o tym, że jest to 4D i zamiast tego wyobraź sobie, że masz zestaw lub partię 7 filtrów. Tworzysz 7 kostek filtracyjnych o wymiarach (3,3,5).
Dużo łatwiej jest wizualizować w domenie Fouriera, ponieważ splot staje się mnożeniem punktowym. W przypadku obrazu wejściowego o wymiarach (100,100,3) można przepisać wymiary filtra jako
Aby uzyskać jedną z 7 map cech wyjściowych, po prostu wykonujemy punktowe pomnożenie kostki filtra przez kostkę obrazu, a następnie sumujemy wyniki w wymiarze kanałów / głębokości (tutaj jest to 3), zwinięte do 2d (100,100) mapa funkcji. Zrób to z każdą kostką filtra, a otrzymasz 7 map funkcji 2D.
źródło
Próbowałem zaimplementować conv2d (do nauki). Cóż, napisałem, że:
Mam nadzieję, że zrobiłem to poprawnie. Sprawdzone na MNIST, dało bardzo zbliżone wyniki (ale ta implementacja jest wolniejsza). Mam nadzieję, że to Ci pomoże.
źródło
Oprócz innych odpowiedzi, operacja conv2d działa w języku c ++ (cpu) lub cuda dla maszyn z procesorem graficznym, które wymagają spłaszczenia i zmiany kształtu danych w określony sposób oraz użycia mnożenia macierzy gemmBLAS lub cuBLAS (cuda).
źródło