卷积神经网络是目前计算机视觉中使用最普遍的模型结构。

本文主要讲卷积神经网络中的一些基础模块,包括了:

  • 卷积(Convolution)
  • 池化(Pooling)
  • ReLU激活函数
  • 批归一化(Batch Normalization)
  • 丢弃法(Dropout)

全连接神经网络的问题

1、输入数据的空间信息丢失。这里指的是RGB通道间的数据具有关联性,但是将其展开为1维向量输入全连接神经网络时,这些信息会丢失。并且像素点之间的空间关系也会丢失。

2、过拟合。全连接神经网络的模型参数过多,容易发生过拟合现象。

为了解决上述问题,我们就要使用卷积神经网络。

上图是一个典型的卷积神经网络结构,多层卷积和池化层组合作用在输入图片上,在网络的最后通常会加入一系列全连接层,ReLU激活函数一般加在卷积或者全连接层的输出上,网络中通常还会加入Dropout来防止过拟合。

说明: 在卷积神经网络中,计算范围是在像素点的空间邻域内进行的,卷积核参数的数目也远小于全连接层。卷积核本身与输入图片大小无关,它代表了对空间邻域内某种特征模式的提取。比如,有些卷积核提取物体边缘特征,有些卷积核提取物体拐角处的特征,图像上不同区域共享同一个卷积核。当输入图片大小不一样时,仍然可以使用同一个卷积核进行操作。

卷积

卷积计算

卷积计算在图像处理中采用的是卷积的离散形式。这里需要说明的是,在卷积神经网络中,卷积层的实现方式实际上是数学中定义的互相关 (cross-correlation)运算,与数学分析中的卷积定义有所不同。

计算过程非常容易理解:

卷积核(kernel)也被叫做滤波器(filter),假设卷积核的高和宽分别为kh​和kw​,则将称为kh​xkw​卷积,比如3×5卷积,就是指卷积核的高为3, 宽为5。

偏置:卷积神经网络中,卷积算子除了上面的计算之外,还包括加上偏置项的操作。(因此在计算加法次数的时候要算上“加偏置项”所产生的加法次数)

填充(padding)

由于经过卷积后,图像尺寸变小,为了避免卷积后图像尺寸变小,通常在图片外围进行填充,如下图所示:

步幅(stride)

步幅就是卷积核每次滑动的距离大小。

其实,输出特征图尺寸本质就是在该方向上滑动的次数+1(第一次不用滑动)

感受野(Receptive Field)

输出特征图上每个点的数值对应输入图片上kh*kw的区域的元素与卷积核每个元素相乘再相加得到的。所以输入图像上kh*kw区域内每个元素数值的改变,都会影像输出点的数值。我们将这个区域叫做输出特征图上对应点的感受野。感受野内每个元素数值的变动,都会影响输出点的数值变化。

当增加卷积网络深度的同时,感受野将会增大,输出特征图中的一个像素点将会包含更多的图像语义信息。

多输入通道、多输出通道和批量操作

  • 多输入通道场景

上面的例子中,卷积层的数据是一个2维数组,但实际上一张图片往往含有RGB三个通道,要计算卷积的输出结果,卷积核的形式也会发生变化。假设输入图片的通道数为Cin​,输入数据的形状是Cin*Hin​*Win,计算过程如下图所示。

  1. 对每个通道分别设计一个2维数组作为卷积核,卷积核数组的形状是Cin*kh*kw
  2. 对任一通道Cin∈[0,Cin),分别用大小为kh*kw​的卷积核在大小为Hin​*Win​的二维数组上做卷积。
  3. 将这Cin​个通道的计算结果相加,得到的是一个形状为Hout*Wout​的二维数组。
  • 多输出通道场景

说明:通常将卷积核的输出通道数叫做卷积核的个数。

  • 批量操作

卷积算子应用举例

池化(Pooling)

池化是使用某一位置的相邻输出的总体统计特征代替网络在该位置的输出,其好处是当输入数据做出少量平移时,经过池化函数后的大多数输出还能保持不变。比如:当识别一张图像是否是人脸时,我们需要知道人脸左边有一只眼睛,右边也有一只眼睛,而不需要知道眼睛的精确位置,这时候通过池化某一片区域的像素点来得到总体统计特征会显得很有用。由于池化之后特征图会变得更小,如果后面连接的是全连接层,能有效的减小神经元的个数,节省存储空间并提高计算效率。 如 下图所示,将一个2×2的区域池化成一个像素点。通常有两种方法,平均池化和最大池化。

