前言
大致告一段落了,下午还要把实验整理一波,上午思考了一下 还是吧之前为了面试将机器学习、深度学习、强化学习的内容整理的放在blog,之后就是将前一段时间 弄的DRL的一些实验也放进去;
这里的CNN 其实是某次面试感知岗的时候,被问到池化层的反向传播的时候,才发现自己对于深度学习的一些基础,其实还是不够了解 不能很好地描述,知其然不知其所以然;所以将整体都好好整理了一下,下一步 还是对于RNN的内容多看些吧;
CNN的基本特征
首先是关于感受野的概念,其表示了输出的feature map上每一个节点所对应的输入图像的区域;
然后是CNN的两个基本概念:
稀疏连接和参数共享
前者作为CNN和FCN的不同之处,原有的FCN的参数矩阵的每个独立参数都表示了输入和输出单元的一次连接;而现在借助于卷积核这样的相比于输入数据来说很小的区域 检测出来一些很小的有意义的特征,从而使计算量大大减少,存储的参数量也大大减少;「比如原先的输入为m输出为n,那么需要计算m*n
现在借助于卷积核只有k个,那么这样的链接方法就只需要k*n
个参数」;
后者的参数共享,代表着只需要学习一个卷积核的参数分布,就不用针对着每个输入和输出的关系都像是FCN一样 学习一个参数;这样相同的卷积核的参数分布 学习得到一样的特征,尽管依旧需要同样的乘加运算,但是存储的参数量大大减少;
局部特征和平移等变性
上面两者总结起来其实就是局部特征这个概念。局部特征作为卷积的核心思想,不再是全连接网络那样针对每个输入和输出建立一个参数,进而用于拟合提取特征的函数关系;而是借助于相同的一组参数,针对输入数据的一部分进行对应拟合,于是相同的权值参数和激活函数带来的是相同的映射关系,于是针对每一块区域或者称为感受野 也提取的是相同类型的特征;
平移等变性:这也是卷积神经网络之所以适合处理图像的原因。其让CNN更多的在意的是:特征是否存在而非特征在哪。平移等变性的含义是输入做出一定的改变后 如平移一定的单位,输出一样有着类似的改变 即f(g(x))=g(f(x))
,这一种特性可以保证 当输入发生一定的如:平移 旋转 缩放等简单变化后 依旧能完成对于图像的识别。同时池化层也能进而保证这种属性,也就是说,池化能保证输入的表示近似不变,我们往往还是在意的是特征是否出现 而不是它的具体位置「比如最大池化层」,所以就算借助池化函数 对于相关数据进行一定的平移 之后的输出也还是不会发生变化。「同时借助池化层可以更好的考虑周围的统计特性」
池化层可以降低图像维度 加速计算
卷积的意义
- 提高统计效率
- 当处理一张图像时,输入的图像可能包含成千上万个像素点,但是我们可以通过只占用几十到上百个像素点的核来检测一些局部但有意义的特征,例如图像的边缘。
- 减少参数数量
- 减少存储需求
- 加速计算
caffe里面的group参数
涉及的一个group的参数 是用来对于卷积核分组的「输入和输出都分组」
90x100x100x32 90是数据批大小 100x100是图像数据shape,32是通道数,假设要经过一个3x3x48的卷积,group默认是1,就是全连接的卷积层;
如果group是2,则输入的32个通道分成2个16的通道,将输出的48个通道分成2个24的通道「然后各自 同一个group里面的进行计算」。对输出的2个24的通道,第一个24通道与输入的第一个16通道进行全卷积,第二个24通道与输入的第二个16通道进行全卷积。极端情况下,输入输出通道数相同,比如为24,group大小也为24,那么每个输出卷积核,只与输入的对应的通道进行卷积。
卷积核的结构和数量
首先是卷积核的结构及其数量:依照tensorflow中 构造一个标准conv2d
需要设置的参数有:
[k_height, k_width]
表示卷积核的大小;n_in
表示“输入的通道数”,n_out
表示“输出的通道数” 「也可以说是输出的卷积核的种类」
这样描述某个卷积网络层,一个卷积核大小的时候 除了正常的长宽之外 还应该包括输入的通道数 n_in
,即 [k_height, k_width, n_in]
这部分;从几何的角度来看,卷积核应该是一个“长方体”,而不是“长方形/矩形” ;同样的 卷积核的数目是n_out ;
Theano和Caffe的卷积实现
在说两者的卷积实现之前,首先说一下三通道的RGB图像进行卷积操作:
毕竟每张图像都是会有三个channel的,那么对于需要计算的:输出的M个卷积核,每个就是针对RGB三个通道,如果进一步的表示来说,卷积的shape参考tensorflow中的定义应该包括四部分:[k_width,k_length,n_in,n_out]
,因而 这里的n_in
其实就已经说明是3了,n_out
为M,于是需要做的就是 分别的使用kernel_size*kernel_size
大小的卷积核去卷积每个通道上的W*H
的图片,然后将三个通道卷积得到的输出相加,从而得到M个卷积输出的结果;
首先是Theano上的卷积操作,其将输入的图片「这里就先不要在意channel了,就是某channel来说的一个二维的input」然后展开为一个一维向量,一批数据就堆叠成为一个矩阵,形如:([in_h, in_w] -> [in_h * in_w]
);如果是一批 inputs
,则依次堆叠为一个矩阵 [N, in_h * in_w]
;「写成一行」
然后 kernel
按 步长 循环展开成一个稀疏矩阵;
可以看到 步长为1,于是在行和列上都进行空1处理,比如行上隔着一位,而列位置上空1 表现出来就是 一行内全0;进而就转为了标准的矩阵相乘:$y=C\cdot x^T$
对于caffe上的卷积操作,其会将inputs
做 im2col 操作得到输入矩阵,再将 kernel
转化为权值矩阵,然后将两个矩阵相乘得到输出矩阵: $y=x\cdot W$
具体来说,im2col操作是说:对于一个输入图像矩阵,依据卷积核的大小,对其进行重叠划分成为多个子矩阵(子区域)$[k_{height},k_{width}]$,对于每个子矩阵转化为向量的形式$k_{width}*k_{height}$,这就成为了第一行,然后卷积核的移动一次 得到新的一行,以此类推,得到一个矩阵;
同时有着多个输入矩阵 就把最终得到的矩阵 横向拼在一起;如下:
可以看到 上面的图可以认为是三个单通道 或者说一个三通道,如果是看做三通道,那么就是:对于每一行来说 就是由三个通道 每个通道里面的数据进行一次子矩阵的划分,然后序列化成一个向量 然后三个通道总共三个 然后这三个向量横向拼接;对于列来说 每一次划分就构成了一行 于是每一列中每个元素 都是不同次划分的结果;
同样的 这里的参数矩阵 也需要对应的进行变化形态 可以看到根据input的channel和卷积核shape的不同,对应的进行变化;
完整的操作如下
如上图 上半部分是卷积的直观操作,下面是转化为卷积乘法的操作;可以更直观的体现出来 对于输入向量和权值向量的操作;
“输入为 1 个
3*3*3
的三通道特征矩阵;输出为 1 个2*2*2
的双通道特征矩阵;kernel 的形状为2*2*3
「这里的3是指输入的channel单位」,数量为 2 个”
卷积里面的反向传播
就像上面所说 caffe和theano里面对于卷积操作的实现一样,其实本质上 卷积内部的操作也还是矩阵相乘;所以说 卷积的反向传播过程实际上跟普通的全连接是类似的 ,如下是标准的全连接的链式法则:
单纯的BP算法就是链式法则 然后求解梯度 对于权值进行更新;同样的 查看卷积核操作 其实也是乘加然后激活函数的套路 于是也是一样的链式法则 然后求解权值梯度,把卷积操作看做正常的全连接的样子就好,就是正常反向传播一层层就好;如下:
于是公式有
$z_{11} = a_{11}w_{11} + a_{12}w_{12} + a_{21}w_{21} + a_{22}w_{22}$ $z_{12} = a_{12}w_{11} + a_{13}w_{12} + a_{22}w_{21} + a_{23}w_{22} $ $z_{21} = a_{21}w_{11} + a_{22}w_{12} + a_{31}w_{21} + a_{32}w_{22} $ $z_{22} = a_{22}w_{11} + a_{23}w_{12} + a_{32}w_{21} + a_{33}w_{22}$
所以说
进而说道 求解偏差分配 就是需要考虑CNN中的池化层的问题了:
池化层中的反向传播
很显然 池化层中并没有参数需要学习,只是单纯的数据经过够 被进行了降维处理
同样的,对于池化层的反向传播 我们需要做的也还是误差的分配,也就是说 对于反向传播来的误差,是基于池化层shape而来的,我们需要变化为池化层输入层的大小对应单元的shape各个单元的误差,方便后续的求解梯度;举例如下:
对于池化层的输出大小为2*2
,误差项为$\delta^l= \left( \begin{array}{ccc} 2 & 8 \ 4 & 6 \end{array} \right)$ ;进而我们需要转化为其输入的误差项,进而首先把维度还原成为上一层的维度:$\left( \begin{array}{ccc} 0 & 0 & 0 & 0 \ 0 & 2 & 8 & 0 \ 0 & 4 & 6 & 0 \ 0 & 0 & 0 & 0 \end{array} \right)$
然后对于average pooling **,我们是我们是把某一范围内的输入值取平均之后 得到的结果,进而其实类似于一个范围内的数据经过了一个平均函数 也就是$average(x)=\frac{1}{m}\sum_{k=1}^m x_k$ m=4 于是针对每个$x_k$ 的导数均为$\frac{\partial average(x)}{\partial x_k}=\frac{1}{m}$ ;「平均池化中 误差是全部参数平均分配」**
于是 池化层反向传播 计算其输入层的误差就是:
同样的 对于max pooling 中,则是经过一个 max() 函数 ,有:
总结的说: 对于池化层的反向传播,只有进行误差项向上传递的操作,并没有梯度计算的操作;采用max pooling,下一层的误差项的值会原封不动的传递到上一层对应区块中的最大值所对应的神经元,而其他神经元的误差项的值都是0; 采用mean pooling, 下一层的误差项的值会平均分配到上一层对应区块中的所有神经元。
卷积其中的结构和几种特殊卷积
首先是卷积核的结构及其数量:依照tensorflow中 构造一个标准conv2d
需要设置的参数有:
[k_height, k_width]
表示卷积核的大小;n_in
表示“输入的通道数”,n_out
表示“输出的通道数” 「也可以说是输出的卷积核的种类」
这样描述某个卷积网络层,一个卷积核大小的时候 除了正常的长宽之外 还应该包括输入的通道数 n_in
,即 [k_height, k_width, n_in]
这部分;从几何的角度来看,卷积核应该是一个“长方体”,而不是“长方形/矩形” ;同样的 卷积核的数目是n_out ;
此外还有填充(padding)方法和步长的不同,得到的结果不同;
输出feature map的计算方法:
output_h =(originalSize_h+padding*2-kernelSize_h)/stride +1
转置卷积
转置卷积可以看做是卷积的逆过程, 正常的卷积操作 我们可以看做是缩小分辨率的一种操作,那么转置卷积就是一种“扩充分辨率”的过程。
其内部依然是常规的卷积操作;也就是说 为了达到填充的目的,首先需要对于输入进行某种填充,进而再执行卷积操作;用途的话,主要是用于编码器-解码器结构中 ,转置卷积可以同时实现图像的粗粒化和卷积操作,而不是通过两个单独过程来完成。
如下图,可以看到 原有单纯的卷积,是从输入确定了padding方式和步长之后,直接进行乘加之类的计算 得到新的图,举个例子就是:假如将一张5×5大小的图像输入到卷积层,其中步幅为2,卷积核为3×3,无边界扩充。则卷积层会输出2×2的图像。
而为了实现其逆过程,还原这种从2x2
到5x5
的操作 就是所谓的转置卷积的操作,如下图一个卷积核为3×3、步幅为2和无边界扩充的二维转置卷积
转置卷积和反卷积的唯一共同点在于两者输出都为5×5大小的图像,不过转置卷积执行的仍是常规的卷积操作。为了实现扩充目的,需要对输入以某种方式进行填充。
你可以理解成,至少在数值方面上,转置卷积不能实现卷积操作的逆过程。
进而各类还原:
空洞卷积
相比于原有卷积 引入了一个称为 “扩张率(dilation rate)”的新参数,该参数定义了卷积核处理数据时各值的间距,比如设置为1,那么就能让一个3x3
的卷积核实现5x5
的感受野的范围「每隔一行或一列删除一行或一列。 」
空洞卷积使 CNN 能够捕捉更远的信息,获得更大的感受野(NLP 中可理解为获取更长的上下文);同时不增加参数的数量,也不影响训练的速度。 「还是那么大的卷积核 那么多的参数」
门卷积
卷积网络与门限单元(Gated Linear Unit)的组合 ,前后两个有着一样的shape的层进行逐位相乘,两者的区别在于 前者不使用操作 后一个卷积使用sigmoid
激活函数 ,同时权值不共享
这样 经过sigmoid的函数就成为了一个至于为(0,1)的函数,就像是给每一个卷积层单元的输出加上了一个阀门;「也就是说对于卷积的激活值记上了一个门限操作,来决定其有多大的概率传到下一层去。 」
也可以起到防止梯度消失的作用:毕竟有一个卷积没有经过激活函数,于是对于这部分球到就是个标准的常数;
常见的CNN结构(从LeNet到DenseNet )
LeNet-5“Locally Connect”「卷积层和池化层」
首先就是最基本的卷积神经网络的开山之作,有着**卷积神经网络的基本结构:卷积层、池化层、全链接层 **;
以下是相关一些关于kernel和shape的介绍:层数很浅,并且kernel大小单一,C1、C3、C5三个卷积层使用的kernel大小全部都是 $5\times5$ ,;C5的feature map大小为 是因为,S4的feature map大小为 而kernel大小与其相同,所以卷积的结果大小是
S2和S4两个池化层使用的window大小均为 ,这里的池化有两种,一个是平均池化(在window内对所有数值求平均值),一个是最大池化(取window内的最大值)。
F6是一个有84个神经元的全连接层,猜测这个神经元数量也是实验所得较优的情况得来。 LeNet有一个很有趣的地方,就是S2层与C3层的连接方式。在原文里,这个方式称为“Locally Connect”;
**“Locally Connect” **
网络除了其中相关基本结构之外,就是这种连接了,图如下:
规定左上角为(0,0),右下角为(15,5),那么在(n,m)位置的“X”表示S2层的第m个feature map与C3层的第n个kernel进行卷积操作。 可以在最开始的LeNet结构图 我们可以看到池化层S2有着6channel的输出 而C3应该有着16种卷积核;
于是上面这个图 我们可用看到 比如对于C3中的第一个卷积核 只针对S2中的前三个channel进行卷积操作「C3层的第0个kernel只与S2层的前三个feature map有连接,与其余三个feature map是没有连接的; 」 而最后一个 也就是第十五个卷积核 和S2全部的channel 或者说 feature map都有连接;
*AlexNet:ReLU、多GPU、局部相应归一化层、Overlapping Pooling 、数据增强、Dropout、减小学习率*「三个卷积层 三个全连接层」
AlexNet在2012年的ImageNet竞赛上以比以往最低错误率低10个百分点的成绩夺冠。在介绍该网络的论文ImageNet Classification with Deep Convolutional Neural Networks中有很多干货:
如图 其中共包括八层结构,5层卷积层和3层全链接层。网络的输入为150,528(224x224x3)维,各层的神经元数量为:253,440=>186,624=>64,896=>64,896=>43,264=>4096=>4096=>1000(ImageNet有1000个类) 「253,440应为笔误 其实为290400」
对于其中的参数个数的计算:55*55*48*2=290400
; 27*27*128*2=186624
; 13*13*192*2=64896
; ` 13131282=43264``4848552=253440`
对于其中输出的feature map计算:
output_h =(originalSize_h+padding*2-kernelSize_h)/stride +1
输入图片大小为200×200,依次经过一层卷积(kernel size 5×5,padding 1,stride 2),pooling(kernel size 3×3,padding 0,stride 1),又一层卷积(kernel size 3×3,padding 1,stride 1)之后,输出特征图大小为:(200-5+2*1)/2+1
为99.5,取99(99-3)/1+1
为97(97-3+2*1)/1+1
为97
网络与之前的网络相比引入了以下新特征:
- ReLU非线性单元(详细的可参考其他部分的总结)
ReLU
相比 sigmoid
的优势
- 防止梯度消失:
- 从图像中也可以看到,当
sigmoid
函数在输入取绝对值非常大的正值或负值时会出现饱和现象——在图像上表现为变得很平,此时函数会对输入的微小变化不敏感——从而造成梯度消失;「也就是变化率不再发生变化」 - 而
ReLU
的导数始终是一个常数——负半区为 0,正半区为 1——所以不会发生梯度消失现象「这也是解决梯度消失的一种方法啊 换一种激活函数」
- 从图像中也可以看到,当
- 减缓过拟合**
- 从
ReLU
的图像可以看到,其在负半区的输出为 0。一旦神经元的激活值进入负半区,那么该激活值就不会产生梯度/不会被训练,造成了网络的稀疏性——稀疏激活;「类似于稀疏化激活单元的操作 」 - 从而减少了参数之间的相互依赖 也是缓解过拟合问题的发生
- 从
- 加速计算*
ReLU
的求导不涉及浮点运算,所以速度更快
为什么 ReLU 不是全程可微/可导也能用于基于梯度的学习?
- 虽然从数学的角度看 ReLU 在 0 点不可导,因为它的左导数和右导数不相等;
- 但是在实现时通常会返回左导数或右导数的其中一个,而不是报告一个导数不存在的错误。从而避免了这个问题
- 多GPU训练
参考上图 可以看到属于模型并行,每个GPU上并行地、分别地运行AlexNet的一部分(例如将4096个神经元的全连接层拆分为两个并行的2048个神经元的全连接层,第一个卷积层有96个feature map而在一块GPU上只有48个feature map等),两块GPU只在特定的层上有交互。
-
局部响应归一化层(Local Response Normalization Layer) (用的不多)
在第一层和第二层卷积层值周的激活函数后被加入了LRN层,引入这一层的主要目的,主要是为了防止过拟合,增加模型的泛化能力。 「使周围相应较大的值变得相对更大 并抑制周围反馈较小的神经单元(侧抑制)」如下图:「针对某一范围内「包括channel」的点除以其总体平方的和」
-
Overlapping Pooling
池化操作的目的是为了寻找那一小部分有代表性的特征,减少冗余信息。传统的卷积层中,相邻的池化单元是不重叠的,具体点说就是,对于一个 的feature map,如果池化的stride=2、window的size=2,我们得到的就是传统的池化操作。如果stride=2,window的size=3,那么在进行池化的过程中,相邻的池化window之间会有重叠的部分,这种池化就是overlapping pooling。论文也指出,这种池化只能“稍微”减轻过拟合。
- 数据增强
行为包括:**平移、翻转、对称等 ** 这里首先从256x256的图片中随机截取224x224的部分出来 ,显然在水平和竖直方向上每个方向有32个位置可以进行裁剪,再加上水平对称的操作 于是就是将整个数据集放大了 32*32*2
倍;
改变RGB通道的强度;**自然图片的一条重要性质:物体的鉴别特征并不会因为图片强度和颜色的变化而变化,也就是说,一定程度上改变图片的对比度、亮度、物体的颜色,并不会影响我们对物体的识别。 ** 于是对每个RGB图片的像素 $I_{xy}=[I^{R}{xy}, I^G{xy}, I^B_{xy}]^T] $变为:
!$I_{xy}=[I^{R}{xy}, I^G{xy}, I^B_{xy}]^T+[p_1,p_2,p_3][α_1λ_1,α_2λ_2,α_3λ_3]^T$
这里的p和λ是RGB值3x3协方差矩阵的特征向量和特征值。α是均值为1标准差为0.1的高斯随机变量。
6.Dropout
具体实现来说:每次某单元输出的时候 都是依据概率来判断这个单元是不是有输出「就是那个0.5之类的参数」如果不应该有 就对输出乘上0,完成对于这些单元的屏蔽;屏蔽完成后就是按照这里所说的权重推断比重 进行除以p「就是乘上倒数」 「这个时候是训练」;或者就是当测试的时候 对于权重进行乘上p;「原因也就是上面所说 毕竟不可能求全部的网络 然后对其均值得到概率分布,只能借助这个概率来体现应有输出的期望值」
Dropout 策略
简单来说,Dropout 通过参数共享提供了一种廉价的 Bagging 集成近似—— Dropout 策略相当于集成了包括所有从基础网络除去部分单元后形成的子网络。 「某些参数被隐藏 即不被使用,」
通常,隐藏层的采样概率为 0.5
,输入的采样概率为 0.8
;超参数也可以采样,但其采样概率一般为 1
权重比例推断规则
- 权重比例推断规则的目的是确保 在测试时一个单元的期望总输入与在训练时该单元的期望总输入大致相同。
- 实践时,如果使用
0.5
的采样概率,权重比例规则相当于在训练结束后将权重除 2,然后像平常一样使用模型;等价的,另一种方法是在训练期间将单元的状态乘 2。
Dropout 与 Bagging 的不同
- 在 Bagging 的情况下,所有模型都是独立的;而在 Dropout 的情况下,所有模型共享参数,其中每个模型继承父神经网络参数的不同子集。「继承来自父神经网络的不同子集」
- 在 Bagging 的情况下,每一个模型都会在其相应训练集上训练到收敛。而在 Dropout 的情况下,通常大部分模型都没有显式地被训练;取而代之的是,在单个步骤中我们训练一小部分的子网络,参数共享会使得剩余的子网络也能有好的参数设定。
7.Learning rate decay
随着训练的进行,逐渐减小学习率。
VGGNet(deep):(更深)「小卷积核 加深层 1x1用来引入非线性」
可以看到,VGGNet与AlexNet很相似,都是卷积池化-卷积池化-…-全连接的套路,不同的是kernel大小,卷积stride,网络深度。
大小卷积核的优劣
上面的AlexNet中第一个卷积层使用的kernel大小为 $11\times11 $ ,stride为4,C3和C5层中使用的都是 的卷积核;而出现在VGGNet中大多数的卷积核都是大小为 ,stride为1的。
直观上来看待 大的卷积核因为其大小 可以对应更大的感受野范围,提取到更大范围内的信息;但实际上,大的卷积核可以用多个小卷积核进行替代,比如一个5x5的卷积核 可以用两个串联的3x3卷积核来代替「假设步长为1 不包含padding 参考上面的输出feature map计算公式:有$\frac{32-5}{1}+1=\frac{[\frac{32-3}{1}+1]-3}{1}+1$」 ;类似的原因,一个 的卷积核就可以用三个串联的 卷积核来代替。
因而,大卷积被小卷积代替的好处就有着:大大减少了所需要的参数「5x5和3x3x2」;增加了更多的非线性「毕竟每一次卷积都会带来一次激活函数」
其中使用的1x1的卷积核 看做是进一步的引入非线性;同时尽管VGGNet相比于AlexNet层数更深,参数更多「后面的全连接层」,但是却可以更快的收敛,原文中被解释为“更深的网络层数和更小的卷积核起到了隐式的正则化效果”, 「个人理解 对于这句话的 小卷积核的理解 认为因为包含更多次的卷积 反向传播相比于原先 变得经过多次的更新 每一次相比于原先更新的要少 但更新的方向就更加趋向于极值点,起到了一定的正则化作用 」
Inception v1:使用了平均池化来替代全连接层
为了解决现有网络中 一味加深网络深度和宽度带来的复杂度过高「梯度弥散问题(梯度越往后穿越容易消失),难以优化模型 」,导致在不够复杂的数据上倾向于过拟合 ;包括Inception在内的GoogLeNet的核心思想是:将全连接,甚至卷积中的局部连接,全部替换为稀疏连接。 「这里所说的稀疏连接就是相比于全连接这种输入到输出之间都有着联系,卷积这种只有部分有着连接」
采用Inception 结构的原因
- 深度和宽度可以加大网络性能,但同时为了减少参数 因而将全连接转化为稀疏连接。深度稀疏网络可以被逐层简化,并且因为保留了网络的统计性质,其表达能力也没有被明显减弱。
- 计算机对于稀疏数据计算的低效性,故需将稀疏矩阵聚类为较为密集的子矩阵来提高计算性能
其中包含的原理有:当一个数据集的概率分布可以由一个很大、很稀疏的深度神经网络表示时,那么通过对于最后一层激活值的相关统计和对于输出高度相关的神经元进行聚类,可以逐层地构建出一个最优网络拓扑结构。也就是说,一个深度稀疏网络可以被逐层简化,并且因为保留了网络的统计性质,其表达能力也没有被明显减弱。
但因为对于计算机对于稀疏数据计算的低效性;需要提出的是一种,既能保持网络结构的稀疏性,又能利用密集矩阵计算的高效性的方法。大量研究表明,可以将稀疏矩阵聚类为较为密集的子矩阵来提高计算性能,Inception应运而生。 「提出了Inception网络结构,就是构造一种“基础神经元”结构,来搭建一个稀疏性、高计算性能的网络结构。 」
如上是Inception的naive版本基本单元 ,这里模型stack起来的网络**既保持了网络结构的稀疏性,又利用了密集矩阵计算的高效性 **:
-
首先 保证了稀疏性 :显然可以看到,其中主要是采用了卷积层,也就是指的卷积运算的使用;
为什么卷积运算就对于了稀疏性:传统的神经网络中,使用矩阵乘法来建立输入与输出之间的连接关系,其中参数矩阵中的每一个单独的参数都描述了一个输入单元和输出单元的交互,我们使用的kernel的尺寸是远远小于图片的尺寸的 ,也就是说其输出的feature map中,一个神经元只受到少数输入单元的影响,这是不同于密集的全连接的,称之为卷积的稀疏性。
-
至于利用了密集矩阵计算的高效性:Inception模块中的四个分支可以看作是较为稀疏的部分,但是拼接之后又成为一个大的密集矩阵。
解决5x5卷积核导致的算力花费解决: 如果之前的输入为100x100x128,5x5的卷积核有着256个,则所需要的参数则为128*5*5*256
个,但如果在之前先进行一次1x1的卷积操作(32) 则 现在的参数就变成$128\times1\times1\times32+32\times5\times5\times256$ ,数目大大减少。「加入1x1的卷积核进行channel维度的整合(降维)」
改进版:
具体的原图在这里 自行查找
具体来说 就是使用模块化的堆积;其中有使用平均池化来代替全连接层 「想法来自于Network in Network」
平均池化代替全连接层的原因:
首先是全连接层的作用,是在卷积层之后添加 首先是进行特征的向量化『flat』,后来再添加几个用于提升卷积神经网络的分类性能;但有一个问题就是其中的参数量过大 尽管有着dropout但因为本身也还是hyper-parameter 也难以优化;这时候替代的方法就选用了GAP(Global Average Pooling;
如下图:
本质上 全连接层的作用还是将卷积层来拆开成向量,进而一层层的进行分类;而GAP作用也是一样,将上述步骤 合二为一;从某种意义上,GAP对于整个网络再结构上做正则化防止过拟合,直接剔除了全连接层黑箱的特征 直接的赋予每个channel实际的内在意义;「可能导致收敛速度变慢」
网络中有三个softmax,这是为了减轻在深层网络反向传播时梯度消失的影响,也就是说,整个网络的loss是由三个softmax共同组成的,这样在反向传播的时候,即使最后一个softmax传播回来的梯度消失了,还有前两个softmax传播回来的梯度进行辅助。在对网络进行测试的时候,这两个额外的softmax将会被拿掉。这样不仅仅减轻了梯度消失的影响,而且加速了网络的收敛。
Inception v2:引入非对称卷积;V3 版本的BN
引入非对称卷积。例如,将3x1的卷积和1x3的卷积串联起来,与直接进行3x3卷积的结果是等价的。这种卷积方式大大降低了参数量,从nxn降到了2xn,所以当n越大,降低得越多。但是也并不是适用于所有的卷积方式,论文说明,在实践中在feature map为12x12~20x20时效果较好,也就是在较深层使用时效果好,浅层不太行,并且使用7x1和1x7卷积的串联可以得到很好的效果。有兴趣可以自己查看论文:Rethinking the Inception Architecture for Computer Vision。 文章在不同深度的网络使用了不同类型的inception module,三种模块如下图所示:
只在很深的层次使用含有非对称卷积的Inception module:这些最粗糙的网格,最靠近网络的末端,对于这些深层的网络来说,最关键的一点是要产生高维的稀疏表示,所以这些深层更需要的是局部处理(比如1x1的卷积得出的是最稀疏的结果),第三种Inception module是这三种模型中可以得到最稀疏结果的模型。
其他的还有结合了ResNet的残差单元的inception单元;
Batch Normalization(批标准化)
BN作为一种正则化方法,目的是加速网络的训练,并防止过拟合。 「花书P194」
动机
训练的本质是学习数据分布 ,但显然如果训练数据与测试数据的分布不同会降低模型的泛化能力。因此,应该在开始训练前对所有输入数据做归一化处理。
但尽管数据可以进行归一化处理,但是神经网络中,每个隐层的参数不同,会使下一层的输入发生变化「映射得到的分布不同」,从而导致每一批数据的分布也发生改变;致使网络在每次迭代中都需要拟合不同的数据分布,增大了网络的训练难度与过拟合的风险。
基本原理
- BN 方法会针对每一批数据,在网络的每一层输入之前增加归一化处理,使输入的均值为
0
,标准差为1
。目的是将数据限制在统一的分布下。 - 具体来说,针对每层的第
k
个神经元,计算这一批数据在第k
个神经元的均值与标准差,然后将归一化后的值作为该神经元的激活值。 - BN 可以看作在各层之间加入了一个新的计算层,对数据分布进行额外的约束,从而增强模型的泛化能力;
- 但也会降低该单元的表达能力,降低了模型的拟合能力,破坏了之前学到的特征分布;
- 为了恢复数据的原始分布,BN 引入了一个重构变换来还原最优的输入数据分布 「其中的
γ
和β
为可训练参数 」
完整的BN算法:
可以看到针对一个batch里面,对于输出x的处理 首先对于全部的x都进行求均值求方差,然后类似于$\gamma \frac{x_i-\mu}{\sqrt{\sigma^2+\epsilon}}$ 对于batch里面每个x进行这样的处理;
BN 在训练和测试时分别是怎么做的?
训练时每次会传入一批数据,做法如前述;
而在测试或预测时,每次可能只会传入单个数据,此时模型会使用全局统计量代替批统计量;
-
训练每个 batch 时,都会得到一组
(均值,方差)
; -
所谓全局统计量,就是对这些均值和方差求其对应的数学期望;
-
具体计算公式为:
其中
μ_i
和σ_i
分别表示第 i 轮 batch 保存的均值和标准差;m
为 batch_size,系数m/(m-1)
用于计算无偏方差估计原文称该方法为移动平均(moving averages)
ResNet:残差网络
首先是残差的定义:标准的残差表示着来自于观测值和估计值之间的差距「输入和输出」;但残差网络中的残差和其定义不同,一般来说 我们都是有着一个输入x 和一种想要的映射关系H(x) 是用神经网络 来拟合这种关系映射 得到一个神经网络;但 定义残差为F(x)=H(x)-x,直接使用一个神经网络来拟合这种残差F(x)「也就是说神经网络拟合的从:输入到估计值 变成了 输入到残差 」
于是一个残差单元就是:
这里可以看到:**如果identity是最优的,它就是我们想要的理想映射,那么我们可以直接将F(x)的参数全部置零;如果identity和H(x)很相近,那么我们就可以通过学习残差来修正这种差别。 **
为什么残差网络不会因为网络加深而带来的梯度消失或者题都爆炸问题:从残差网络结构可以看到 当loss对于输入进行求导的时候,因为结构 导数项会被分解为两个,而有一个直接对输入的导数项并不会消失,所以梯度一直存在。
DenseNet
如图是DenseNet的每一模块的结构,叫作Dense Block,它包括输入层在内共有5层,H是BN+ReLU+3x3Conv的操作,并不改变feature map的大小。 从图中可以看到:对于每一层来说 前面所有层的feature map『也就是输出』都被拿来当做这一层的输入
growth rate就是除了输入层之外,每一层feature map的个数。它的目的是,使得block中的任意两层都能够直接”沟通“。
其实在Dense Block输出的地方还有一个bottleneck layer,在bottleneck layer中的操作是一个1x1的卷积,卷积核共有4k个,降低channel维度,也就是减少了模型的参数。 在transition layer中有进一步压缩的操作称为compression,减少百分之θ的feature map数量,论文中使用的θ=0.5。
进而DenseNet其实是由若干个Dense Block串联起来而得到的,在每个Dense Block之间有一个Convolution+Pooling的操作,也就是图1中的transition layer。transition layer存在的意义是实现池化
**从ResNet发展到DenseNet **:DenseNet论文中认为:ResNet直接通过”Summation”操作将特征加起来,一定程度上阻碍(impede)了网络中的信息流。DenseNet通过连接(concatenate)操作来结合feature map,并且每一层都与其他层有关系,都有”沟通“,这种方式使得信息流最大化。 提升了网络的鲁棒性并且加快了学习速度。