如何理解卷积神经网络(CNN)中的卷积和池化?
31 个回答
要说明这个问题,首先要从计算机视觉中的“Hello World”问题说起: MNIST手写数字的分类 。给定图像,将其分类。

MNIST数据集中的每个图像都是28x28像素,包含一个居中的灰度数字。
什么是卷积?
首先,介绍一下什么是卷积神经网络。
它是使用卷积层(Convolutional layers)的神经网络,基于卷积的数学运算。
卷积层由一组滤波器组成,滤波器可以视为二维数字矩阵。这是一个示例3x3滤波器:

我们可以将滤波器与输入图像进行卷积来产生输出图像,那么什么是卷积操作呢?具体的步骤如下:
- 在图像的某个位置上覆盖滤波器;
- 将滤波器中的值与图像中的对应像素的值相乘;
- 把上面的乘积加起来,得到的和是输出图像中目标像素的值;
- 对图像的所有位置重复此操作。
这个4步描述有点抽象,所以让我们举个例子吧。看下面的4x4灰度图像和3x3滤波器:

图像中的数字表示像素亮度,0是黑色,255是白色。我们将对输入图像和滤波器进行卷积,生成2x2输出图像。
首先,让我们将滤镜覆盖在图片的左上角:

接下来,我们在重叠的图像和滤波器元素之间逐个进行乘法运算,按照从左向右、从上到下的顺序。

把最右列的乘积结果全部相加,得到:

由于滤波器覆盖在输入图像的左上角,因此目标像素是输出图像的左上角像素:

用同样的方式处理图像剩下的区域:

求卷积有何用?
看完了基本概念,你可能会有疑问,对图像求卷积有什么用吗?
我们在前文中使用的那个3x3滤波器,通常称为垂直**索伯滤波器**(Sobel filter):

看看用它来处理知名的Lena照片会得到什么:

看出来了吗?其实, 索伯滤波器是是边缘检测器 。
现在可以解释卷积操作的用处了:用输出图像中更亮的像素表示原始图像中存在的边缘。
你能看出为什么边缘检测图像可能比原始图像更有用吗?
回想一下MNIST手写数字分类问题。在MNIST上训练的CNN可以找到某个特定的数字。比如发现数字1,可以通过使用边缘检测发现图像上两个突出的垂直边缘。
通常,卷积有助于我们找到特定的局部图像特征(如边缘),用在后面的网络中。
填充
在上面的处理过程中,我们用3x3滤波器对4x4输入图像执行卷积,输出了一个2x2图像。
通常,我们希望输出图像与输入图像的大小相同。因此需要在图像周围添加零,让我们可以在更多位置叠加过滤器。3x3滤波器需要在边缘多填充1个像素。

这种方法称之为“相同”填充,因为输入和输出具有相同的大小。而不使用任何填充称为“有效”填充。
池化
图像中的相邻像素倾向于具有相似的值,因此通常卷积层相邻的输出像素也具有相似的值。这意味着,卷积层输出中包含的大部分信息都是冗余的。
如果我们使用边缘检测滤波器并在某个位置找到强边缘,那么我们也可能会在距离这个像素1个偏移的位置找到相对较强的边缘。但是它们都一样是边缘,我们并没有找到任何新东西。
池化层解决了这个问题。这个网络层所做的就是通过减小输入的大小降低输出值的数量。
池化一般通过简单的最大值、最小值或平均值操作完成。以下是池大小为2的最大池层的示例:

刚写完相关的文章,转载一部分过来。
来自自己的专栏: 当我们在谈论数据挖掘 - 知乎专栏
CNN 其实可以看作 DNN 的一种特殊形式。它跟传统 DNN 标志性的区别在于两点,Convolution Kernel 以及 Pooling。
Convolution Kernel
卷积
说起卷积,一般我们我们接触过的都是一维信号的卷积,也就是
y[n]=x[n]\ast h[n]=\sum_k x[k]h[n-k]在信号处理中, x[n] 是输入信号, h[n] 是单位响应。于是输出信号 y[n] 就是输入信号 x[n] 的延迟响应的叠加。这也就是一维卷积本质:加权叠加/积分。
那么对于二维信号,比如图像,卷积的公式就是
y[m,n]=x[m,n]\ast h[m,n]=\sum_j \sum_i x[i,j]h[m-i,n-j]假设现在 Convolution Kernel 大小是 3\times 3 ,我们就可以化简上式为

