CNN

rYL5g.png

卷积神经网络(CNN)的结构:

卷积层→池化层→全连接层

那为何不用传统全连接神经网络处理图像呢?其缺点也是很明显的,对于大尺寸图片:

  • 首先将图片展开为张量会丢失信息
  • 处理大尺寸图片需要巨量的参数
  • 参数太多容易导致过拟合

卷积层

卷积层是构建卷积神经网络的核心层,它产生了网络中大部分的计算量。注意是计算量而不是参数量。

rI8et.png

卷积

何谓卷积?其实就是乘加运算与位置移动。上图所示,左边第一个矩阵为输入x,第二个矩阵为卷积核,所谓卷积就是他们对应位置相乘相加,最后得到了右图中235的结果。那让卷积核不停在输入x上移动过再乘加,得到的就是卷积层的输出。如下图所示卷积核在输入x上不停移动和乘加即为卷积。

rIYvk.gif

卷积运算的维度

既然引入了上图,那我们就借此说一下卷积运算的维度。都说卷积运算处理高度,宽度以外还有一个深度,何谓深度呢?我们先对以上gif做一个分析,就明白了。

首先输入为最左边一列三个矩阵,这三个矩阵来自于同一张图片的R,G,B三个通道,高度为5,宽度为5,外面灰色的0为padding(之后我们会提到),不是原图像数据内容。那么我们输入卷积层的Tensor的size就是:
$$
x[1,3,5,5]
$$
第一个维度表示一张图片,第二个维度为3个channel:RGB,也就是输入x的深度,第三、第四个维度为高度和宽度

图中第二列和第三列为两个卷积核,因为输入深度是3,所以他需要对R,G,B三个矩阵都做卷积,其深度也是3,那么卷积核的Tensor.size()就是:
$$
K[2,3,3,3]
$$
第一个维度表示两个不同卷积核,第二个维度表示3个channel,也就是深度,第三、第四个维度为高度和宽度

那输出参数呢?看图中最后一列:
$$
out[1,2,3,3]
$$
因为这是一张图片通过两个卷积核所得的两个3x3输出。

感受野

如果将上图中每个像素点看作神经节点,对比全连接神经网络,我们发现每个神经节点的输入仅与9个输入节点和权重有关,而不再是全连接中的与所有上一层输入有关。也就是说下一层节点仅与上一层一些神经节点连接,而这些神经节点数量仅决于卷积核的长和宽,这就叫做感受野,即与神经元连接的空间大小。

如此一来,参数的数量不就打打减小了吗,对于28*28的图片,全连接神经网络第一个隐藏层每个节点需要784个参数,而卷积层中只需要卷积核个数x卷积核大小 这么多个参数。

空间排列

稍微动一下脑筋,若卷积核在移动过程中不允许超出输入x的边界范围,那输出矩阵的大小肯定小于原图片大小,所以我们需要引入 padding,即在图像最外面加一层或几层全为0的像素,如此已到达输出核输入矩阵大小相同的目的。

如上图所示,输入为5x5,如果padding=0,卷积核为3x3,那么输出只有2x2,加上一层padding,输出才能达到3x3.

步长就更好理解了,即卷积核每次移动几个单位。

那么以上几个参数都确定了的话,输出尺寸为多大呢,公式如下:
$$
outsize=\frac{W-F+2P}{S}+1
$$
其中

W:输入数据大小

F:卷积核尺寸

S:步长

P:padding

pytorch卷积层模块

nn.Conv2d():其输入参数如下

def __init__(
self,
in_channels: int,
out_channels: int,
kernel_size: _size_2_t,
stride: _size_2_t = 1,
padding: Union[str, _size_2_t] = 0,
dilation: _size_2_t = 1,
groups: int = 1,
bias: bool = True,
padding_mode: str = 'zeros', # TODO: refine this type
device=None,
dtype=None
) -> None:

in_channels:输入数据的channel数(深度),为3的化通常为RGB

out_channels:输出数据的深度,与卷积核的个数相同

kernel_size:感受野的大小,卷积核的尺寸

stride:移动步长

padding:padding=0表示不填充,padding=1表示填充一层

dilation:卷积杜宇输入数据体的空间间隔,默认为1

dilation=2时计算如下:

rRubR.png

卷积时输入x不在紧邻,而是间隔一个像素点

groups:输出数据体深度上和输入数据体深度上的联系,默认为1,相关联。如果groups=2,则输入深度被分割成两份,输出数据也被分割成两份,他们之间分别对应起来,要求输入输出深度都能被groups整除。

bias:是否添加偏执

卷积层输出也需要激活函数
#example
layer1=nn.sequential(
nn.Conv2d(3,32,3,1,padding=1),nn.ReLU(True))

上述代码添加了一个输入channel为3,卷积核个数32,卷积核尺寸3x3,步长为1,padding=1,采用ReLU激活函数的卷积层。

池化层

通常会在卷积层之间周期性的插入一个池化层,其作用是逐渐减低数据体的空间尺寸,这样就能减少网络中的参数量,减少计算耗费资源,同时有效控制过拟合。

池化层和卷积层一样也有一个空间窗口,通常采取这些窗口中的最大值作为暑促,然后不断滑动窗口,对输入数据每一个深度切片(channel)单独处理,减少它的尺寸空间。

最常用的池化层尺寸为2*2,滑动步长为2:

rRnti.png

输出数据体与输入数据体尺寸关系如下:
$$
W_2=\frac{W_1-F}{S}+1
$$
F:池化窗口大小

W1:输入数据大小

W2:输出数据大小

S:步长

卷积层之间一般引入最大池化效果最好,而平均池化一般放在卷积神经网络的最后一层。

谨慎使用比较大的池化窗口,以免对网络有破坏性

pytorch池化层模块

nn.MaxPool2d()参数:

kernel_size: 窗口大小

stride: 步长

padding: 一般不添加

dilation: 默认为1

return_indices:是否返回最大值下标,默认为False

全连接层

全连接成与之前介绍的一般神经网络的结构是一样的。一般经过一系列卷积层核池化层之后,提取出图片的特征图,将特征图中所有神经元变为全连接层的样子。

比如卷积层和池化层的输出为3x3x512,那么将其变为3x3x512=4608个神经元,再经过几个隐藏层后输出结果,在这个过程中为了防止过拟合引入Dropout。

小卷积核有效性

一般而言,几个小滤波器的卷积层的组合比一个大滤波器好。

比如3个3x3的卷积核堆叠,其最终第三层卷积层对第一层输入数据的感受野是7x7,但这样做比直接使用一个7x7的卷积核好,原因如下:

  • 多个卷积层之间还有激活函数,比单一卷积层的结构更能提取出深层的特征
  • 3个3x3的卷积层才27个参数,一个7x7需要49个参数