3.4 CNN架构

3.4 CNN架构

学习目标

  • 目标

    • 知道LeNet-5网络结构

    • 了解经典的分类网络结构

    • 说明一些常见的卷机网络结构的优化

    • 知道NIN中1x1卷积原理以及作用

    • 知道Inception的作用

    • 说明ResNet的结构特点

    • 了解卷积神经网络学习过程内容

  • 应用

下面我们主要以一些常见的网络结构去解析,并介绍大部分的网络的特点。这里看一下卷积的发展历史图。

3.4.1 LeNet-5解析

首先我们从一个稍微早一些的卷积网络结构LeNet-5(这里稍微改了下名字),开始的目的是用来识别数字的。从前往后介绍完整的结构组成,并计算相关输入和输出。

3.3.1.1 网络结构

  • 激活层默认不画网络图当中,这个网络结构当时使用的是sigmoid和Tanh函数,还没有出现Relu函数

  • 将卷积、激活、池化视作一层,即使池化没有参数

3.4.1.2 参数形状总结

shape

size

parameters

 

Input

(32,32,3)

3072

0

Conv1(f=5,s=1)

(28,28,6)

4704

450+6

Pool1

(14,14,6)

1176

0

Conv2(f=5,s=1)

(10,10,16)

1600

2400+16

Pool2

(5,5,16)

400

0

FC3

(120,1)

120

48000+120

FC4

(84,1)

84

10080+84

Ouput:softmax

(10,1)

10

840+10

  • 中间的特征大小变化不宜过快

事实上,在过去很多年,许多机构或者学者都发布了各种各样的网络,其实去了解设计网络最好的办法就是去研究现有的网络结构或者论文。大多数网络设计出来是为了Image Net的比赛(解决ImageNet中的1000类图像分类或定位问题),后来大家在各个业务上进行使用。

3.4.2 AlexNet

2012年,Alex Krizhevsky、Ilya Sutskever在多伦多大学Geoff Hinton的实验室设计出了一个深层的卷积神经网络AlexNet,夺得了2012年ImageNet LSVRC的冠军,且准确率远超第二名(top5错误率为15.3%,第二名为26.2%),引起了很大的轰动。AlexNet可以说是具有历史意义的一个网络结构。

  • 总参数量:60M=6000万,5层卷积+3层全连接

  • 使用了非线性激活函数:ReLU

  • 防止过拟合的方法:Dropout,数据扩充(Data augmentation)

  • 批标准化层的使用(BN)

3.4.3 卷积网络结构的优化

3.4.3.1 常见结构特点

整个过程:AlexNet-->NIN-->(VGG—GoogLeNet)-->ResNet-->DenseNet

  • NIN:引入1 * 1卷积

  • VGG,斩获2014年分类第二(第一是GoogLeNet),定位任务第一。

    • 参数量巨大,140M(M相当于百万) = 1.4亿

    • 19layers

    • VGG 版本

      • VGG16

      • VGG19

GoogleNet,2014年比赛冠军的model,这个model证明了一件事:用更多的卷积,更深的层次可以得到更好的结构。(当然,它并没有证明浅的层次不能达到这样的效果)

  • 500万的参数量

  • 22layers

  • 引入了Inception模块

    • Inception V1

    • Inception V2

    • Inception V3

    • Inception V4

  • 下面我们将针对卷积网络架构常用的一些结构进行详细分析,来探究这些结构带来的好处

3.4.4 VGG

  • 特点:

    • 1、VGG-16的结构非常整洁,深度较AlexNet深得多,里面包含多个conv->conv->max_pool这类的结构,VGG的卷积层都是same的卷积,即卷积过后的输出图像的尺寸与输入是一致的,它的下采样完全是由max pooling来实现。

    • 2、VGG网络后接3个全连接层,filter的个数(卷积后的输出通道数)从64开始,然后没接一个pooling后其成倍的增加,128、512,VGG的注意贡献是使用小尺寸的filter,及有规则的卷积-池化操作。

  • 闪光点:

    • 卷积层使用更小的filter尺寸和间隔

    • 与AlexNet相比,可以看出VGG-Nets的卷积核尺寸还是很小的,比如AlexNet第一层的卷积层用到的卷积核尺寸就是11*11,这是一个很大卷积核了。而反观VGG-Nets,用到的卷积核的尺寸无非都是1×1和3×3的小卷积核,可以替代大的filter尺寸。

3×3卷积核的优点:

  • 多个3×3的卷积层比一个大尺寸filter卷基层有更多的非线性,使得判决函数更加具有判决性

  • 多个3×3的卷积层比一个大尺寸的filter有更少的参数,假设卷基层的输入和输出的特征图大小相同为C,那么三个3×3的卷积层参数个数3×(3×3×C×C)=27CC;一个7×7的卷积层参数为49CC;所以可以把三个3×3的filter看成是一个7×7filter的分解(中间层有非线性的分解)

VGG-16的Keras实现(这里只做展示了解):