看公式不太容易明白,我们画个图看看,假如 Convolution Kernel 如下图

那么,从 Input Image 到 Output Image 的变化如下

可以看出,其实二维卷积一样也是加权叠加/积分。需要注意的是,其中 Convolution Kernel 进行了水平和竖直方向的翻转。
Convolution Kernel 的意义
Convolution Kernel 其实在图像处理中并不是新事物,Sobel 算子等一系列滤波算子,一直都在被用于边缘检测等工作中,只是以前被称为 Filter。做图像处理的同学应该有印象。
Convolution Kernel 具有的一个属性就是局部性。即它只关注局部特征,局部的程度取决于 Convolution Kernel 的大小。比如用 Sobel 算子进行边缘检测,本质就是比较图像邻近像素的相似性。
也可以从另外一个角度理解 Convolution Kernel 的意义。学过信号处理的同学应该记得,时域卷积对应频域相乘。所以原图像与 Convolution Kernel 的卷积,其实对频域信息进行选择。比如,图像中的边缘和轮廓属于是高频信息,图像中某区域强度的综合考量属于低频信息。在传统图像处理里,这是指导设计 Convolution Kernel 的一个重要方面。
CNN 的 Convolution Kernel
CNN 中的 Convolution Kernel 跟传统的 Convolution Kernel 本质没有什么不同。仍然以图像为例,Convolution Kernel 依次与 Input 不同位置的图像块做卷积,得到 Output,如下图。

同时,CNN 有一些它独特的地方,比如各种定义:
- CNN 可以看作是 DNN 的一种简化形式,即这里 Convolution Kernel 中的每一个权值就可以看成是 DNN 中的 w ,且与 DNN 一样,会多一个参数 Bias b
- 一个 Convolution Kernel 在与 Input 不同区域做卷积时,它的参数是固定不变的。放在 DNN 的框架中理解,就是对同一层 Layer 中的神经元而言,它们的 w 和 b 是相同的,只是所连接的节点在改变。因此在 CNN 里,这叫做 Shared Weights and Biases
- 在 CNN 中,Convolution Kernel 可能是高维的。假如输入是 m \times n \times k 维的,那么一般 Convolution Kernel 就会选择为 d \times d \times k 维,也就是与输入的 Depth 一致
- 最重要的一点,在 CNN 中,Convolution Kernel 的权值不需要提前设计,而是跟 DNN 一样利用 GD 来优化,我们只需要初始化
- 如上面所说,其实 Convolution Kernel 卷积后得到的会是原图的某些特征(如边缘信息),所以在 CNN 中,Convolution Kernel 卷积得到的 Layer 称作 Feature Map
- 一般 CNN 中两层之间会含有多个 Convolution Kernel,目的是学习出 Input 的不同特征,对应得到多个 Feature Map。又由于 Convolution Kernel 中的参数是通过 GD 优化得到而非我们设定的,于是初始化就显得格外重要了
Pooling
Pooling 的本质,其实是采样。Pooling 对于输入的 Feature Map,选择某种方式对其进行压缩。如下图,表示的就是对 Feature Map 2 \times 2 邻域内的值,选择最大值输出到下一层,这叫做 Max Pooling。于是一个 2N \times 2N 的 Feature Map 被压缩到了 N \times N 。

除此之外,还有Mean-Pooling,Stochastic-Pooling 等。它们的具体实现如名称所示,具体选择哪一个则取决于具体的任务。
Pooling 的意义,主要有两点:
- 其中一个显而易见,就是减少参数。通过对 Feature Map 降维,有效减少后续层需要的参数
- 另一个则是 Translation Invariance。它表示对于 Input,当其中像素在邻域发生微小位移时,Pooling Layer 的输出是不变的。这就使网络的鲁棒性增强了,有一定抗扰动的作用
回答里的公式太难用了。。对 CNN 还有想要更多了解的可以参考原专栏文章: