名奢网 名表 名表日报 查看内容

卷积神经网络基础(卷积,池化,激活,全连接)

2023-4-15 15:51| 发布者: 挖安琥| 查看: 83| 评论: 0

放大 缩小
简介:视频:https://space.bilibili.com/555233120 博文:https://www.zhihu.com/column/c_1531055529060831232代码:https://gitee.com/yifanrensheng/deep_learning_for_cv文章概述:主要介绍 CNN 网络发展,重点讲述了 ...

视频:https://space.bilibili.com/555233120

博文:https://www.zhihu.com/column/c_1531055529060831232

代码:https://gitee.com/yifanrensheng/deep_learning_for_cv


文章概述:主要介绍 CNN 网络发展,重点讲述了搭建 CNN 网络的组件:卷积层,池化层,激活层和全连接层。

1、CNN 简介

卷积神经网络(Convolutional Neural Networks,CNN)属于神经网络的一个重要分支。应用于CV,NLP等的各个方面。

1 发展史

  1. 1962年,Hubel和Wiesel对猫大脑中的视觉系统的研究。
  2. 1980年,日本科学家福岛邦彦在论文 NeoCognitron 中提出了包含卷积和池化的神经网络结构。
  3. 1998年,Lecun发明了LeNet,网络结构比较完整,包括卷积层、pooling层、全连接层,这些都是现代CNN网络的基本组件。
  4. 2012年AlexNet由Hinton的学生Alex Krizhevsky提出,并在当年取得了Imagenet比赛冠军。AlexNet可以算是LeNet的一种更深更宽的版本,证明了卷积神经网络在复杂模型下的有效性,算是神经网络在低谷期的第一次发声,确立了深度学习,或者说卷积神经网络在计算机视觉中的统治地位。
  5. 2014年,VGGNet是牛津大学计算机视觉组和Google DeepMind公司一起研发的深度卷积神经网络,在2014年的 ILSVRC localization and classification 两个问题上分别取得了第一名和第二名,常用的是VGG16,VGG19网络。
  6. 2014年GoogLeNet,提出的Inception结构是主要的创新点,性能比AlexNet要好;2014年ILSVRC冠军。
  7. 2015年,ResNet(残差神经网络)由微软研究院的何凯明,孙健等4名华人提出,成功训练了152层超级深的卷积神经网络,效果非常突出,而且容易结合到其他网络结构中。对应的论文应用量极大,且后续的网络大多基于残差的思想构造而来。
  8. 2017 SENet,ILSVRC竞赛2017年第一名;后面还有MobileNet,ShuffleNet,EfficientNet等。

2 出现的原因

1)传统神经网络参数巨大 VS CNN的参数共享机制

① 参数更少

  • 比如1920*1080图片采用1000的隐层连接,需要参数量为:1920*1080*1000 ≈ 207360 万个参数;
  • 而使用卷积神经网络,同样输出1000,使用卷积核 3*3大小,一共3*3*1000 = 0.9 万个参数。

平移不变性:由于filter的参数共享,即使图片进行了一定的平移操作,我们照样可以识别出特征。因此,模型就更加稳健了。

2)局部感受野

局部范围内的像素之间联系较为紧密,而距离较远的像素则相关性较弱。因而,每个神经元其实没有必要对全局图像进行感知,只需要对局部进行感知,然后在更高层将局部的信息综合起来就得到了全局的信息。而且每一个区域都有自己的专属特征,我们不希望它受到其他区域的影响。

3 常见的结构

一般而言,CNN主要由以下层构造而成:

  • 卷积层:Convolutional layer(CONV)
  • 池化层:Pooling layer (POOL)
  • 激活层:Activation Layer
  • 全连接层:Fully Connected layer(FC)

2、卷积层

1 卷积的理解

CNN 中最为重要的部分,而卷积其实主要的就是用对应的卷积核(下图左侧黄色)在被卷积矩阵上(下图左侧绿色)移动做乘法和加法得到提取后的特征(如下图右侧)。


卷积神经网络基础(卷积,池化,激活,全连接)

