Czy ktoś mógłby jasno wyjaśnić na przykładach różnicę między konwolucjami 1D, 2D i 3D w konwolucyjnych sieciach neuronowych (w uczeniu głębokim)?
127
Czy ktoś mógłby jasno wyjaśnić na przykładach różnicę między konwolucjami 1D, 2D i 3D w konwolucyjnych sieciach neuronowych (w uczeniu głębokim)?
Chcę to wyjaśnić obrazem z C3D .
W skrócie, kierunek splotu i kształt wyjścia są ważne!
↑↑↑↑↑ 1D zwojów - Podstawowe ↑↑↑↑↑
import tensorflow as tf
import numpy as np
sess = tf.Session()
ones_1d = np.ones(5)
weight_1d = np.ones(3)
strides_1d = 1
in_1d = tf.constant(ones_1d, dtype=tf.float32)
filter_1d = tf.constant(weight_1d, dtype=tf.float32)
in_width = int(in_1d.shape[0])
filter_width = int(filter_1d.shape[0])
input_1d = tf.reshape(in_1d, [1, in_width, 1])
kernel_1d = tf.reshape(filter_1d, [filter_width, 1, 1])
output_1d = tf.squeeze(tf.nn.conv1d(input_1d, kernel_1d, strides_1d, padding='SAME'))
print sess.run(output_1d)
& Uarr ; & uarr; & gt; & gt; & gt; & gt; & gt; & gt; & gt; &
ones_2d = np.ones((5,5))
weight_2d = np.ones((3,3))
strides_2d = [1, 1, 1, 1]
in_2d = tf.constant(ones_2d, dtype=tf.float32)
filter_2d = tf.constant(weight_2d, dtype=tf.float32)
in_width = int(in_2d.shape[0])
in_height = int(in_2d.shape[1])
filter_width = int(filter_2d.shape[0])
filter_height = int(filter_2d.shape[1])
input_2d = tf.reshape(in_2d, [1, in_height, in_width, 1])
kernel_2d = tf.reshape(filter_2d, [filter_height, filter_width, 1, 1])
output_2d = tf.squeeze(tf.nn.conv2d(input_2d, kernel_2d, strides=strides_2d, padding='SAME'))
print sess.run(output_2d)
& Uarr ; & uarr; &; & gt; & gt; & gt; & gt; & gt; & gt; & rdquo; & rdquo; & d \ u003; d \ u003d
ones_3d = np.ones((5,5,5))
weight_3d = np.ones((3,3,3))
strides_3d = [1, 1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_3d = tf.constant(weight_3d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
in_depth = int(in_3d.shape[2])
filter_width = int(filter_3d.shape[0])
filter_height = int(filter_3d.shape[1])
filter_depth = int(filter_3d.shape[2])
input_3d = tf.reshape(in_3d, [1, in_depth, in_height, in_width, 1])
kernel_3d = tf.reshape(filter_3d, [filter_depth, filter_height, filter_width, 1, 1])
output_3d = tf.squeeze(tf.nn.conv3d(input_3d, kernel_3d, strides=strides_3d, padding='SAME'))
print sess.run(output_3d)
↑↑↑↑↑ 2D zwojów z wejściem 3D - LeNet, VGG, ..., ↑↑↑↑↑
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
ones_3d = np.ones((5,5,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae with in_channels
weight_3d = np.ones((3,3,in_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_3d = tf.constant(weight_3d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_3d.shape[0])
filter_height = int(filter_3d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_3d = tf.reshape(filter_3d, [filter_height, filter_width, in_channels, 1])
output_2d = tf.squeeze(tf.nn.conv2d(input_3d, kernel_3d, strides=strides_2d, padding='SAME'))
print sess.run(output_2d)
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
out_channels = 64 # 128, 256, ...
ones_3d = np.ones((5,5,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae x number of filters = 4D
weight_4d = np.ones((3,3,in_channels, out_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_4d = tf.constant(weight_4d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_4d.shape[0])
filter_height = int(filter_4d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_4d = tf.reshape(filter_4d, [filter_height, filter_width, in_channels, out_channels])
#output stacked shape is 3D = 2D x N matrix
output_3d = tf.nn.conv2d(input_3d, kernel_4d, strides=strides_2d, padding='SAME')
print sess.run(output_3d)
↑↑↑↑↑ Bonus conv 1x1 w CNN - GoogLeNet, ..., ↑↑↑↑↑
in_channels = 32 # 3 for RGB, 32, 64, 128, ...
out_channels = 64 # 128, 256, ...
ones_3d = np.ones((1,1,in_channels)) # input is 3d, in_channels = 32
# filter must have 3d-shpae x number of filters = 4D
weight_4d = np.ones((3,3,in_channels, out_channels))
strides_2d = [1, 1, 1, 1]
in_3d = tf.constant(ones_3d, dtype=tf.float32)
filter_4d = tf.constant(weight_4d, dtype=tf.float32)
in_width = int(in_3d.shape[0])
in_height = int(in_3d.shape[1])
filter_width = int(filter_4d.shape[0])
filter_height = int(filter_4d.shape[1])
input_3d = tf.reshape(in_3d, [1, in_height, in_width, in_channels])
kernel_4d = tf.reshape(filter_4d, [filter_height, filter_width, in_channels, out_channels])
#output stacked shape is 3D = 2D x N matrix
output_3d = tf.nn.conv2d(input_3d, kernel_4d, strides=strides_2d, padding='SAME')
print sess.run(output_3d)
- Oryginalny link: LINK
- Autor: Martin Görner
- Twitter: @martin_gorner
- Google +: plus.google.com/+MartinGorne
↑↑↑↑↑ 1D zwojów z wejściem 1D ↑↑↑↑↑
↑↑↑↑↑ 1D zwojów z wejściem 2D ↑↑↑↑↑
in_channels = 32 # 3, 32, 64, 128, ...
out_channels = 64 # 3, 32, 64, 128, ...
ones_4d = np.ones((5,5,5,in_channels))
weight_5d = np.ones((3,3,3,in_channels,out_channels))
strides_3d = [1, 1, 1, 1, 1]
in_4d = tf.constant(ones_4d, dtype=tf.float32)
filter_5d = tf.constant(weight_5d, dtype=tf.float32)
in_width = int(in_4d.shape[0])
in_height = int(in_4d.shape[1])
in_depth = int(in_4d.shape[2])
filter_width = int(filter_5d.shape[0])
filter_height = int(filter_5d.shape[1])
filter_depth = int(filter_5d.shape[2])
input_4d = tf.reshape(in_4d, [1, in_depth, in_height, in_width, in_channels])
kernel_5d = tf.reshape(filter_5d, [filter_depth, filter_height, filter_width, in_channels, out_channels])
output_4d = tf.nn.conv3d(input_4d, kernel_5d, strides=strides_3d, padding='SAME')
print sess.run(output_4d)
sess.close()
1
, a następnie → dla wiersza1+stride
. Samo splot jest niezmienny, więc dlaczego kierunek splotu ma znaczenie?Podążając za odpowiedzią @runhani, dodaję kilka dodatkowych szczegółów, aby wyjaśnienie było nieco bardziej przejrzyste i spróbuję to wyjaśnić nieco dokładniej (i oczywiście z przykładami z TF1 i TF2).
Jednym z głównych dodatkowych elementów, które dołączam, są:
tf.Variable
Konwolucja 1D
Oto jak możesz wykonać splot 1D używając TF 1 i TF 2.
Mówiąc konkretnie, moje dane mają następujące kształty,
[batch size, width, in channels]
(np.1, 5, 1
)[width, in channels, out channels]
(np.5, 1, 4
)[batch size, width, out_channels]
(np.1, 5, 4
)Przykład TF1
Przykład TF2
To znacznie mniej pracy z TF2, ponieważ TF2 nie potrzebuje
Session
ivariable_initializer
na przykład.Jak to mogłoby wyglądać w prawdziwym życiu?
Zrozummy więc, co to robi, na przykładzie wygładzania sygnału. Po lewej stronie masz oryginał, a po prawej wyjście Convolution 1D z 3 kanałami wyjściowymi.
Co oznacza wiele kanałów?
Wiele kanałów to w zasadzie wiele reprezentacji funkcji wejścia. W tym przykładzie masz trzy reprezentacje uzyskane przez trzy różne filtry. Pierwszy kanał to jednakowo ważony filtr wygładzający. Drugi to filtr, który waży środek filtru bardziej niż granice. Ostatni filtr działa odwrotnie niż drugi. Możesz więc zobaczyć, jak te różne filtry wywołują różne efekty.
Aplikacje uczenia głębokiego splotu 1D
Zwój 1D został pomyślnie użyty do zadania klasyfikacji zdań .
Konwolucja 2D
Wyłącz do splotu 2D. Jeśli jesteś osobą uczącą się głęboko, prawdopodobieństwo, że nie spotkałeś się z konwolucją 2D, wynosi… cóż, zero. Jest używany w CNN do klasyfikacji obrazów, wykrywania obiektów itp., A także w problemach NLP, które obejmują obrazy (np. Generowanie podpisów do obrazów).
Spróbujmy na przykładzie, mam jądro konwolucji z następującymi filtrami tutaj,
Mówiąc konkretnie, moje dane mają następujące kształty,
[batch_size, height, width, 1]
(np.1, 340, 371, 1
)[height, width, in channels, out channels]
(np.3, 3, 1, 3
)[batch_size, height, width, out_channels]
(np.1, 340, 371, 3
)Przykład TF1,
Przykład TF2
Jak to mogłoby wyglądać w prawdziwym życiu?
Tutaj możesz zobaczyć dane wyjściowe wygenerowane przez powyższy kod. Pierwszy obraz jest oryginalny i zgodnie z ruchem wskazówek zegara masz wyjścia pierwszego filtra, drugiego filtra i trzeciego filtra.
Co oznacza wiele kanałów?
W kontekście splotu 2D dużo łatwiej jest zrozumieć, co oznaczają te wielokrotne kanały. Powiedz, że robisz rozpoznawanie twarzy. Możesz sobie wyobrazić (jest to bardzo nierealistyczne uproszczenie, ale ma sens) każdy filtr reprezentuje oko, usta, nos itp. Tak więc każda mapa cech byłaby binarną reprezentacją tego, czy ta cecha znajduje się na dostarczonym obrazie . Myślę, że nie muszę podkreślać, że dla modelu rozpoznawania twarzy są to bardzo cenne cechy. Więcej informacji w tym artykule .
To jest ilustracja tego, co próbuję wyrazić.
Zastosowania głębokiego uczenia splotu 2D
Konwolucja 2D jest bardzo rozpowszechniona w dziedzinie uczenia głębokiego.
CNN (Convolution Neural Networks) używają operacji splotu 2D do prawie wszystkich zadań widzenia komputerowego (np. Klasyfikacja obrazu, wykrywanie obiektów, klasyfikacja wideo).
Konwolucja 3D
Teraz coraz trudniej jest zilustrować, co się dzieje wraz ze wzrostem liczby wymiarów. Ale mając dobre zrozumienie, jak działa splot 1D i 2D, bardzo łatwo jest uogólnić to zrozumienie na splot 3D. Więc oto idzie.
Mówiąc konkretnie, moje dane mają następujące kształty,
[batch size, height, width, depth, in channels]
(np.1, 200, 200, 200, 1
)[height, width, depth, in channels, out channels]
(np.5, 5, 5, 1, 3
)[batch size, width, height, width, depth, out_channels]
(np.1, 200, 200, 2000, 3
)Przykład TF1
Przykład TF2
Aplikacje uczenia głębokiego splotu 3D
Konwolucja 3D została wykorzystana podczas tworzenia aplikacji uczenia maszynowego wykorzystujących dane LIDAR (Light Detection and Ranging), które mają charakter trójwymiarowy.
Co ... więcej żargonu ?: krok i wyściółka
W porządku, już prawie jesteś. Więc trzymaj się. Zobaczmy, czym jest krok i wyściółka. Są dość intuicyjne, jeśli się nad nimi zastanowić.
Jeśli przejdziesz przez korytarz, dotrzesz tam szybciej, wykonując mniejszą liczbę kroków. Ale oznacza to również, że obserwowałeś mniejsze otoczenie, niż gdybyś przeszedł przez pokój. Wzmocnijmy teraz nasze zrozumienie ładnym obrazkiem! Rozumiemy to poprzez splot 2D.
Zrozumienie kroku
Kiedy używasz
tf.nn.conv2d
na przykład, musisz ustawić go jako wektor 4 elementów. Nie ma powodu, aby się tym onieśmielać. Po prostu zawiera kroki w następującej kolejności.Konwolucja 2D -
[batch stride, height stride, width stride, channel stride]
. Tutaj, batch stride i channel stride, ustawiłeś tylko jeden (wdrażam modele głębokiego uczenia się od 5 lat i nigdy nie musiałem ustawiać ich na nic poza jednym). Masz więc tylko 2 kroki do ustawienia.Konwolucja 3D -
[batch stride, height stride, width stride, depth stride, channel stride]
. Tutaj martwisz się tylko krokami wysokości / szerokości / głębokości.Zrozumienie dopełnienia
Teraz zauważysz, że bez względu na to, jak mały jest twój krok (tj. 1), podczas splotu następuje nieuniknione zmniejszenie wymiarów (np. Szerokość wynosi 3 po skręceniu obrazu o szerokości 4 jednostek). Jest to niepożądane zwłaszcza przy budowaniu głębokich konwolucyjnych sieci neuronowych. Tutaj na ratunek przychodzi wyściółka. Istnieją dwa najczęściej używane typy wypełnienia.
SAME
iVALID
Poniżej możesz zobaczyć różnicę.
Ostatnie słowo : jeśli jesteś bardzo ciekawy, możesz się zastanawiać. Właśnie zrzuciliśmy bombę na całą automatyczną redukcję wymiarów, a teraz rozmawiamy o różnych krokach. Ale najlepszą rzeczą w kroku jest to, że kontrolujesz, gdzie i jak zmniejszają się wymiary.
źródło
CNN 1D, 2D lub 3D odnosi się do kierunku splotu, a nie do wymiaru wejściowego lub filtra.
Dla wejścia 1-kanałowego CNN2D równa się CNN1D to długość jądra = długość wejścia. (1 kierunek konw.)
źródło
Podsumowując, w 1D CNN jądro porusza się w jednym kierunku. Dane wejściowe i wyjściowe 1D CNN są dwuwymiarowe. Używany głównie w przypadku danych szeregów czasowych.
W 2D CNN jądro porusza się w 2 kierunkach. Dane wejściowe i wyjściowe 2D CNN są trójwymiarowe. Używany głównie w przypadku danych obrazu.
W 3D CNN jądro porusza się w 3 kierunkach. Dane wejściowe i wyjściowe 3D CNN są 4-wymiarowe. Stosowany głównie w przypadku danych obrazu 3D (skany MRI, CT).
Więcej szczegółów znajdziesz tutaj: https://medium.com/@xzz201920/conv1d-conv2d-and-conv3d-8a59182c4d6
źródło