Jaka jest różnica między Conv1D a Conv2D?

19

Przeglądałem dokumenty konwolucji keras i znalazłem dwa rodzaje konwulsji Conv1D i Conv2D. Przeprowadziłem wyszukiwanie w Internecie i właśnie to rozumiem na temat Conv1D i Conv2D; Conv1D jest używany do sekwencji, a Conv2D do zdjęć.

Zawsze myślałem, że sieci nerwowe splotu są używane tylko do obrazów i w ten sposób wizualizują CNN

wprowadź opis zdjęcia tutaj

Obraz jest uważany za dużą matrycę, a następnie filtr przesunie się po tej matrycy i obliczy iloczyn punktowy. Wierzę w to, co Keras wymienia jako Conv2D. Jeśli Conv2D działa w ten sposób, to jaki jest mechanizm Conv1D i jak możemy sobie wyobrazić jego mechanizm?

Eka
źródło
2
Spójrz na tę odpowiedź . Mam nadzieję że to pomoże.
uczeń 101

Odpowiedzi:

4

Konwolucja jest operacją matematyczną polegającą na „podsumowaniu” tensora lub macierzy lub wektora na mniejszy. Jeśli macierz wejściowa jest jednowymiarowe następnie podsumować wzdłuż że wymiary, a jeśli tensor ma n wymiary wtedy mogłaby podsumować wzdłuż wszystkich wymiarach n. Conv1D i Conv2D podsumowują (zwijają) wzdłuż jednego lub dwóch wymiarów.

Na przykład, możesz przekształcić wektor w krótszy wektor w następujący sposób. Uzyskaj „długi” wektor A z n elementów i splot go za pomocą wektora ciężaru W z m elementów w „krótki” (podsumowujący) wektor B z n-m + 1 elementami: gdzie

bja=jot=m-10zaja+jotwjot
ja=[1,n-m+1]

Tak więc, jeśli masz wektor długości n, a twoja macierz wagowa ma również długość n , wówczas splot wytworzy skalar lub wektor długości 1 równy średniej wartości wszystkich wartości w macierzy wejściowej. To rodzaj zdegenerowanego splotu, jeśli chcesz. Jeśli ta sama macierz ciężaru jest o jeden mniejsza niż macierz wejściowa, wówczas otrzymujesz średnią ruchomą na wyjściu o długości 2 itd.wja=1/n

[za:za1za2)za3)w:1/2)1/2)w:1/2)1/2)]=[b:za1+za2)2)za2)+za3)2)]

Możesz zrobić to samo z trójwymiarowym tensorem (macierzą) w ten sam sposób: gdzie

bjakl=jot1=m1-1jot2)=m2)-1jot3)=m4-10zaja+jot1,k+jot2),l+jot3)wjot1jot2)jot3)
ja=[1,n1-m1+1],k=[1,n2)-m2)+1],l=[1,n3)-m3)+1]

Aksakal
źródło
3

Ten splot 1d jest oszczędny, działa w ten sam sposób, ale zakłada tablicę 1-wymiarową, która tworzy mnożenie z elementami. Jeśli chcesz wizualizować, pomyśl o macierzy wiersza lub kolumny, tj. O pojedynczym wymiarze, gdy się mnożymy, otrzymujemy tablicę o tym samym kształcie, ale o mniejszych lub wyższych wartościach, co pomaga w maksymalizacji lub minimalizacji intensywności wartości.

Ten obraz może ci pomóc, wprowadź opis zdjęcia tutaj

Szczegółowe informacje można znaleźć na stronie https://www.youtube.com/watch?v=qVP574skyuM

Reeves
źródło
1

Będę używał perspektywy Pytorch, jednak logika pozostaje taka sama.

Korzystając z Conv1d (), musimy pamiętać, że najprawdopodobniej będziemy pracować z wejściami dwuwymiarowymi, takimi jak sekwencje DNA kodowane na gorąco lub czarno-białe obrazy.

