¿Cuál es la diferencia entre Conv1D y Conv2D?

19

Estaba revisando los documentos de convolución de Keras y he encontrado dos tipos de convulsiones Conv1D y Conv2D. Hice una búsqueda en la web y esto es lo que entiendo sobre Conv1D y Conv2D; Conv1D se usa para secuencias y Conv2D usa para imágenes.

Siempre pensé que las redes de convolución nerual se usaban solo para imágenes y visualizaban CNN de esta manera

ingrese la descripción de la imagen aquí

Una imagen se considera como una matriz grande y luego un filtro se deslizará sobre esta matriz y calculará el producto de puntos. Esto creo lo que Keras menciona como un Conv2D. Si Conv2D funciona de esta manera, ¿cuál es el mecanismo de Conv1D y cómo podemos imaginar su mecanismo?

Eka
fuente
2
Echa un vistazo a esta respuesta . Espero que esto ayude.
Learner101

Respuestas:

4

La convolución es una operación matemática en la que "resume" un tensor o una matriz o un vector en uno más pequeño. Si su matriz de entrada es unidimensional, entonces resume a lo largo de eso en las dimensiones, y si un tensor tiene n dimensiones, entonces podría resumir a lo largo de todas las n dimensiones. Conv1D y Conv2D resumen (convolucionan) a lo largo de una o dos dimensiones.

Por ejemplo, podría convolver un vector en un vector más corto como sigue. Obtenga un vector "largo" A con n elementos y convolucione usando el vector de peso W con elementos m en un vector "corto" (resumen) B con elementos n-m + 1: donde

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

Entonces, si tiene un vector de longitud n, y su matriz de peso también es longitud n , entonces la convolución producirá un escalar o un vector de longitud 1 igual al valor promedio de todos los valores en la matriz de entrada. Es una especie de convolución degenerada si lo desea. Si la misma matriz de peso es una más corta que la matriz de entrada, obtendrá un promedio móvil en la salida de longitud 2, etc.wi=1/n

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

Puede hacer lo mismo con el tensor tridimensional (matriz) de la misma manera: donde

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

Aksakal
fuente
3

Esta convolución 1d ahorra costos, funciona de la misma manera pero asume una matriz de 1 dimensión que hace una multiplicación con los elementos. Si desea visualizar, piense en una matriz de filas o columnas, es decir, una sola dimensión cuando multiplicamos, obtenemos una matriz de la misma forma pero de valores más bajos o más altos, por lo tanto, ayuda a maximizar o minimizar la intensidad de los valores.

Esta imagen puede ayudarte ingrese la descripción de la imagen aquí

Para obtener más información, consulte https://www.youtube.com/watch?v=qVP574skyuM

Reeves
fuente
1

Usaré una perspectiva Pytorch, sin embargo, la lógica sigue siendo la misma.

Al usar Conv1d (), debemos tener en cuenta que lo más probable es que trabajemos con entradas bidimensionales, como secuencias de ADN codificadas en caliente o imágenes en blanco y negro.

La única diferencia entre el Conv2d () más convencional y el Conv1d () es que este último utiliza un núcleo unidimensional como se muestra en la imagen a continuación.

Ejemplo de Conv1d () encontrado en /programming/48859378/how-to-give-the-1d-input-to-convolutional-neural-networkcnn-using-keras/52508449

Aquí, la altura de sus datos de entrada se convierte en la "profundidad" (o in_channels), y nuestras filas se convierten en el tamaño del núcleo. Por ejemplo,

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]

Podemos ver que el kernel se extiende automáticamente a la altura de la imagen (al igual que en Conv2d () la profundidad del kernel se extiende automáticamente por los canales de la imagen) y, por lo tanto, todo lo que tenemos que dar es el tamaño del kernel con respecto al lapso de las filas

Solo tenemos que recordar que si asumimos una entrada bidimensional, nuestros filtros se convierten en nuestras columnas y nuestras filas se convierten en el tamaño del núcleo.

Erick Platero
fuente
La imagen fue tomada de esta pregunta anterior: stackoverflow.com/questions/48859378/…
Erick Platero
0

Me gustaría explicar la diferencia visualmente y en detalle (comentarios en código) y en un enfoque muy muy fácil.

Primero revisemos el Conv2D en TensorFlow .

ingrese la descripción de la imagen aquí

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

Y el Conv1D es un caso especial de Conv2D como se indica en este párrafo del documento TensorFlow de Conv1D .

Internamente, esta operación da nueva forma a los tensores de entrada e invoca tf.nn.conv2d. Por ejemplo, si data_format no comienza con "NC", un tensor de forma [batch, in_width, in_channels] se reforma a [batch, 1, in_width, in_channels], y el filtro se reforma a [1, filter_width, in_channels, canales_salida]. El resultado se vuelve a dar forma a [lote, out_width, out_channels] (donde out_width es una función del paso y el relleno como en conv2d) y se devuelve a la persona que llama.

Veamos cómo podemos transferir Conv1D también un problema Conv2D. Dado que Conv1D se usa generalmente en escenarios de PNL, podemos ilustrar eso en el siguiente problema de PNL.
ingrese la descripción de la imagen aquí

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

Hagámoslo usando Conv1D (también en 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

Podemos ver que el 2D en Conv2D significa que cada canal en la entrada y el filtro es bidimensional (como vemos en el ejemplo de gif) y 1D en Conv1D significa que cada canal en la entrada y el filtro es 1 dimensional (como vemos en el gato y perro NLP ejemplo).

Lerner Zhang
fuente