您的位置:首页 > 理论基础 > 计算机网络

经典卷积神经网络(4)--InceptionNet-V3卷积网络模型

2019-06-05 15:30 851 查看
版权声明:所有内容均是作者在学习过程中根据查阅的相关资料(包括不限于学术论文、相关书籍、网络公开资料)结合自己的学习经验整理所得,如有疑问请联系zumeru@163.com https://blog.csdn.net/weixin_43002202/article/details/90902901

InceptionV1

GoogLeNet是一个22层的CNN,它以6.7%的错误率赢得了2014年度ILSVRC的冠军。这是第一个跟传统方法,也就是卷积层与池化层简单叠加以形成序列结构的方法不同的一种CNN的新架构。

按传统方法来增加模型深度,存在一些缺陷:

1.网络模型产生巨大参数,容易导致过拟合。

2.网络规模扩大会极大增加计算量,消耗更多计算机的资源。

InceptionV2

1.Inception V2学习了VGGNet,用两个3´3的卷积代替5´5的大卷积(用以降低参数量,减少计算量)

2.提出了著名的Batch Normalization(以下简称BN)方法。

BN是一个非常有效的正则化方法,可以让大型卷积网络的训练速度加快很多倍,同时收敛后的分类准确率也可以得到大幅提高。BN在用于神经网络某层时,会对每一个mini-batch数据的内部进行标准化(normalization)处理,使输出规范化到N(0,1)的正态分布,减少了Internal Covariate Shift(内部神经元分布的改变)。

BN的论文指出,传统的深度神经网络在训练时,每一层的输入的分布都在变化,导致训练变得困难,我们只能使用一个很小的学习速率解决这个问题。而对每一层使用BN之后,我们就可以有效地解决这个问题,学习速率可以增大很多倍,达到之前的准确率所需要的迭代次数只有1/14,训练时间大大缩短。而达到之前的准确率后,可以继续训练,并最终取得远超于Inception V1模型的性能——top-5错误率4.8%,已经优于人眼水平。

InceptionV3

InceptionV3对InceptionV2主要进行了两方面的改进

1.一方面,引入了Factorization into small convolutions的思想(分解大尺寸卷积为多个小卷积乃至一维卷积),将一个较大的二维卷积拆成两个较小的一维卷积,比如将7´7卷积拆成1´7卷积和7´1卷积,或者将3´3卷积拆成1´3卷积和3´1卷积,如下图所示。一方面节约了大量参数,加速运算并减轻了过拟合(比将7´7卷积拆成1´7卷积和7´1卷积,比拆成3个3´3卷积更节约参数),同时增加了一层非线性扩展模型表达能力。论文中指出,这种非对称的卷积结构拆分,其结果比对称地拆为几个相同的小卷积核效果更明显,可以处理更多、更丰富的空间特征,增加特征多样性。

于是,任意nxn的卷积都可以通过1xn卷积后接nx1卷积来替代。实际上,作者发现在网络的前期使用这种分解效果并不好,在中度大小的feature map上使用效果才会更好。(对于mxm大小的feature map,建议m在12到20之间)。

2.另一方面,Inception V3优化了Inception Module的结构,现在Inception Module有35´35(书上图8-14a)、17´17(书上图8-14b)和8´8(书上图8-14c)三种不同结构。这些Inception Module只在网络的后部出现,前部还是普通的卷积层。并且Inception V3除了在Inception Module中使用分支,还在分支中使用了分支(8´8的结构中),可以说是Network In Network In Network。

InceptionV3的一个module

tensor中的slim库

在阅读用tensorflow实现的深度学习网络结构的源码时,经常会看到使用TF中封装的slim高级库,看起来(实际上也是)比直接调用TF的API简洁好多。 TF-Slim是tensorflow中定义、训练和评估复杂模型的轻量级库。tf-slim中的组件可以轻易地和原生tensorflow框架。

TF-slim主要由下面几个组成:

