基于Keras中Conv1D和Conv2D的区别说明

时间:2022-09-04 00:27:38

如有错误,欢迎斧正。

我的答案是,在Conv2D输入通道为1的情况下,二者是没有区别或者说是可以相互转化的。首先,二者调用的最后的代码都是后端代码(以TensorFlow为例,在tensorflow_backend.py里面可以找到):

?
1
2
3
4
5
6
7
x = tf.nn.convolution(
  input=x,
  filter=kernel,
  dilation_rate=(dilation_rate,),
  strides=(strides,),
  padding=padding,
  data_format=tf_data_format)

区别在于input和filter传递的参数不同,input不必说,filter=kernel是什么呢?

我们进入Conv1D和Conv2D的源代码看一下。他们的代码位于layers/convolutional.py里面,二者继承的都是基类_Conv(Layer)。

进入_Conv类查看代码可以发觉以下代码:

?
1
2
3
4
self.kernel_size = conv_utils.normalize_tuple(kernel_size, rank, 'kernel_size')
……#中间代码省略
input_dim = input_shape[channel_axis]
kernel_shape = self.kernel_size + (input_dim, self.filters)

我们假设,Conv1D的input的大小是(600,300),而Conv2D的input大小是(m,n,1),二者kernel_size为3。

进入conv_utils.normalize_tuple函数可以看到:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
def normalize_tuple(value, n, name):
 """Transforms a single int or iterable of ints into an int tuple.
 # Arguments
  value: The value to validate and convert. Could an int, or any iterable
   of ints.
  n: The size of the tuple to be returned.
  name: The name of the argument being validated, e.g. "strides" or
   "kernel_size". This is only used to format error messages.
 # Returns
  A tuple of n integers.
 # Raises
  ValueError: If something else than an int/long or iterable thereof was
  passed.
 """
 if isinstance(value, int):
  return (value,) * n
 else:
  try:
   value_tuple = tuple(value)
  except TypeError:
   raise ValueError('The `' + name + '` argument must be a tuple of ' +
        str(n) + ' integers. Received: ' + str(value))
  if len(value_tuple) != n:
   raise ValueError('The `' + name + '` argument must be a tuple of ' +
        str(n) + ' integers. Received: ' + str(value))
  for single_value in value_tuple:
   try:
    int(single_value)
   except ValueError:
    raise ValueError('The `' + name + '` argument must be a tuple of ' +
         str(n) + ' integers. Received: ' + str(value) + ' '
         'including element ' + str(single_value) + ' of type' +
         ' ' + str(type(single_value)))
 return value_tuple

所以上述代码得到的kernel_size是kernel的实际大小,根据rank进行计算,Conv1D的rank为1,Conv2D的rank为2,如果是Conv1D,那么得到的kernel_size就是(3,)如果是Conv2D,那么得到的是(3,3)

input_dim = input_shape[channel_axis] kernel_shape = self.kernel_size + (input_dim, self.filters)

又因为以上的inputdim是最后一维大小(Conv1D中为300,Conv2D中为1),filter数目我们假设二者都是64个卷积核。

因此,Conv1D的kernel的shape实际为:

(3,300,64)

而Conv2D的kernel的shape实际为:

(3,3,1,64)

刚才我们假设的是传参的时候kernel_size=3,如果,我们将传参Conv2D时使用的的kernel_size设置为自己的元组例如(3,300),那么传根据conv_utils.normalize_tuple函数,最后的kernel_size会返回我们自己设置的元组,也即(3,300)那么Conv2D的实际shape是:

(3,300,1,64),也即这个时候的Conv1D的大小reshape一下得到,二者等价。

换句话说,Conv1D(kernel_size=3)实际就是Conv2D(kernel_size=(3,300)),当然必须把输入也reshape成(600,300,1),即可在多行上进行Conv2D卷积。

这也可以解释,为什么在Keras中使用Conv1D可以进行自然语言处理,因为在自然语言处理中,我们假设一个序列是600个单词,每个单词的词向量是300维,那么一个序列输入到网络中就是(600,300),当我使用Conv1D进行卷积的时候,实际上就完成了直接在序列上的卷积,卷积的时候实际是以(3,300)进行卷积,又因为每一行都是一个词向量,因此使用Conv1D(kernel_size=3)也就相当于使用神经网络进行了n_gram=3的特征提取了。

这也是为什么使用卷积神经网络处理文本会非常快速有效的内涵。

补充知识:tf.layer.conv1d、conv2d、conv3d

下面我都是抄的,如果说是正确,那么conv3d就是2d+时间域的吧?

网上搜的一篇资料,还没看:tensorflow中一维卷积conv1d处理语言序列的一点记录

tensorflow中的conv1d和conv2d的区别:conv1d是单通道的,conv2d是多通道,所以conv1d适合处理文本序列,conv2d适合处理图像。

conv1d

?
1
2
3
4
5
6
7
8
9
import tensorflow as tf
input = tf.Variable(tf.random_normal([1, 5, 20]))
params1 = {"inputs": input, "filters": 2048, "kernel_size": 2,"strides":1,"activation": tf.nn.relu, "use_bias": True,"padding":'SAME'}
op01 = tf.layers.conv1d(**params1)
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
print(sess.run(tf.shape(op01)))
>>>[1,5,2048]

输入input第一维为batch_size,此处为1,即只有一个样本,第二维和第三维分别表示输入的长和宽,在文本中就是word_embedding矩阵,句子长度为5,embedding维度为20。

在文本中,卷积的某一维大小往往为embedding长度,即在宽度上不需要窗口移动,宽度就是整个窗口。所以conv1d默认卷积的宽度就为embedding维度,长度是通过kernel_size来指定的,此处为2,即卷积核的大小为2*embedding_size。strides为步长,此处为1,即卷积核每隔一个单词移动一次。filters是卷积核的个数,即输出的维度。padding有valid和same两种选择,valid在长度方向(宽度方向不padding)不进行padding,而same则在长度方向进行padding,保证输入句子长度和卷积后输出的句子长度一致,此处为5。

conv2d

?
1
2
3
4
5
6
7
8
#case 1
#input输入是1张 3*3 大小的图片,图像通道数是5(batch,长,宽,输入通道数)
#filter卷积核是 1*1 大小,数量是1(长,宽,输入通道数,输出通道数(卷积核个数))
#strides步长是[1,1,1,1],第一维和最后一维保持1不变,第二维和第三维分别为长度方向和宽度方向的步长。
#1张图最后输出的op1就是一个 shape为[1,3,3,1] 的张量,即得到一个3*3的feature map(batch,长,宽,输出通道数)
input = tf.Variable(tf.random_normal([1, 3, 3, 5]))
filter = tf.Variable(tf.random_normal([1, 1, 5, 1]))
op1 = tf.nn.conv2d(input, filter, strides=[1, 1, 1, 1], padding='SAME')

这是另一个内容

class AveragePooling1D:1D输入的平均池层.

class AveragePooling2D:2D输入的平均池层(例如图像).

class AveragePooling3D:3D输入的平均池层(例如,体积).

class Conv1D:一维卷积层(例如时间卷积).

class Conv2D:二维卷积层(例如图像上的空间卷积).

class Conv3D:3D卷积层(例如卷上的空间卷积).

class MaxPooling1D:1D输入的最大池层.

class MaxPooling2D:2D输入的最大池层(例如图像).

class MaxPooling3D:3D输入的最大池层(例如卷).

以上这篇基于Keras中Conv1D和Conv2D的区别说明就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/hahajinbu/article/details/79535172