Jedyną różnicą między bardziej konwencjonalnymi Conv2d () i Conv1d () jest to, że ten ostatni używa jednowymiarowego jądra, jak pokazano na poniższym obrazku.

Przykład Conv1d () znaleziony na /programming/48859378/how-to-give-the-1d-input-to-convolutional-neural-networkcnn-using-keras/52508449

Tutaj wysokość twoich danych wejściowych staje się „głębokością” (lub kanałami_wybieranymi), a nasze wiersze stają się rozmiarem jądra. Na przykład,

import torch
import torch.nn as nn

tensor = torch.randn(1,100,4)
output = nn.Conv1d(in_channels =100,out_channels=1,kernel_size=1,stride=1)(tensor)
#output.shape == [1,1,4]

Widzimy, że jądro automatycznie rozciąga się na wysokość obrazu (tak jak w Conv2d () głębokość jądra automatycznie obejmuje kanały obrazu) i dlatego pozostaje nam tylko rozmiar jądra w odniesieniu do rozpiętości rzędy.

Musimy tylko pamiętać, że jeśli przyjmujemy dwuwymiarowe dane wejściowe, nasze filtry stają się naszymi kolumnami, a nasze wiersze rozmiarami jądra.

Erick Platero
źródło
Zdjęcie zostało zrobione z poprzedniego pytania: stackoverflow.com/questions/48859378/…
Erick Platero
1

Chciałbym wyjaśnić różnicę wizualnie i szczegółowo (komentarze w kodzie) i bardzo bardzo łatwo.

Sprawdźmy najpierw Conv2D w TensorFlow .

wprowadź opis zdjęcia tutaj

c1 = [[0, 0, 1, 0, 2], [1, 0, 2, 0, 1], [1, 0, 2, 2, 0], [2, 0, 0, 2, 0], [2, 1, 2, 2, 0]]
c2 = [[2, 1, 2, 1, 1], [2, 1, 2, 0, 1], [0, 2, 1, 0, 1], [1, 2, 2, 2, 2], [0, 1, 2, 0, 1]]
c3 = [[2, 1, 1, 2, 0], [1, 0, 0, 1, 0], [0, 1, 0, 0, 0], [1, 0, 2, 1, 0], [2, 2, 1, 1, 1]]
data = tf.transpose(tf.constant([[c1, c2, c3]], dtype=tf.float32), (0, 2, 3, 1))
# we transfer [batch, in_channels, in_height, in_width] to [batch, in_height, in_width, in_channels]
# where batch = 1, in_channels = 3 (c1, c2, c3 or the x[:, :, 0], x[:, :, 1], x[:, :, 2] in the gif), in_height and in_width are all 5(the sizes of the blue matrices without padding) 
f2c1 = [[0, 1, -1], [0, -1, 0], [0, -1, 1]]
f2c2 = [[-1, 0, 0], [1, -1, 0], [1, -1, 0]]
f2c3 = [[-1, 1, -1], [0, -1, -1], [1, 0, 0]]
filters = tf.transpose(tf.constant([[f2c1, f2c2, f2c3]], dtype=tf.float32), (2, 3, 1, 0))
# we transfer the [out_channels, in_channels, filter_height, filter_width] to [filter_height, filter_width, in_channels, out_channels]
# out_channels is 1(in the gif it is 2 since here we only use one filter W1), in_channels is 3 because data has three channels(c1, c2, c3), filter_height and filter_width are all 3(the sizes of the filter W1)
# f2c1, f2c2, f2c3 are the w1[:, :, 0], w1[:, :, 1] and w1[:, :, 2] in the gif
output = tf.squeeze(tf.nn.conv2d(data, filters, strides=2, padding=[[0, 0], [1, 1], [1, 1], [0, 0]]))
# this is just the o[:,:,1] in the gif
# <tf.Tensor: id=93, shape=(3, 3), dtype=float32, numpy=
# array([[-8., -8., -3.],
#        [-3.,  1.,  0.],
#        [-3., -8., -5.]], dtype=float32)>

