如有错误,欢迎斧正。
我的答案是,在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