2 PyToch中的公式

常用的卷积(Conv2d)在pytorch中对应的函数是:

torch.nn.Conv2d(in_channels,
out_channels,
kernel_size,
stride=1,
padding=0,
dilation=1,
groups=1,
bias=True,
padding_mode='zeros',
device=None,
dtype=None)
  • in_channels (int) – 参数代表输入特征矩阵的深度即channel,比如输入一张RGB彩色图像,那in_channels=3
  • out_channels (int) – 参数代表卷积核的个数,使用n个卷积核输出的特征矩阵深度即channel就是n
  • kernel_size (int or tuple) – 参数代表卷积核的尺寸,输入可以是int类型如3 代表卷积核的height=width=3,也可以是tuple类型如(5, 3)代表卷积核的height=5,width=3
  • stride (int or tuple, optional) – 参数代表卷积核的步距默认为1,和kernel_size一样输入可以是int类型,也可以是tuple类型
  • padding (int, tuple or str, optional) – 参数代表在输入特征矩阵四周补零的情况默认为0,同样输入可以为int型如1 代表上下左右补一圈0,如果输入为tuple型如(2, 1) 代表在上方补两行下方补两行,左边补一列,右边补一列。padding[0]是在H高度方向两侧填充的,padding[1]是在W宽度方向两侧填充的。如果要实现更灵活的padding方式,可使用nn.ZeroPad2d方法。
  • dilation (int or tuple, optional)– 空洞卷积,参数代表kernel内的点(卷积核点)的间距,默认为1,取值方式类似padding。
  • bias (bool, optional) – 参数表示是否使用偏置(默认使用)
  • groups (int, optional) – 分组卷积的组数,能减少参数和正则化效果。默认为1,也即都在1个组内。

以上很多参数会影响对应的输出特征大小。


卷积神经网络基础(卷积,池化,激活,全连接)

【图片截取自pytorch官网】

注意:pytorch的图片载入tensor的顺序:[ Batch,Channel,Height,Width ]

实际应用中,dilation相对较少,因此特征图的边长公式一般可以简化如下:

N=(WF+2P)/S+1

其中:

  • W是输入的图像的宽度
  • F是卷积核大小,一般是 F × F
  • P是填充值
  • S是步长

说明:当所得N为非整数时,我们采用向下取整(等于小于自己的最大整数)的方式进行。

3 卷积对通道的影响及计算

1)通道影响

一般卷积过程如下图所示,其中:

  • 输入的图像的宽度 W = 5
  • 卷积核 F = 3
  • 填充值 P = 1
  • 步长 S = 2
  • 输出的特征 N = 3
  • 初始通道数 3;输出通道数:2

卷积神经网络基础(卷积,池化,激活,全连接)

① 对于输出宽度,再校验一次上述公式:

\begin{aligned} &公式: N=(WF+2P)/S+1 \\ &本例:3 = (5-3 +2*1)/2 +1 \end{aligned}

② 对于最终的特征值的数量为2个,这个根据卷积核的组数决定的,也即中间红色部分是两列。若是想得到更多特征数量,可以增加卷积核的组数来控制。

2)训练中参数计算

假设卷积核大小为 n*m,输入时有C个通道(channels)/维度,而选用的"卷积核/filter"有K个,再加上1个bias,可以得到引进的参数有:

\begin{aligned} &公式:(n*m*C+1)*k \\ &本例:(3*3*3+1)*2\\ \end{aligned}

3、池化层

1 池化层的理解

池化层不改变三维矩阵的深度,可以缩小矩阵的大小。池化操作可以认为是将一张分辨率高的图片转化为分辨率较低的图片。通过池化层,可以进一步缩小最后全连接层中节点的个数,从而到达减少整个神经网络参数的目的。池化层本身没有可以训练的参数。一般有三种池化策略:

  • 最大池化:把卷积后函数区域内元素的最大值作为函数输出的结果,对输入图像提取局部最大响应,选取最显著的特征。
  • 平均池化:把卷积后函数区域内元素的算法平均值作为函数输出结果,对输入图像提取局部响应的均值。
  • 最小池化:把卷积后函数区域内元素的最小值作为函数输出的结果,对输入图像提取局部最小响应,选取最小的特征(一般不用,因为现在使用大多是 relu激活,使用最小池化,会导致无意义)。如下图。

