Quelle est la différence entre Conv1D et Conv2D?

19

Je parcourais les documents de convolution keras et j'ai trouvé deux types de convultuion Conv1D et Conv2D. J'ai fait quelques recherches sur le Web et c'est ce que je comprends à propos de Conv1D et Conv2D; Conv1D est utilisé pour les séquences et Conv2D utilise pour les images.

J'ai toujours pensé que les réseaux de convolution nerual étaient utilisés uniquement pour les images et visualisaient CNN de cette façon

entrez la description de l'image ici

Une image est considérée comme une grande matrice, puis un filtre glissera sur cette matrice et calculera le produit scalaire. Je crois que ce que Keras mentionne comme un Conv2D. Si Conv2D fonctionne de cette façon, alors quel est le mécanisme de Conv1D et comment pouvons-nous imaginer son mécanisme?

Eka
la source
2
Jetez un oeil à cette réponse . J'espère que cela t'aides.
Learner101

Réponses:

4

La convolution est une opération mathématique où vous "résumez" un tenseur ou une matrice ou un vecteur en un plus petit. Si votre matrice d'entrée est unidimensionnelle, vous résumez le long de celle des dimensions, et si un tenseur a n dimensions, vous pouvez résumer le long de toutes les n dimensions. Conv1D et Conv2D résument (convolvent) selon une ou deux dimensions.

Par exemple, vous pouvez convertir un vecteur en un vecteur plus court comme suit. Obtenir un vecteur "long" A avec n éléments et le convolutionner en utilisant le vecteur de poids a avec m éléments en un vecteur "court" (résumé) B avec n-m + 1 éléments: où

bi=j=m10ai+jwj
i=[1,nm+1]

Donc, si vous avez un vecteur de longueur n et que votre matrice de poids est également de longueur n , la convolution produira un scalaire ou un vecteur de longueur 1 égal à la valeur moyenne de toutes les valeurs de la matrice d'entrée. C'est une sorte de convolution dégénérée si vous le souhaitez. Si la même matrice de poids est plus courte que la matrice d'entrée, alors vous obtenez une moyenne mobile dans la sortie de longueur 2, etc.wi=1/n

[a:a1a2a3w:1/21/2w:1/21/2]=[b:a1+a22a2+a32]

Vous pouvez faire de même pour un tenseur (matrice) tridimensionnel de la même manière: où

bikl=j1=m11j2=m21j3=m410ai+j1,k+j2,l+j3wj1j2j3
i=[1,n1m1+1],k=[1,n2m2+1],l=[1,n3m3+1]

Aksakal
la source
3

Cette convolution 1d est moins coûteuse, elle fonctionne de la même manière mais suppose un tableau 1 dimension qui fait une multiplication avec les éléments. Si vous voulez visualiser pensez à une matrice de ligne ou de colonnes, c'est-à-dire une seule dimension lorsque nous multiplions, nous obtenons un tableau de même forme mais de valeurs inférieures ou supérieures, donc cela aide à maximiser ou minimiser l'intensité des valeurs.

Cette image pourrait vous aider, entrez la description de l'image ici

Pour plus de détails, consultez https://www.youtube.com/watch?v=qVP574skyuM

Reeves
la source
1

J'utiliserai une perspective Pytorch, cependant, la logique reste la même.

Lorsque vous utilisez Conv1d (), nous devons garder à l'esprit que nous allons très probablement travailler avec des entrées bidimensionnelles telles que des séquences d'ADN à codage à chaud ou des images en noir et blanc.

La seule différence entre le Conv2d () et le Conv1d () plus conventionnels est que ce dernier utilise un noyau à 1 dimension comme indiqué dans l'image ci-dessous.

Exemple Conv1d () trouvé sur /programming/48859378/how-to-give-the-1d-input-to-convolutional-neural-networkcnn-using-keras/52508449

Ici, la hauteur de vos données d'entrée devient la «profondeur» (ou in_channels), et nos lignes deviennent la taille du noyau. Par exemple,

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]

Nous pouvons voir que le noyau s'étend automatiquement à la hauteur de l'image (tout comme dans Conv2d () la profondeur du noyau s'étend automatiquement sur les canaux de l'image) et donc tout ce qu'il nous reste à donner est la taille du noyau par rapport à la durée de les rangées.

Nous devons juste nous rappeler que si nous supposons une entrée bidimensionnelle, nos filtres deviennent nos colonnes et nos lignes deviennent la taille du noyau.

Erick Platero
la source
L'image a été prise à partir de cette question précédente: stackoverflow.com/questions/48859378/…
Erick Platero
1

Je voudrais expliquer la différence visuellement et en détail (commentaires dans le code) et dans une approche très très facile.

Vérifions d'abord le Conv2D dans TensorFlow .

entrez la description de l'image ici

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)>

Et le Conv1D est un cas spécial de Conv2D comme indiqué dans ce paragraphe du doc TensorFlow de Conv1D .

En interne, cette opération remodèle les tenseurs d'entrée et appelle tf.nn.conv2d. Par exemple, si data_format ne commence pas par "NC", un tenseur de forme [batch, in_width, in_channels] est remodelé en [batch, 1, in_width, in_channels] et le filtre est remodelé en [1, filter_width, in_channels, out_channels]. Le résultat est ensuite remodelé vers [batch, out_width, out_channels] (où out_width est fonction de la foulée et du remplissage comme dans conv2d) et renvoyé à l'appelant.

Voyons comment nous pouvons transférer Conv1D également un problème Conv2D. Puisque Conv1D est généralement utilisé dans les scénarios PNL, nous pouvons illustrer cela dans le problème ci-dessous PNL.
entrez la description de l'image ici

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)>

Faisons cela en utilisant Conv1D (également dans 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

Nous pouvons voir que le 2D dans Conv2D signifie que chaque canal dans l'entrée et le filtre est bidimensionnel (comme nous le voyons dans l'exemple gif) et 1D dans Conv1D signifie que chaque canal dans l'entrée et le filtre est 1 dimensionnel (comme nous le voyons dans le chat et chien PNL exemple).

Lerner Zhang
la source