def VGG_16():   
    model = Sequential()

    model.add(Conv2D(64,(3,3),strides=(1,1),input_shape=(224,224,3),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(64,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Conv2D(128,(3,2),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(128,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(256,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(Conv2D(512,(3,3),strides=(1,1),padding='same',activation='relu',kernel_initializer='uniform'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Flatten())
    model.add(Dense(4096,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(4096,activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(1000,activation='softmax'))

    return model

3.4.5 ResNet-里程碑式创新

2015年何恺明推出的ResNet在ISLVRC和COCO上横扫所有选手,获得冠军。ResNet在网络结构上做了大创新,而不再是简单的堆积层数,ResNet在卷积神经网络的新思路,绝对是深度学习发展历程上里程碑式的事件。

  • 问题:网络的深度提升不能通过层与层的简单堆叠来实现。由于梯度消失问题,深层网络很难训练。因为梯度反向传播到前面的层,重复相乘可能使梯度无穷小。结果就是,随着网络的层数更深,其性能趋于饱和,甚至开始迅速下降。

  • 特点:

    • 层数非常深,已经超过百层

    • 引入残差单元来解决退化问题

引入:

对神经网络模型添加新的层,充分训练后的模型是否只可能更有效地降低训练误差?理论上,原模型解的空间只是新模型解的空间的子空间。新模型和原模型将同样有效。由于新模型可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。然而在实践中,添加过多的层后训练误差往往不降反升。

3.4.5.1 残差网络-Residual network

  • 通过增加 恒等快捷连接(identity shortcut connection)实现,直接跳过一个或多个层。

    • 可以保证网络的深度在加深,但因为没有学习新的参数,网络不会发生退化的现象。

  • 1、理解:假设我们希望学出的理想映射为f(x),从而作为图5.9上方激活函数的输入。左图虚线框中的部分需要直接拟合出该映射f(x),而右图虚线框中的部分则需要拟合出有关恒等映射的残差映射f(x)−x

    • 1、残差映射在实际中往往更容易优化

    • 2、实验中,当理想映射f(x)极接近于恒等映射时,残差映射也易于捕捉恒等映射的细微波动

      • 右图也是ResNet的基础块,即残差块(residual block)。在残差块中,输入可通过跨层的数据线路更快地向前传播。

  • 2、学习过程:我们只需将图中右图虚线框内上方的加权运算(最上方激活函数下的加权运算符号+)的权重和偏差参数学成0,那么f(x)即为恒等映射。

    • 实际上残差不会为0, 这会使得堆积层在输入特征的基础上学习到新的特征,从而获得更好的性能。

  • 3、原理:将原来需要学习的函数f(x)f(x) 转换成f(x) - xf(x)−x文章认为,相比较于f(x)f(x)的优化要简单,二者的优化难度并不相同,这一想法源自图像处理中的残差向量编码,通过一个reformulation,将一个问题分解成多个尺度之间的残差问题,可以更好的获得优化效果。

1、原理数学公式解释

我们以该图来解释:

第二种情况:证明不经过1x1卷积(直接映射时最好的)

 

 

2、短路连接shortcut的方式

考虑到x的维度与F(X)维度可能不匹配情况,需进行维度匹配。这里论文中采用两种方法解决这一问题(其实是三种,但通过实验发现第三种方法会使performance急剧下降,故不采用):

  • zero_padding:对恒等层进行0填充( 添加0像素的特征图 )的方式将维度补充完整。这种方法不会增加额外的参数

  • projection:在恒等层采用1x1的卷积核来增加维度。这种方法会增加额外的参数

3、bottleneck 实现方式

当研究50层以上的深层网络时,使用了上图所示的Bottleneck网络结构。该结构第一层使用1x1的卷积层来降维,最后一层使用1x1的卷积层来进行升维,从而保持与原来输入同维以便于恒等映射。

4、激活函数的位置

几种情况图示

最终实验结果:

 

实验结果也表明将激活函数移动到残差部分可以提高模型的精度。

3.4.5.4 实验

  • 构建了一个18层和34层的plain网络作为对比,所有层都只作简单的叠加,之后又构建了一个18层和34层的residual网络,在plain网络上加入shortcut,两个网络的参数量和计算量相同

在plain上观测到明显的退化现象,而在ResNet上没有出现退化现象,34层的网络反而比18层的更好,同时ResNet的收敛速度比plain要快。

 

3.4.5.3 完整结构

ResNet比起VGG19这样的网络深很多,但是运算量是少于VGG19等的。

3.4.5.4 代码实现

def Conv2d_BN(x, nb_filter,kernel_size, padding='same',strides=(1,1),name=None):
    if name is not None:
        bn_name = name + '_bn'
        conv_name = name + '_conv'
    else:
        bn_name = None
        conv_name = None

    x = Conv2D(nb_filter,kernel_size,padding=padding,strides=strides,activation='relu',name=conv_name)(x)
    x = BatchNormalization(axis=3,name=bn_name)(x)
    return x

def Inception(x,nb_filter):
    branch1x1 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)

    branch3x3 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
    branch3x3 = Conv2d_BN(branch3x3,nb_filter,(3,3), padding='same',strides=(1,1),name=None)

    branch5x5 = Conv2d_BN(x,nb_filter,(1,1), padding='same',strides=(1,1),name=None)
    branch5x5 = Conv2d_BN(branch5x5,nb_filter,(1,1), padding='same',strides=(1,1),name=None)

    branchpool = MaxPooling2D(pool_size=(3,3),strides=(1,1),padding='same')(x)
    branchpool = Conv2d_BN(branchpool,nb_filter,(1,1),padding='same',strides=(1,1),name=None)

    x = concatenate([branch1x1,branch3x3,branch5x5,branchpool],axis=3)

    return x

def GoogLeNet():
    inpt = Input(shape=(224,224,3))
    #padding = 'same',填充为(步长-1)/2,还可以用ZeroPadding2D((3,3))
    x = Conv2d_BN(inpt,64,(7,7),strides=(2,2),padding='same')
    x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
    x = Conv2d_BN(x,192,(3,3),strides=(1,1),padding='same')
    x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
    x = Inception(x,64)#256
    x = Inception(x,120)#480
    x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
    x = Inception(x,128)#512
    x = Inception(x,128)
    x = Inception(x,128)
    x = Inception(x,132)#528
    x = Inception(x,208)#832
    x = MaxPooling2D(pool_size=(3,3),strides=(2,2),padding='same')(x)
    x = Inception(x,208)
    x = Inception(x,256)#1024
    x = AveragePooling2D(pool_size=(7,7),strides=(7,7),padding='same')(x)
    x = Dropout(0.4)(x)
    x = Dense(1000,activation='relu')(x)
    x = Dense(1000,activation='softmax')(x)
    model = Model(inpt,x,name='inception')
    return model

3.4.6 DenseNet-密集连接卷积网络

DenseNet是在ResNet之后的一个分类网络,连接方式的改变,使其在各大数据集上取得比ResNet更好的效果.。DenseNet的另一大特色是通过特征在channel上的连接来实现特征重用(feature reuse)。这些特点让DenseNet在参数和计算成本更少的情形下实现比ResNet更优的性能,DenseNet也因此斩获CVPR 2017的最佳论文奖。

3.4.6.1 设计理念

我们常用的有 GoogleNet、VGGNet、ResNet 模型,但随着网络层数的加深,网络在训练过程中的前传信号和梯度信号在经过很多层之后可能会逐渐消失。

  • 作者基于这个核心理念设计了一种全新的连接模式。为了最大化网络中所有层之间的信息流,作者将网络中的所有层两两都进行了连接,使得网络中每一层都接受它前面所有层的特征作为输入。

3.4.6.2 网络结构

DenseNet的网络结构主要由DenseBlock和Transition组成

  • 1、DenseBlock中,各个层的特征图大小一致,可以在channel维度上连接

  • 2、DenseBlock中的非线性组合函数采用的是BN+ReLU+3x3 Conv的结构

  • 3、所有DenseBlock中各个层卷积之后均输出K个特征图,或者说采用K个卷积核

    • 在DenseNet称为growth rate,这是一个超参数。一般情况下使用较小的值(比如12)

    • 假定输入层的特征图的channel数为k0,那么l层输入的channel数为k0+k(l-1)

  • 4、DenseBlock内部可以采用bottleneck层来减少计算量,主要是原有的结构中增加1x1 Conv,如图7所示,即BN+ReLU+1x1 Conv+BN+ReLU+3x3 Conv,称为DenseNet-B结构。

  • 5、Transition层包括一个1x1的卷积和2x2的AvgPooling,结构为BN+ReLU+1x1 Conv+2x2 AvgPooling

  • 降低特征图大小、压缩模型

3.4.6.3 DenseNet优点

  • DenseNet的优势主要体现在以下几个方面:

    • 由于密集连接方式,DenseNet提升了梯度的反向传播,使得网络更容易训练。由于每层可以直达最后的误差信号,实现了隐式的“deep supervision”;

    • 参数更小且计算更高效,这有点违反直觉,由于DenseNet是通过concat特征来实现短路连接,实现了特征重用,并且采用较小的growth rate,每个层所独有的特征图是比较小的;

    • 由于特征复用,最后的分类器使用了低级特征。

3.4.6.4 对比

在ImageNet数据集上ResNet vs DenseNet

3.4.7 卷积神经网络学习特征可视化

我们肯定会有疑问真个深度的卷积网络到底在学习什么?可以将网络学习过程中产生的特征图可视化出来,并且对比原图来看看每一层都干了什么。

  • 可视化案例使用的网络

 

 

 

  • layer1,layer2学习到的特征基本是颜色、边缘等低层特征

  • layer3学习到的特征,一些纹理特征,如网格纹理

  • layer4学习到的特征会稍微复杂些,比如狗的头部形状

  • layer5学习到的是完整一些的,比如关键性的区分特征

3.4.8 总结

  • 掌握LeNet-5 结构计算

  • 了解卷积常见网络结构

  • 掌握1x1卷积结构作用

  • 掌握Inception结构作用

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值