conv1d与conv2d的区别
看到这个标题,可能不少人的想法都是“博主真是学艺不精,这么简单的区别都要写下来”。说的没错,我的确才疏学浅了。
conv1d与conv2d的区别显然在于一个是一维卷积一个是二维卷积,但是这里的“维度”具体是指哪个维度呢?在Word Embedding上使用conv1d和conv2d是一回事吗?
网络上的许多文章都说这两者完全是一回事,但是他们的理解都是有问题的,几乎把我也误导了,我特此写下这篇文章来记录此事,希望能够帮到思考这个问题的人。
起因
我近日在研究TextCNN时(为什么都2020年了还有人在研究TextCNN? 因为笔者最近才开始正经接触课程作业以外的NLP任务),发现了一种TextCNN的实现使用了conv1d,这是我第一个看到的实现,当我阅读它的代码时即发现了它使用的conv1d,当时我想,原论文中的卷积核显然是二维的(忽略通道数),为什么这里使用了conv1d?然后又看到了keras官方对imdb进行情感分析的CNN示例代码,其中也用的是conv1d。
到这我就疑惑了,上google一顿搜索conv1d和conv2d的区别,当时看到了有人对keras的例子使用conv1d提出了疑问,看上去这个issue里提的问题和我想的一样。问题是:conv1d的卷积核似乎只在word embedding向量行内进行滑动,而不会在word embedding向量之间进行滑动。有人提出的解答是,conv1d卷积核滑动的方向是在向量之间,而不是word embedding的行内。
其实这个人的解答严格来说是没有问题的,这个issue回答的是有关conv1d的卷积核滑动方向问题,无关conv1d本身的卷积核是一维还是二维的。但是我当时理解错了,以为conv1d的卷积核可以是二维的,只不过只在一个方向上滑动。我的错误理解是:conv1d会根据输入数据的shape确认二维卷积核的宽度,手动制定的kernel_size
确认了卷积核的高度,如果使用多个向量作为输入(不考虑batch),则卷积核在多个向量间方向进行滑动卷积。我的错误理解中,将conv1d当成了conv2d的一种特殊情况。
其实conv1d是不是conv2d的一种特殊情况呢?是的,但是要注意的是,conv1d的卷积核是1维的,而conv2d的卷积核是2维的。也就是说,如果你的目的是使用二维的卷积核进行卷积,那么你应该使用covn2d而非conv1d。例如一组word embedding作为输入,使用conv1d会独立地在word embedding的每个维度的数据中进行卷积,即如果词向量有300维,它是从第1维的数据的卷积加到第300维数据的卷积,而不是使用二维卷积核同时计算。
数学
如果要看清这一点,我们需要明确地去寻找conv1d的操作定义。而为了对conv1d的定义更加明晰,我们先回顾一下conv2d的定义(因为许多框架中的conv1d是用conv2d实现的)
conv2d
流行的神经网络框架中的conv1d,conv2d的定义是类似的,其中写明数学定义的有pytorch,pytorch中对conv2d的定义如下,
对于输入数据shape为
卷积核的通道数与输入数据的通道数是相同的,输出数据的通道数等于卷积核的个数,输出数据的高和宽与
我们可以看到,输出数据每一通道的二维矩阵是分别计算的,而每个通道的的矩阵的值需要对输入数据每一通道的二维矩阵做卷积后相加得到。
conv1d
当我们回顾了conv2d后再来看conv1d,可以发现定义十分类似。
输入数据的shape为
当我们使用conv2d处理图片时,二维卷积核在图片每一通道的矩阵中滑动卷积,当我们用conv1d处理向量时,一维卷积核在每一通道的向量中滑动卷积。
从数学定义上我们就可以看到,conv2d的卷积核是二维的,conv1d的卷积核是一维的,他们处理的输入数据的形状也是不同的。
文本向量
那么,具体到Word Embedding表示的文本向量中,conv1d又和conv2d有什么样的区别呢?
在TextCNN的原论文中Convolutional Neural Networks for Sentence Classification有张流传度很广的图为Figure 1,可以从中比较直观地看到对一篇文本的卷积,是对这个文本所有单词的词向量叠加成的矩阵进行二维卷积操作。下面我们将更详细地说明这个操作的实现。
首先,让我们把输入数据描述清楚。设我们的每个batch中有
当使用conv2d时,要求输入数据的形状是
可以看到,在使用conv2d时,我们将embedding向量的维度
那么使用conv1d时呢?要求输入的数据形状是
即
从上面的分析就可以清楚地看到,conv1d与conv2d在文本向量上的操作是完全不同的,他们虽然都是卷积,但是完全不是一个运算,每一个通道中,一个的卷积核是1维的向量,一个是2维的矩阵。
代码验证
我们下面将通过代码验证,我们使用tensorflow的tf.nn.conv1d来进行验证。首先确认tf.nn.conv1d与我们之前说的conv1d的操作是相同的,根据官方documentation,conv1d的定义如下
1 | tf.nn.conv1d( |
Given an input tensor of shape [batch, in_width, in_channels] if data_format is "NWC", or [batch, in_channels, in_width] if data_format is "NCW", and a filter / kernel tensor of shape [filter_width, in_channels, out_channels], this op reshapes the arguments to pass them to conv2d to perform the equivalent convolution operation.
Internally, this op reshapes the input tensors and invokes
tf.nn.conv2d
. For example, ifdata_format
does not start with "NC", a tensor of shape [batch, in_width, in_channels] is reshaped to [batch, 1, in_width, in_channels], and the filter is reshaped to [1, filter_width, in_channels, out_channels]. The result is then reshaped back to [batch, out_width, out_channels] (where out_width is a function of the stride and padding as in conv2d) and returned to the caller.
tf.nn.conv1d的输入数据shape为
文档中描述到,conv1d将会调用conv2d来实现,将输入数据reshape为
下面我们用代码验证,conv1d的计算即为用卷积核与输入word embedding的各个通道的数据分别卷积相加获得。
下面的代码首先定义了一个text embedding数据,一共4个单词,每个单词的embedding向量是3维的。首先使用一个3通道,kernel_size为2的的卷积核对其使用conv1d,得到一个结果。然后分别对该数据每一通道的数据使用每一通道的卷积核使用conv1d,将结果相加,最后得到的结果是一样的。这就说明了对于embedding向量每一维度的数据卷积,只会用到一个通道的一维卷积核进行计算,这与我们在TextCNN中期待的二维卷积计算是不一样的。
1 | text1 = [0.7, 0.4, 0.5] |
尾记
网上有不少误人子弟的文章,差点也误了我,就写篇文章总结这件事。
感谢LX大佬和我的讨论。
下面是TextCNN的一些实现参考。
论文作者的实现https://github.com/yoonkim/CNN_sentence
作者推荐的tensorflow实现https://github.com/dennybritz/cnn-text-classification-tf
尚可的一种实现https://github.com/bhaveshoswal/CNN-text-classification-keras
- 文章链接: https://renzibei.com/2020/06/30/conv1d与conv2d的区别/
- 版权声明: 本网站所有文章(包含文字、图片等内容)除特别声明外,均系作者原创,采用 CC BY-NC-ND 4.0 许可协议。引用与转载时请遵守协议、注明出处。