В чем разница между Conv1D и Conv2D?

19

Я проходил документооборот по керасам и нашел два типа конвульсий Conv1D и Conv2D. Я выполнил поиск в Интернете, и это то, что я понимаю о Conv1D и Conv2D; Conv1D используется для последовательностей, а Conv2D - для изображений.

Я всегда думал, что нервные сети свертки использовались только для изображений и таким образом визуализировали CNN.

введите описание изображения здесь

Изображение рассматривается как большая матрица, а затем фильтр скользит по этой матрице и вычисляет точечное произведение. Это я верю, что Керас упоминает как Conv2D. Если Conv2D работает таким образом, то каков механизм Conv1D и как мы можем представить его механизм?

Eka
источник
2
Посмотрите на этот ответ . Надеюсь это поможет.
ученик101

Ответы:

4

Свертка - это математическая операция, в которой вы «суммируете» тензор, матрицу или вектор в меньший. Если ваша входная матрица одномерна, вы суммируете ее по измерениям, а если тензор имеет n измерений, вы можете суммировать по всем n измерениям. Conv1D и Conv2D суммируют (сворачивают) по одному или двум измерениям.

Например, вы можете свернуть вектор в более короткий вектор, как следует. Получите «длинный» вектор A с n элементами и сверните его, используя весовой вектор W с m элементами, в «короткий» (суммарный) вектор B с n-m + 1 элементами: где

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

Таким образом, если у вас есть вектор длины n, а ваша весовая матрица также имеет длину n , то в результате свертки будет получен скаляр или вектор длины 1, равный среднему значению всех значений во входной матрице. Это своего рода вырожденная свертка, если хотите. Если одна и та же весовая матрица короче входной, вы получите скользящую среднюю на выходе длины 2 и т. Д.wi=1/n

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

Вы можете сделать то же самое для трехмерного тензора (матрицы) таким же образом: где

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

Аксакал
источник
3

Эта 1-мерная свертка экономит затраты, она работает таким же образом, но принимает одномерный массив, который умножает элементы. Если вы хотите визуализировать представление о матрице из строки или столбца, т.е. одного измерения, когда мы умножаем, мы получаем массив той же формы, но с более низкими или более высокими значениями, таким образом, это помогает максимизировать или минимизировать интенсивность значений.

Это изображение может помочь вам, введите описание изображения здесь

Подробнее см. Https://www.youtube.com/watch?v=qVP574skyuM.

Reeves
источник
1

Я буду использовать перспективу Pytorch, однако логика остается той же.

При использовании Conv1d () мы должны помнить, что мы, скорее всего, будем работать с двумерными входами, такими как последовательности ДНК с горячим кодированием или черно-белые изображения.

Единственное отличие между более традиционными Conv2d () и Conv1d () состоит в том, что последний использует одномерное ядро, как показано на рисунке ниже.

Пример Conv1d () находится по адресу /programming/48859378/how-to-give-the-1d-input-to-convolutional-neural-networkcnn-using-keras/52508449

Здесь высота ваших входных данных становится «глубиной» (или in_channels), а наши строки становятся размером ядра. Например,

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]

Мы можем видеть, что ядро ​​автоматически охватывает высоту изображения (так же, как в Conv2d () глубина ядра автоматически охватывает каналы изображения), и поэтому все, что нам остается, - это размер ядра по отношению к размеру строки

Нам просто нужно помнить, что если мы предполагаем двумерный ввод, наши фильтры становятся нашими столбцами, а наши строки - размером ядра.

Эрик Платеро
источник
Фотография была взята из этого предыдущего вопроса: stackoverflow.com/questions/48859378/…
Эрик Платеро
1

Я хотел бы объяснить разницу визуально и подробно (комментарии в коде) и очень очень простой подход.

Давайте сначала проверим Conv2D в TensorFlow .

введите описание изображения здесь

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 является частным случаем Conv2D, как указано в этом параграфе из документа TensorFlow Conv1D .

Внутренне эта операция изменяет входные тензоры и вызывает tf.nn.conv2d. Например, если data_format не начинается с «NC», тензор формы [batch, in_width, in_channels] преобразуется в [batch, 1, in_width, in_channels], а фильтр преобразуется в [1, filter_width, in_channels, out_channels]. Затем результат преобразуется обратно в [batch, out_width, out_channels] (где out_width является функцией шага и заполнения, как в conv2d) и возвращается вызывающей стороне.

Давайте посмотрим, как мы можем передать Conv1D также проблема Conv2D. Поскольку Conv1D обычно используется в сценариях НЛП, мы можем проиллюстрировать это в приведенной ниже проблеме НЛП.
введите описание изображения здесь

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

Давайте сделаем это с помощью Conv1D (также в 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

Мы можем видеть, что 2D в Conv2D означает, что каждый канал на входе и фильтре является двухмерным (как мы видим в примере с gif), а 1D в Conv1D означает, что каждый канал на входе и фильтре является одномерным (как мы видим в cat и собака нлп пример).

Лернер Чжан
источник