43 votos

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

Estaba revisando la convolución de keras docs y he encontrado dos tipos de convulsión Conv1D y Conv2D. Hice algunas búsquedas en la web y esto es lo que entiendo sobre Conv1D y Conv2D; Conv1D se utiliza para las secuencias y Conv2D utiliza para las imágenes.

Siempre pensé que las redes nerales de convolución se usaban sólo para imágenes y visualicé la CNN de esta manera

enter image description here

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

18voto

nunya Puntos 21

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

Comprobemos primero el Conv2D en TensorFlow .

enter image description here

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 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))
# 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 de el documento TensorFlow de Conv1D .

Internamente, esta operación remodela los tensores de entrada e invoca tf.nn.conv2d. Por ejemplo, si data_format no empieza por "NC", un tensor de forma [batch, in_width, in_channels] es reformado a [batch, 1, in_width, in_channels], y el filtro es reformado a [1, filter_width, in_channels, out_channels]. El resultado se vuelve a formar en [batch, out_width, out_channels] (donde out_width es una función del stride y el padding como en conv2d) y se devuelve a la persona que llama.

Veamos cómo podemos transferir Conv1D a un problema Conv2D. Dado que Conv1D se suele utilizar en escenarios de PNL, podemos ilustrarlo en el siguiente problema de PNL.
enter image description here

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

Hagamos eso 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 de 2 dimensiones (como vemos en el ejemplo del gif) y 1D en Conv1D significa que cada canal en la entrada y el filtro es de 1 dimensión (como vemos en el ejemplo del gato y el perro NLP).

6voto

user246357 Puntos 11

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

Al utilizar Conv1d(), tenemos que tener en cuenta que lo más probable es que trabajemos con entradas bidimensionales como secuencias de ADN de un solo disparo o imágenes en blanco y negro.

La única diferencia entre la más convencional Conv2d() y Conv1d() es que esta última utiliza un núcleo de 1 dimensión como se muestra en la imagen de abajo.

Conv1d() example found on https://stackoverflow.com/questions/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 núcleo se extiende automáticamente a la altura de la imagen (al igual que en Conv2d() la profundidad del núcleo se extiende automáticamente a los canales de la imagen) y por lo tanto todo lo que nos queda por dar es el tamaño del núcleo con respecto a la extensión de las filas.

Sólo tenemos que recordar que si estamos asumiendo una entrada bidimensional, nuestros filtros se convierten en nuestras columnas y nuestras filas en el tamaño del núcleo.

6voto

Aksakal Puntos 11351

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

Por ejemplo, se puede convulsionar un vector en un vector más corto como se indica a continuación. Obtenga un vector "largo" A con n elementos y convérselo utilizando el vector de pesos W con m elementos en un vector "corto" (resumido) B con n-m+1 elementos: $$b_i=\sum_{j=m-1}^0 a_{i+j}*w_j$$ donde $i=[1,n-m+1]$

Así, si tienes un vector de longitud n, y tu matriz de pesos es también de longitud n $w_i=1/n$ entonces la convolución producirá un escalar o un vector de longitud 1 igual al valor medio de todos los valores de la matriz de entrada. Es una especie de convolución degenerada si se quiere. Si la misma matriz de pesos es una más corta que la matriz de entrada, entonces se obtiene una media móvil en la salida de longitud 2, etc.

$$\begin{bmatrix} a:&a_1 & a_2 & a_3\\ w:&1/2 & 1/2&\\ w:&&1/2 & 1/2\\ \end{bmatrix}=\begin{bmatrix} b:&\frac{a_1+a_2} 2 & \frac{a_2+a_3} 2 \end{bmatrix} $$

Se podría hacer lo mismo con un tensor (matriz) tridimensional de la misma manera: $$b_{ikl}=\sum_{j_1=m_1-1\\j_2=m_2-1\\j_3=m_4-1}^{0} a_{i+j_1,k+j_2,l+j_3}*w_{j_1j_2j_3}$$ donde $i=[1,n_1-m_1+1],k=[1,n_2-m_2+1],l=[1,n_3-m_3+1]$

6voto

vaferdolosa Puntos 11

En resumen, en la CNN 1D, el núcleo se mueve en una dirección. Los datos de entrada y salida de la CNN 1D son bidimensionales. Se utiliza sobre todo en datos de series temporales.

En la CNN 2D, el núcleo se mueve en 2 direcciones. Los datos de entrada y salida de la CNN 2D son tridimensionales. Se utiliza sobre todo con datos de imágenes.

En la CNN 3D, el núcleo se mueve en 3 direcciones. Los datos de entrada y salida de la CNN 3D son de 4 dimensiones. Se utiliza sobre todo en datos de imágenes 3D (IRM, TAC).

Puede encontrar más detalles aquí: https://medium.com/@xzz201920/conv1d-conv2d-and-conv3d-8a59182c4d6

5voto

Bryan Puntos 33

Esta convolución 1d es ahorradora de costes, funciona de la misma manera pero asumiendo un array de 1 dimensión que realiza una multiplicación con los elementos. Si quieres visualizarlo, piensa en una matriz de filas o columnas, es decir, de una sola dimensión, cuando multiplicamos obtenemos una matriz de la misma forma pero con valores más bajos o más altos, lo que ayuda a maximizar o minimizar la intensidad de los valores.

Esta imagen puede ayudarte, enter image description here

Para más detalles, consulte, https://www.youtube.com/watch?v=qVP574skyuM

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X