卷积神经网络基础(卷积,池化,激活,全连接)

2 池化层计算公式

1)PyTorch 接口和公式

torch.nn.MaxPool2d(kernel_size,
stride=None,
padding=0,
dilation=1,
return_indices=False,
ceil_mode=False)
  • kernel_size (int or tuple) – 参数代表移动的窗口尺寸
  • stride (int or tuple, optional) – 参数代表窗口移动的步距默认为 kernel_size
  • padding (int, tuple or str, optional) – 参数代表在输入特征矩阵四周补零的情况默认为0,同样输入可以为int型如1 代表上下左右补一圈0,如果输入为tuple型如(2, 1) 代表在上方补两行下方补两行,左边补一列,右边补一列。可见下图,padding[0]是在H高度方向两侧填充的,padding[1]是在W宽度方向两侧填充的。如果要实现更灵活的padding方式,可使用nn.ZeroPad2d方法。
  • dilation (int or tuple, optional)– a parameter that controls the stride of elements in the window类似卷积中的空洞数量,默认为1 。
  • return_indices (bool) – if True, will return the max indices along with the outputs. Useful for torch.nn.MaxUnpool2d later。
  • ceil_mode (bool) – when True, will use ceil instead of floor to compute the output shape,ceil向上取整数(即不小于该值的最大整数),否则向下取整(默认为该形式)。


卷积神经网络基础(卷积,池化,激活,全连接)

【图片截取自 pytorch官网 】

实际应用中,dilation相对较少,因此特征图的边长公式一般可以简化如下:

N=(WF+2P)/S+1

其中:

  • W是输入的图像的宽度
  • F是池化窗口大小,一般是 F × F
  • P是填充值
  • S是步长

说明:当所得N为非整数时,默认采用向下取整(等于小于自己的最大整数)的方式进行。

2)一般经验

  • 池化层中没有需要学习的参数,所以通常不把池化层当做独立的一层来看。
  • 池化层是一般不会设置pading,即一般padding为0。
  • kernel_size为2,stride为2是最常见的参数设置,尺寸图像缩小为原来的一半。

4、激活层

激活函数(Activation Function),就是在人工神经网络的神经元上运行的函数,负责将神经元的输入映射到输出端。

激活函数的主要作用是提供网络的非线性建模能力。如果没有激活函数,那么该网络仅能够表达线性映射,此时即便有再多的隐藏层,其整个网络跟单层神经网络也是等价的。因此也可以认为,只有加入了激活函数之后,深度神经网络才具备了分层的非线性映射学习能力。


卷积神经网络基础(卷积,池化,激活,全连接)

该图可用代码中的tools activate_test.py 运行得到。

1 Sigmoid

Sigmoid函数也叫Logistic函数,用于隐层神经元输出,取值范围为(0,1),它可以将一个实数映射到(0,1)的区间,可以用来做二分类。在特征相差比较复杂或是相差不是特别大时效果比较好。sigmoid是一个十分常见的激活函数,函数的表达式如下:

\begin{aligned} & f(x) = \frac{1}{1+e^{-z}} \\ & f'(x) = f(x)(1-f(x)) \end{aligned}

优点:

  1. Sigmoid函数的输出映射在(0,1)之间,单调连续,输出范围有限,如果是非常大的负数,那么输出就是0;如果是非常大的正数,输出就是1。优化稳定,可以用作输出层。
  2. 求导容易。
  3. sigmoid 函数曾经被使用的很多,不过近年来,用它的人越来越少了。

缺点:

  1. 容易饱和和终止梯度传递("死神经元");
  2. sigmoid函数的输出没有0中心化。

2 Tanh(双曲正切函数)