池化输出特征图尺寸的计算方式与卷积相同

ReLU激活函数

Sigmoid的问题:在多层神经网络中,容易造成梯度消失现象。

Sigmoid的导数最大值为1/4,前向传播时,y=Sigmiod(x),反向传播时,L对x的梯度最大值不会超过y对x的梯度的1/4,如果有多层网络使用了Sigmoid激活函数,则比较靠后的那些层梯度将衰减到非常小的值。

批归一化(Batch Normalization)

批归一化方法(Batch Normalization,BatchNorm)是由Ioffe和Szegedy于2015年提出的,已被广泛应用在深度学习中,其目的是对神经网络中间层的输出进行标准化处理,使得中间层的输出更加稳定。

通常我们会对神经网络的数据进行标准化处理,处理后的样本数据集满足均值为0,方差为1的统计分布,这是因为当输入数据的分布比较固定时,有利于算法的稳定和收敛。对于深度神经网络来说,由于参数是不断更新的,即使输入数据已经做过标准化处理,但是对于比较靠后的那些层,其接收到的输入仍然是剧烈变化的,通常会导致数值不稳定,模型很难收敛。BatchNorm能够使神经网络中间层的输出变得更加稳定,并有如下三个优点:

  • 使学习快速进行(能够使用较大的学习率)
  • 降低模型对初始值的敏感性
  • 从一定程度上抑制过拟合

BatchNorm主要思路是在训练时以mini-batch为单位,对神经元的数值进行归一化,使数据的分布满足均值为0,方差为1。具体计算过程如下:

  1. 计算mini-batch内样本的均值
  2. 计算mini-batch内样本的方差
  3. 计算标准化之后的输出

如果强行限制输出层的分布是标准化的,可能会导致某些特征模式的丢失,所以在标准化之后,BatchNorm会紧接着对数据做缩放和平移。

其中γβ是可学习的参数,可以赋初始值γ=1,β=0,在训练过程中不断学习调整。

小窍门:

可能有读者会问:“BatchNorm里面不是还要对标准化之后的结果做仿射变换吗,怎么使用Numpy计算的结果与BatchNorm算子一致?” 这是因为BatchNorm算子里面自动设置初始值γ=1,β=0,这时候仿射变换相当于是恒等变换。在训练过程中这两个参数会不断的学习,这时仿射变换就会起作用。

预测时使用BatchNorm

使用的均值和方差是训练时保存的。

丢弃法(Dropout)

丢弃法(Dropout)是深度学习中一种常用的抑制过拟合的方法,其做法是在神经网络学习过程中,随机删除一部分神经元。训练时,随机选出一部分神经元,将其输出设置为0,这些神经元将不对外传递信号。

在预测场景时,会向前传递所有神经元的信号,可能会引出一个新的问题:训练时由于部分神经元被随机丢弃了,输出数据的总大小会变小。比如:计算其L1范数会比不使用Dropout时变小,但是预测时却没有丢弃神经元,这将导致训练和预测时数据的分布不一样。为了解决这个问题,飞桨支持如下两种方法:

  • downscale_in_infer

训练时以比例r随机丢弃一部分神经元,不向后传递它们的信号;预测时向后传递所有神经元的信号,但是将每个神经元上的数值乘以(1−r)。

  • upscale_in_train

训练时以比例、r随机丢弃一部分神经元,不向后传递它们的信号,但是将那些被保留的神经元上的数值除以(1−r);预测时向后传递所有神经元的信号,不做任何处理。

在飞桨Dropout API中,通过mode参数来指定用哪种方式对神经元进行操作,

paddle.nn.Dropout(p=0.5, axis=None, mode=”upscale_in_train”, name=None)

小练习

答案是乘法和加法都是867041280次。ps:加法的计算方式和乘法的不同。

转载请注明来源:https://www.longjin666.top/?p=1033

欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~

你也可能喜欢

发表评论