[code]arg_scope
data
evluation
layers
learning
losses
metrics
nets
queues
regularizers
variables

tf.nn.conv2d和tf.contrib.slim.conv2d的区别

tf.nn.conv2d()搭建一个卷积时,

  1. 创建权重、偏置变量
  2. 将来自上一层的数据和权值进行卷积
  3. 在卷积结果上加上偏置
  4. 应用激活函数
[code]with tf.variable_scope("conv1_1"):
conv1_weights = tf.get_variable("weight", [5, 5, 1, 32],
initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable("bias", [32], initializer=tf.constant_initializer(0.0))

conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding="SAME")
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))

为了缓解重复这些代码,Slim库在更抽象的神经网络层的层面上提供了大量方便使用的操作符。tf.contrib.slim.conv2d()是上面代码封装后的结果,

tf.contrib.slim.conv2d (inputs, num_outputs,[卷积核个数] kernel_size,[卷积核的高度,卷积核的宽度] stride=1, padding="SAME" scope[变量空间名])

使用arg_scope后可以避免在每个slim.conv2d中添加重复的参数(如straide=1,padding="SAME",weight_initializer=xxx等)

[code]import tensorflow as tf
import tensorflow.contrib.slim as slim

#用slim的srg_scope()函数设置一些会用到卷积或池化函数的默认参数,
#这包括stride=1和padding="SAME"
with slim.arg_scope([slim.conv2d,slim.max_pool2d,slim.avg_pool2d],stride=1,
padding="SAME"):

#在这里为InceptionModule创建一个统一的变量命名空间,模块里面有多个路径,
#每一条路径都会接收模块之前网络节点的输出,这里用last_net统一代表这个输出
with tf.variable_scope("Module"):

#使用变量空间的名字标识模块的路径,这类似于"BRANCH_n"的形式,
#例如BRANCH_1表示这个模块里的第二条路径
with tf.variable_scope("BRANCH_0"):
branch_0 = slim.conv2d(last_net,320,[1,1],scope="Conv2d_0a_1x1")

with tf.variable_scope("BRANCH_1"):
branch_1 = slim.conv2d(last_net,384,[1,1],scope="Conv2d_1a_1x1")
#concat()函数实现了拼接的功能,函数原型为concat(values,axis,name)
#第一个参数用于指定拼接的维度信息,对于InceptionModule,值一般为3,
#表示在第三个维度上进行拼接(串联),第二个参数是用于拼接的两个结果
branch_1 = tf.concat(3,[
slim.conv2d(branch_1, 384, [1,3], scope="Conv2d_1b_1x3"),
slim.conv2d(branch_1, 384, [3,1], scope="Conv2d_1c_3x1")])

with tf.variable_scope("BRANCH_2"):
branch_2 = slim.conv2d(last_net,448,[1,1],scope="Conv2d_2a_1x1")
branch_2 = slim.conv2d(branch_2, 384, [3,3], scope="Conv2d_2b_3x3")
branch_2 = tf.concat(3,[
slim.conv2d(branch_2, 384, [1,3], scope="Conv2d_2c_1x3"),
slim.conv2d(branch_2, 384, [3,1], scope="Conv2d_2d_3x1")])

with tf.variable_scope("BRANCH_3"):
branch_3 = slim.avg_pool2d(last_net, [3,3], scope="AvgPool_3a_3x3")
branch_2 = slim.conv2d(branch_3, 192, [1, 1], scope="Conv2d_3a_1x1")

#最后用concat()函数将InceptionModule每一条路径的结果进行拼接得到最终结果
Module_output = tf.concat(3,[branch_0,branch_1,branch_2,branch_3])

tf.concat(values,concat_dim,name)

concat_dim表示你在哪个维度上进行连接,他是整数,从0开始计数,0表示第一个维度,1表示第二个维度...... values是一个列表。列表里面是要连接的矩阵或者数组。

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