它是完全可微分的,反对称,对称中心在原点。为了解决学习缓慢和/或梯度消失问题。

\begin{aligned} & f(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} \\ & f'(x) = 1-f^2(x) \end{aligned}

优点

  1. 比Sigmoid函数收敛速度更快。
  2. 相比Sigmoid函数,其输出以0为中心。

缺点

还是没有改变Sigmoid函数的最大问题——由于饱和性产生的梯度消失。

3 ReLU(Rectified linear unit) 修正线性单元

\begin{aligned} & f(x)= max(0,x) \\ & f'(x) = \begin{cases} 0 , \quad & if \; x<0 \\ 1 , \quad & if \; x>0 \\ underfined , \quad & if \; x=0 \\ \end{cases} \end{aligned}

优点

  1. 相比起Sigmoid和tanh,ReLU在SGD中能够快速收敛。
  2. Sigmoid和tanh涉及了很多很expensive的操作(比如指数),ReLU可以更加简单的实现。
  3. 有效缓解了梯度消失的问题,在输入为正时,Relu函数不存在饱和问题,即解决了gradient vanishing问题,使得深层网络可训练。
  4. Relu输出会使一部分神经元为0值,在带来网络稀疏性的同时,也减少了参数之间的关联性,一定程度上缓解了过拟合的问题;

缺点

  1. 没有边界,可以使用变种ReLU6: min(max(0,x), 6)
  2. 比较脆弱,比较容易陷入出现"死神经元"的情况

4 Leaky ReLU

经典(以及广泛使用的)ReLU 激活函数的变体,带泄露修正线性单元(Leaky ReLU)的输出对负值输入有很小的坡度。由于导数总是不为零,这能减少静默神经元的出现,允许基于梯度的学习(虽然会很慢)。

\begin{aligned} & f(x) = max(\alpha x, x) \\ & \\ & 其中: \\ & \alpha \; 一般取很小的数值,比如 0.01等\\ \end{aligned}

优点

  1. 具体有ReLu相同的优势。
  2. 针对Relu函数中存在的"死神经元"问题,Leaky Relu函数在输入为负值时,给予输入值一个很小的斜率;

缺点

  1. 理论上来说,该函数比Relu函数更好的效果,但大量的实践证明,其效果不稳定,故实际中该函数的应用并不多。
  2. 无法为正负输入值提供一致的关系预测。

5 ELU

ELU(Exponential Linear Unit) 的提出同样也是针对解决 ReLU负数部分存在的问题,由Djork等人提出,被证实有较高的噪声鲁棒性。ELU激活函数对 x 小于零的情况采用类似指数计算的方式进行输出。与 ReLU 相比,ELU 有负值,这会使激活的平均值接近零。均值激活接近于零可以使学习更快,因为它们使梯度更接近自然梯度。 函数表达式为

\begin{aligned} & f(x) = \begin{cases} \alpha (e^x -1), \quad & if \; x ≤ 0 \\ x , \quad & if \; x > 0 \\ \end{cases} \\ & f'(x) = \begin{cases} f(x) + \alpha, \quad & if \; x ≤ 0 \\ 1 , \quad & if \; x > 0 \\ \end{cases} & \\ &其中:\\ & \alpha \; 一般取1或2\\ \end{aligned}

优点:

  1. ELU具有Relu的大多数优点,不存在Dead Relu问题;
  2. 该函数在负数域存在饱和区域,从而对噪声具有一定的鲁棒性;

缺点:

  1. 计算强度较高,含有指数运算;
  2. 在实践中同样没有较Relu更突出的效果,故应用不多。

6 GELU

GELU(Gaussian Error Linear Unit 高斯误差线性单元)是一个非初等函数形式的激活函数,是RELU的变种。由16年论文 Gaussian Error Linear Units (GELUs) 提出,随后被GPT-2、BERT、RoBERTa、ALBERT 等NLP模型所采用。因为gelu的非线性变化是一种符合预期的随机正则变换方式,公式如下:

