为什么要看这些实例分析呢?之前讲了神经网络的基本构建,比如卷积层、池化层以及全连接层这些组件。事实上,过去几年计算机视觉研究中的大量研究都集中在如何把这些基本构件组合起来,形成有效的卷积神经网络。最直观的方式之一就是去看一些案例,就像很多人通过看别人的代码来学习编程一样,通过研究别人构建有效组件的案例是个不错的办法。
1.经典网络
几个经典的神经网络结构分别是LeNet-5、AlexNet和VGGNet。
LeNet:
LeNet-5是针对灰度图片训练的,所以图片的大小只有32×32×1。网络结构如下:
这个神经网络中还有一种模式至今仍然经常用到,就是一个或多个卷积层后面跟着一个池化层,然后又是若干个卷积层再接一个池化层,然后是全连接层,最后是输出,这种排列方式很常用。经典的LeNet-5网络在池化后进行了非线性函数处理,在这个例子中,池化层之后使用了sigmod函数。
LeNet中的经典模式:
- 随着网络的深度增加,图像的大小在缩小,与此同时,通道的数量却在增加;
- 每个卷积层后面都要接一个池化层。
AlexNet:
AlexNet首先用一张227×227×3的图片(彩色图片)作为输入,结构如下:
- 与LeNet相似,但AlexNet要比LeNet大得多,参数也要多很多;
- AlexNet比LeNet表现更为出色的另一个原因是它使用了ReLu激活函数;
- 在写这篇论文的时候,GPU的处理速度还比较慢,所以AlexNet采用了非常复杂的方法在两个GPU上进行训练。大致原理是,这些层分别拆分到两个不同的GPU上,同时还专门有一个方法用于两个GPU进行交流。
- 经典的AlexNet结构还有另一种类型的层,叫作“局部响应归一化层”(Local Response Normalization),即LRN层,这类层应用得并不多。(局部响应归一层的基本思路是,假如这是网络的一块,比如是13×13×256,LRN要做的就是选取一个位置,比如说这样一个位置,从这个位置穿过整个通道,能得到256个数字,并进行归一化。进行局部响应归一化的动机是,对于这张13×13的图像中的每个位置来说,我们可能并不需要太多的高激活神经元。但是后来,很多研究者发现LRN起不到太大作用,这应该是被弃用的原因之一,因为并不重要。我们现在并不用LRN来训练网络。)
VGG-16:
VGG-16网络没有那么多超参数,这是一种只需要专注于构建卷积层的简单网络。首先用3×3,步幅为1的过滤器构建卷积层,padding参数为same卷积中的参数。然后用一个2×2,步幅为2的过滤器构建最大池化层。因此VGG网络的一大优点是它确实简化了神经网络结构,下面我们具体讲讲这种网络结构:
- VGG-16的这个数字16,就是指在这个网络中包含16个卷积层和全连接层。
- 但VGG-16的结构并不复杂,这点非常吸引人,而且这种网络结构很规整,都是几个卷积层后面跟着可以压缩图像大小的池化层,池化层缩小图像的高度和宽度。
- 卷积层的过滤器数量变化存在一定的规律,由64翻倍变成128,再到256和512。作者可能认为512已经足够大了,所以后面的层就不再翻倍了。
- 每一步都进行翻倍,或者说在每一组卷积层进行过滤器翻倍操作,正是设计此种网络结构的另一个简单原则。
2.残差网络(ResNets / Residual Networks)
由于存在梯度消失和梯度爆炸问题,随着神经网络深度的加大,训练难度渐渐提升。为解决这个问题,提出了跳跃连接(Skip connection)这一概念。它可以从某一层网络层获取激活,然后迅速反馈给另外一层,甚至是神经网络的更深层。我们可以利用跳跃连接构建能够训练深度网络的ResNets,有时深度能够超过100层。
ResNets是由残差块(Residual block)构建的。下面介绍残差块的概念。
上图为神经网络块的传输过程,普通神经网络块的前向传播的计算步骤为:
- Linear:
- Relu:
- Linear:
- Relu:
而ResNet块则将其传播过程增加了一个从直接到
的连接,将其称之为“short cut”或者“skip connection”,也就是上述前向传播的最后一个公式在增加"short cut"后被改为:
注意:“short cut”或“skip connection”是添加在Relu激活函数之前的。
Residual Network:
使用残差块能够训练更深的神经网络。所以构建一个ResNet网络就是通过将很多这样的残差块堆积在一起,形成一个很深神经网络。
这个网络不是一个残差网络,而是一个普通网络(Plain network)。
把它变成残差网络的方法是加上所有的跳跃连接,每两层增加一个捷径,构成一个残差块。如图所示,5个残差块连接在一起构成一个残差网络。
Plain network和ResNet的误差曲线对比如图:
- 在没有残差的普通神经网络中,训练的误差实际上是随着网络层数的加深,先减小再增加;
- 在有残差的ResNet中,即使网络再深,训练误差都会随着网络层数的加深逐渐减小。
因此,ResNet对于中间的激活函数来说,有助于能够达到更深的网络,解决梯度消失和梯度爆炸的问题。
3.残差网络为什么有用?
设有个比较大的神经网络,输入为,输出为
。如果我们想增加网络的深度,这里再给网络增加一个残差块:
假设神经网络均使用Relu激活函数,所以最后的输出,我们给出
的值:
如果使用L2正则化或权重衰减,会压缩W和b的值,如果同时
,那么上式就变成:
结果表明,残差块学习这个恒等函数并不难,跳跃连接使我们很容易得出。这意味着,即使给神经网络增加这两层,它的效率也并不逊色于更简单的神经网络,因为学习神经网络对它来说很简单。所以尽管增加了网络的深度,但是并不会影响网络的性能。同时如果增加的网络结构能够学习到一些有用的信息,那么就会提升网络的性能。
除此之外,关于残差网络,另一个值得探讨的细节是,假设与
具有相同维度,所以ResNets使用了许多same卷积,以保持
与
维度相同。所以这个
的维度等于这个输出层的维度。之所以能实现跳跃连接是因为same卷积保留了维度,所以很容易得出这个捷径连接,并输出这两个相同维度的向量。
如何把普通深度神经网络转化为ResNet:
在两个相同的卷积层之间添加"skip connection"。
结论是,只需要添加跳跃连接。这里我们只讨论几个细节,这个网络有很多层3×3卷积,而且它们大多都是same卷积,这就是添加等维特征向量的原因。所以这些都是卷积层,而不是全连接层,因为它们是same卷积,维度得以保留,这也解释了添加项(维度相同所以能够相加)。
4.网络中的网络以及1
1卷积
1
1卷积:
计算过程:这个1×1×32过滤器中的32个数字可以这样理解,一个神经元的输入是32个数字(输入图片中左下角位置32个通道中的数字),即相同高度和宽度上某一切片上的32个数字,这32个数字具有不同通道,乘以32个权重(将过滤器中的32个数理解为权重),然后应用ReLU非线性函数,在这里输出相应的结果。
所以1×1卷积可以从根本上理解为对这32个不同的位置都应用一个全连接层,全连接层的作用是输入32个数字(过滤器数量标记为,在这36个单元上重复此过程),输出结果是6×6×#filters(过滤器数量),以便在输入层上实施一个非平凡(non-trivial)计算。
在三维上,与卷积核进行卷积,相当于三维图像上的
的切片,也就是
个点乘以卷积数值权重,通过Relu函数后,输出对应的结果。而不同的卷积核则相当于不同的隐层神经元结点与切片上的点进行一一连接。所以根本上
卷积核相当于对一个切片上的
个单元都应用了一个全连接的神经网络。
这种方法通常称为1×1卷积,有时也被称为Network in Network,在林敏、陈强和杨学成的论文中有详细描述。虽然论文中关于架构的详细内容并没有得到广泛应用,但是1×1卷积或Network in Network这种理念却很有影响力,很多神经网络架构都受到它的影响,包括下节课要讲的Inception网络。
1
1卷积的应用:
- 压缩维度:使用目标维度的
卷积核个数;
- 增加非线性:保持与原维度相同的
卷积核个数。
5.谷歌Inception网络简介
Inception Network 的作用就是使我们无需去考虑在构建深度卷积神经网络时,使用多大的卷积核以及是否添加池化层等问题。基本思想是Inception网络不需要人为决定使用哪个过滤器或者是否需要池化,而是由网络自行确定这些参数,你可以给网络添加这些参数的所有可能值,然后把这些输出连接起来,让网络自己学习它需要什么样的参数,采用哪些过滤器组合。
Inception网络主要结构 :
在上面的Inception结构中,应用了不同的卷积核,以及带padding的池化层(为了匹配所有维度,我们需要对最大池化使用padding,它是一种特殊的池化形式,因为如果输入的高度和宽度为28×28,则输出的相应维度也是28×28。然后再进行池化,padding不变,步幅为1)。在保持输入图片大小不变的情况下,通过不同运算结果的叠加,增加了通道的数量。
基本思想是Inception网络不需要人为决定使用哪个过滤器或者是否需要池化,而是由网络自行确定这些参数,你可以给网络添加这些参数的所有可能值,然后把这些输出连接起来,让网络自己学习它需要什么样的参数,采用哪些过滤器组合。
计算成本问题:
对于上面的大小的卷积核的计算成本:
- 1个filter:
(32个filter);
- 总的计算成本:
对于大小卷积核用作过渡的计算成本,也将下面的中间的层用作“bottleneck layer”,瓶颈层也是网络中最小的部分,我们先缩小网络表示,然后再扩大它:
卷积层计算成本:
卷积层计算成本:
- 总的计算成本:
所以1×1卷积核作为bottleneck layer”的过渡层能够有效减小卷积神经网的计算成本。事实证明,只要合理地设置“bottleneck layer”,既可以显著减小上层的规模,同时又能降低计算成本,从而不会影响网络的性能。
总结一下,如果你在构建神经网络层的时候,不想决定池化层是使用1×1,3×3还是5×5的过滤器,那么Inception模块就是最好的选择。我们可以应用各种类型的过滤器,只需要把输出连接起来。之后我们讲到计算成本问题,我们学习了如何通过使用1×1卷积来构建瓶颈层,从而大大降低计算成本。
你可能会问,仅仅大幅缩小表示层规模会不会影响神经网络的性能?事实证明,只要合理构建瓶颈层,你既可以显著缩小表示层规模,又不会降低网络性能,从而节省了计算。
6.Inception网络
Inception模块:
Inception模块会将之前层的激活或者输出作为它的输入,作为前提,这是一个28×28×192的输入,和我们之前视频中的一样。我们详细分析过的例子是,先通过一个1×1的层,再通过一个5×5的层,1×1的层可能有16个通道,而5×5的层输出为28×28×32,共32个通道,这就是我们之前讲过的例子。
为了能在最后将这些输出都连接起来,我们会使用same类型的padding来池化,使得输出的高和宽依然是28×28,这样才能将它与其他输出连接起来。但注意,如果你进行了最大池化,即便用了same padding,3×3的过滤器,stride为1,其输出将会是28×28×192,其通道数或者说深度与这里的输入(通道数)相同。所以看起来它会有很多通道,我们实际要做的就是再加上一个1×1的卷积层,去进行我们在1×1卷积层的视频里所介绍的操作,将通道的数量缩小,缩小到28×28×32。也就是使用32个维度为1×1×192的过滤器,所以输出的维度其通道数缩小为32。这样就避免了最后输出时,池化层占据所有的通道。
最后,将这些方块全都连接起来。在这过程中,把得到的各个层的通道都加起来,最后得到一个28×28×256的输出。通道连接实际就是之前视频中看到过的,把所有方块连接在一起的操作。这就是一个Inception模块,而Inception网络所做的就是将这些模块都组合到一起.。
Inception Network:
多个Inception 模块的堆叠构成Inception Network,下面是GoogleNet的结构:
7.迁移学习(Transfer Learning)
如果你要做一个计算机视觉的应用,相比于从头训练权重,或者说从随机初始化权重开始,如果你下载别人已经训练好网络结构的权重,你通常能够进展的相当快,用这个作为预训练,然后转换到你感兴趣的任务上。使用迁移学习可以把公共的数据集的知识迁移到你自己的问题上。
小数据集:
如今在深度学习领域,许多研究者都会将他们的工作共享到网络上。在我们实施自己的工作的时候,比如说做某种物体的识别分类,但是只有少量的数据集,对于从头开始训练一个深度网络结构是远远不够的。
但是我们可以应用迁移学习,应用其他研究者建立的模型和参数,用少量数据仅训练最后自定义的softmax网络。从而能够在小数据集上达到很好的效果。
大数据集:
如果我们在自己的问题上也拥有大量的数据集,我们可以多训练后面的几层。总之随着数据集的增加,我们需要“ freeze”的层数越来越少。最后如果我们有十分庞大的数据集,那么我们可以训练网络模型的所有参数,将其他研究者训练的模型参数作为参数的初始化来替代随机初始化,来加速我们模型的训练。
8.数据增强(Data argumentation)
大部分的计算机视觉任务使用很多的数据,所以数据扩充是经常使用的一种技巧来提高计算机视觉系统的表现。与其他机器学习问题相比,在计算机视觉领域当下最主要的问题是没有办法得到充足的数据。所以在我们训练计算机数据模型的时候,数据的扩充就是会非常有用。
数据扩充方法:
- 镜像翻转(Mirroring);
- 随机裁剪(Random Cropping);
- 色彩转换(Color shifting);
为图片的RGB三个色彩通道进行增减值,如(R:+20,G:-20,B:+20);PCA颜色增强:对图片的主色的变化较大,图片的次色变化较小,使总体的颜色保持一致。
训练过程中的数据扩充:
常用的实现数据扩充的方法是使用一个线程或者是多线程,这些可以用来加载数据,实现变形失真,然后传给其他的线程或者其他进程,来训练这个(编号2)和这个(编号1),可以并行实现。
CPU线程持续加载数据,然后实现任意失真变形,从而构成批数据或者最小批数据,这些数据持续的传输给其他线程或者其他的进程,然后开始训练,可以在CPU或者GPU上实现训一个大型网络的训练。
总结:这就是数据扩充,与训练深度神经网络的其他部分类似,在数据扩充过程中也有一些超参数,比如说颜色变化了多少,以及随机裁剪的时候使用的参数。与计算机视觉其他部分类似,一个好的开始可能是使用别人的开源实现,了解他们如何实现数据扩充。