Conv1D jest szczególnym przypadkiem Conv2D, jak stwierdzono w tym paragrafie z dokumentu TensorFlow Conv1D .

Ta opcja wewnętrznie przekształca tensory wejściowe i wywołuje tf.nn.conv2d. Na przykład, jeśli format danych nie zaczyna się od „NC”, tensor kształtu [partia, szerokość_instancji, kanały_kanałowe] jest przekształcany na [partia, 1, szerokość_instancji, kanały_internatywne], a filtr jest przekształcany na [1, szerokość_pliku, kanały_kanałowe, out_channels]. Wynik jest następnie przekształcany z powrotem do [partii, out_width, out_channels] (gdzie out_width jest funkcją kroku i wypełnienia jak w conv2d) i wraca do dzwoniącego.

Zobaczmy, jak możemy przenieść Conv1D również na problem Conv2D. Ponieważ Conv1D jest zwykle używany w scenariuszach NLP, możemy to zilustrować w poniższym problemie NLP.
wprowadź opis zdjęcia tutaj

cat = [0.7, 0.4, 0.5]
sitting = [0.2, -0.1, 0.1]
there = [-0.5, 0.4, 0.1]
dog = [0.6, 0.3, 0.5]
resting = [0.3, -0.1, 0.2]
here = [-0.5, 0.4, 0.1]
sentence = tf.constant([[cat, sitting, there, dog, resting, here]]
# sentence[:,:,0] is equivalent to x[:,:,0] or c1 in the first example and the same for sentence[:,:,1] and sentence[:,:,2]
data = tf.reshape(sentence), (1, 1, 6, 3))
# we reshape [batch, in_width, in_channels] to [batch, 1, in_width, in_channels] according to the quote above
# each dimension in the embedding is a channel(three in_channels)
f3c1 = [0.6, 0.2]
# equivalent to f2c1 in the first code snippet or w1[:,:,0] in the gif
f3c2 = [0.4, -0.1]
# equivalent to f2c2 in the first code snippet or w1[:,:,1] in the gif
f3c3 = [0.5, 0.2]
# equivalent to f2c3 in the first code snippet or w1[:,:,2] in the gif
# filters = tf.constant([[f3c1, f3c2, f3c3]])
# [out_channels, in_channels, filter_width]: [1, 3, 2]
# here we have also only one filter and also three channels in it. please compare these three with the three channels in W1 for the Conv2D in the gif
filter1D = tf.transpose(tf.constant([[f3c1, f3c2, f3c3]]), (2, 1, 0))
# shape: [2, 3, 1] for the conv1d example
filters = tf.reshape(filter1D, (1, 2, 3, 1))  # this should be expand_dim actually
# transpose [out_channels, in_channels, filter_width] to [filter_width, in_channels, out_channels]] and then reshape the result to [1, filter_width, in_channels, out_channels] as we described in the text snippet from Tensorflow doc of conv1doutput
output = tf.squeeze(tf.nn.conv2d(data, filters, strides=(1, 1, 2, 1), padding="VALID"))
# the numbers for strides are for [batch, 1, in_width, in_channels] of the data input
# <tf.Tensor: id=119, shape=(3,), dtype=float32, numpy=array([0.9       , 0.09999999, 0.12      ], dtype=float32)>

Zróbmy to za pomocą Conv1D (również w TensorFlow):

output = tf.squeeze(tf.nn.conv1d(sentence, filter1D, stride=2, padding="VALID"))
# <tf.Tensor: id=135, shape=(3,), dtype=float32, numpy=array([0.9       , 0.09999999, 0.12      ], dtype=float32)>
# here stride defaults to be for the in_width

Widzimy, że 2D w Conv2D oznacza, że ​​każdy kanał na wejściu i filtrze jest dwuwymiarowy (jak widzimy w przykładzie gif), a 1D w Conv1D oznacza, że ​​każdy kanał na wejściu i filtrze jest jednowymiarowy (jak widzimy u kota i psi przykład NLP).

Lerner Zhang
źródło