\mathrm{xP}(\mathrm{X} \leq \mathrm{x})= \mathrm{x} \int_{-\infty}^{\mathrm{x}} \frac{\mathrm{e}^{-\frac{(\mathrm{X} - \mu)^{2}}{2 \sigma^{2}}}}{\sqrt{2 \pi} \sigma} \mathrm{dX}

一般实际计算过程中,使用简单形式替换:

0.5 \mathrm{x}\left(1+\tanh \left[\sqrt{\frac{2}{\pi}}\left(\mathrm{x}+0.044715 \mathrm{x}^{3}\right)\right]\right)

或者使用:

x \sigma(1.702x)

优点:

  1. 似乎是 NLP 领域的很好用;尤其在 Transformer 模型中表现最好。
  2. 对比RELU,在x=0处依旧可导,能避免梯度消失问题。
  3. 代码实现也比较简单。

源码中的GELU

在google-research/bert/modeling.py中的GELU,也是采用近似的形式实现的:

def gelu():
cdf = 0.5 * (1.0 + tf.tanh((np.sqrt(2 / np.pi) * (x + 0.044715 * tf.pow(x, 3)))))
return x * cdf

而在pretrained-BERT-pytorch/modeling.py中,更加精准:

def gelu(x):
"""Implementation of the gelu activation function.
For information: OpenAI GPT's gelu is slightly different (and gives slightly different results):
0.5 * x * (1 + torch.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * torch.pow(x, 3))))
Also see https://arxiv.org/abs/1606.08415
"""
return x * 0.5 * (1.0 + torch.erf(x / math.sqrt(2.0)))

7 小结


卷积神经网络基础(卷积,池化,激活,全连接)

上图来源于论文:gaussian error linear units

  1. CNN尽量不要使用sigmoid,如果要使用,建议只在全连接层使用
  2. tanh激活函数在某些情况下有比较好的效果,但是应用场景比较少
  3. 首先使用ReLU,因为迭代速度快,但是有可能效果不佳
  4. 如果使用ReLU失效的情况下,考虑使用Leaky ReLu或者GELU,此时一般情况都可以解决

5、全连接层

全连接层(fully connected layers,FC)在整个卷积神经网络中起到“分类器”的作用。如果说卷积层、池化层和激活函数等操作是将原始数据映射到隐层特征空间的话,全连接层则起到将学到的“分布式特征表示”映射到样本标记空间的作用。之前MLP网络中使用的就是大量的全连接层组成的网络。

我们都知道全连接层是最需要参数支撑的(可占整个网络参数80%左右),对模型影响参数:

  • 全接解层的总层数(长度)
  • 单个全连接层的神经元数(宽度)

作用及使用方式

最后一层FC一般用于分类,输出不同类的概率。

全连接层宽度或长度增加,神经元个数增加,模型复杂度提升。理论上可以提高模型的学习能力。长度和宽度都是越多越好?肯定不是,原因有:

  • 学习能力太好容易造成过拟合。
  • 运算时间增加,效率变低。

替代方案:用全局平均池化(global average pooling,GAP)取代全连接层来融合学到的深度特征。如ResNet和GoogLeNet等。

同全连接层相比,GAP的一个优点

  • 它强制了特征图和类别之间的对应关系,更加适合卷积结构。因此,特征图可以很容易地解释为类别置信度图。
  • GAP没有要优化的参数,因此能避免过拟合
  • GAP汇总了空间信息,对输入的空间变换也更鲁棒

路过

雷人

握手

鲜花

鸡蛋
已有 0 人参与

会员评论

文章排行

  • 阅读
  • 评论

最新文章

文章列表

 名表回收网手机版

官网微博:名表回收网服务平台

今日头条二维码 1 微信公众号二维码 1 抖音小程序二维码 1
浙江速典奢贸易有限公司 网站经营许可证 备案号:浙ICP备19051835号2012-2022
名表回收网主要专注于手表回收,二手名表回收/销售业务,可免费鉴定(手表真假),评估手表回收价格,正规手表回收公司,浙江实体店,支持全国范围上门回收手表
返回顶部