经典的卷积网络架构(二)——GoogLeNet [inception v1] 详解

GoogLeNet出自论文Going Deeper With Convolutions

如有错误,欢迎指正!

(未完待续)

 

目录

论文阅读

补充知识点:1*1卷积的作用

网络结构分析

参考博文

参考代码

附录

网络结构图

网络具体参数


引言:整理经典的卷积网络架构


论文阅读

GoogLeNet的最大特点是使用了Inception模块

目的

设计一种具有局部拓扑结构的网络,即对输入图像并行地执行多个卷积运算和池化操作

问题

1、在对图像进行操作的时候,图像中包含目标信息的部分具有很大的差异性,可大可小。也即,目标在整个图像中所占的比例或者说区域是不一样的。由于信息位置差异大,难以确定合适的卷积核的大小

2、比较深的网络容易造成过拟合,很难将梯度更新传递给整个网络

3、网络的‘深’有两层含义:一是高水平的组织方式(本文的构建Inception模块);二是以直接的方式来增加网络的深度。

那么后一种简单地堆叠较大的卷积层很消耗计算资源

解决方案

设计Inception模块。

主要的设计思路是在一个卷积网络中寻找一个局部最优的稀疏结构,该结构被可获得的密集组件覆盖或者近似表达。

在3*3和5*5的卷积以及最大池化层之前加1*1的卷积层,将所有的子层输出级联起来并送入下一个Inception模块。

这种网中网的结构增加了神经网络的表现力。

说明:网络越往后,特征就越抽象,每个特征涉及到的感受野也越大,所以随着网络层数的增加,3*3和5*5的卷积核比例会增加。采用不同大小的卷积核意味着有不同大小的感受野,大尺寸的卷积核意味着较大的感受野也意味着更多的参数,用连接的小网络来代替单个的大网络,在保持感受野的同时又减少了参数量。

 

补充知识点:1*1卷积的作用

1、控制特征图的深度

可以用来调节通道数,对不同通道数的像素进行线性组合,然后,进行非线性操作,完成升维和降维的功能

2、减少参数

降维其实也是减少参数,因为特征图少了,参数也就减少了。

相当于在特征图的通道数上进行卷积,压缩了特征图,二次提取特征,使得新特征的表达效果更好

3、实现了通道的信息组合,并增加了非线性特征

在保持feature map尺度不变(不损失分辨率)的前提下,大幅度增加了非线性特征(主要是利用后面接的非线性激活函数实现)。

 

网络结构分析

(如附录的网络结构图所示)有9个线性堆叠的Inception模块, 共22层(包括池化层有27层),在最后一个Inception处,使用全局平均池化来代替全连接层(为方便对输出灵活调整,实际仍然加了全连接层)

主要还是CNN的几个基本模块的组合:卷积层、池化层、全连接层,此外,添加了Inception模块

为了避免梯度消失的的问题,添加了2个辅助分类器(softmax),将中间某层的输出用作分类,以较小的权重(0.3)加到最终的分类结果中去(实际测试的过程不包含这两个辅助分类器)

0、INPUT——输入层

输出的图像尺寸大小为224*224*3

均进行零均值化的预处理操作

1、C1——卷积层

卷积核 7*7*64,padding=3,stride=2

卷积后 112*112*64 ((224-7+3*2)/2+1=112)

送入RuLU激活函数

max pooling 3*3,stride=2

池化后 56*56*64 ((112-3+1)/2+1=56)

2、C2——卷积层

卷积核 3*3*192,padding=1,stride=1

卷积后 56*56*192 ((56-3+1*2)/1+1=56)

送入RuLU激活函数

max pooling 3*3,stride=2

池化后 28*28*192 ((56-3+1)/2+1=28)

3a、Inception 3a层

经过1*1*64的卷积,得28*28*64;送入ReLU激活函数。

经过1*1*96的卷积,得28*28*96;送入ReLU激活函数;经过3*3*128的卷积(padding=1),得28*28*128。

经过1*1*16的卷积,得28*28*16;送入ReLU激活函数;经过5*5*32的卷积(padding=2),得28*28*32。

经过3*3的max pooling (padding=1),得28*28*192;经过1*1*32的卷积,得28*28*32。

最后将四个分支合并:64+128+32+32=256

得到28*28*256

3b、Inception 3b层

4a、4b、4c、4d、4e、Inception 层

5a、5b、Inception 层

 

网络结构

基于tensorflow

# 模型架构文件 googlenet.py

'''
googlenet的网络结构
sstart at 2019.3.19
'''

import tensorflow as tf
import tensorflow.contrib.layers as layers
import tensorflow.contrib.framework as ops


# 定义Inception层
def get_inception_layer(inputs, conv11_size, conv33_11_size, conv33_size, conv55_11_size, conv55_size, pool_size):
    with tf.variable_scope("conv_1*1"):
        conv11 = layers.conv2d(inputs, conv11_size, [1, 1])
    with tf.variable_scope("conv_3*3"):
        conv33_11 = layers.conv2d(inputs, conv33_11_size, [1, 1])
        conv33 = layers.conv2d(conv33_11, conv33_size, [3, 3])
    with tf.variable_scope("conv_5*5"):
        conv55_11 = layers.conv2d(inputs, conv55_11_size, [1, 1])
        conv55 = layers.conv2d(conv55_11, conv55_size, [5, 5])
    with tf.variable_scope("pool"):
        pool = layers.max_pool2d(inputs, [3, 3], stride=1)
        pool11 = layers.conv2d(pool, pool_size, [1, 1])
    return tf.concat([conv11, conv33, conv55, pool11], 3)


# 定义网络中的辅助分类器(softmax)
def aux_logit_layer(inputs, n_classes, is_training):
    with tf.variable_scope('ave_pool'):
        ave_pool1 = layers.avg_pool2d(inputs, [5, 5], stride=3)
    with tf.variable_scope("conv11"):
        conv11 = layers.conv2d(ave_pool1, 128, [1, 1])
    with tf.variable_scope("flatten"):
        flat = tf.reshape(conv11, [-1, 2048])
    with tf.variable_scope("fc1"):  # activation_fn=None激活函数默认为relu函数
        fc = layers.fully_connected(flat, 2048, activation_fn=None)
    with tf.variable_scope("drop"):
        drop = layers.dropout(fc, 0.3, is_training=is_training)
    with tf.variable_scope("linear"):
        linear = layers.fully_connected(drop, n_classes, activation_fn=None)
    with tf.variable_scope("soft"):
        soft = tf.nn.softmax(linear)
    return soft


def googlenet(inputs, rate=0.4, n_classes=10):
    with tf.name_scope('googlenet'):
        conv1 = tf.nn.relu(layers.conv2d(inputs, 64, [7, 7], stride=2, scope='conv1'))
        pool1 = layers.max_pool2d(conv1, [3, 3], scope='pool1')
        conv2 = tf.nn.relu(layers.conv2d(pool1, 192, [3, 3], stride=1, scope='conv2'))
        pool2 = layers.max_pool2d(conv2, [3, 3], stride='pool2')

        with tf.variable_scope('Inception_3a'):
            incpt3a = get_inception_layer(pool2, 64, 96, 128, 16, 32, 32)
        with tf.variable_scope("Inception_3b"):
            incpt3b = get_inception_layer(incpt3a, 128, 128, 192, 96, 64)
        pool3 = layers.max_pool2d(incpt3b, [3, 3], scope='pool3')
        with tf.variable_scope("Inception_4a"):
            incpt4a = get_inception_layer(pool3, 192, 96, 208, 16, 48, 64)
        with tf.variable_scope("aux_logit_layer1"):
            aux1 = aux_logit_layer(incpt4a, n_classes, is_training=True)
        with tf.variable_scope("Inception_4b"):
            incpt4b = get_inception_layer(incpt4a, 160, 112, 224, 24, 64, 64)
        with tf.variable_scope("Inception_4c"):
            incpt4c = get_inception_layer(incpt4b, 128, 128, 256, 24, 64, 64)
        with tf.variable_scope("Inception_4d"):
            incpt4d = get_inception_layer(incpt4c, 112, 144, 288, 32, 64, 64)
        with tf.variable_scope("aux_logit_layer2"):
            aux2 = aux_logit_layer(incpt4d, n_classes, is_training=True)
        pool4 = layers.max_pool2d(incpt4d, [3, 3], scope='pool4')
        with tf.variable_scope("Inception_5a"):
            incept5a = get_inception_layer(pool4, 256, 160, 320, 32, 128, 128)
        with tf.variable_scope("Inception_5b"):
            incept5b = get_inception_layer(incept5a, 384, 192, 384, 48, 128, 128)
        pool5 = layers.avg_pool2d(incept5b, [7, 7], stride=1, scope='pool5')
        reshape = tf.reshape(pool5, [-1, 2048])
        drop = layers.dropout(reshape, rate, is_training=True)
        linear = layers.fully_connected(drop, n_classes, activation_fn=None, scope='linear')
        # soft = tf.nn.softmax(linear)
    return linear, aux1, aux2


def losses(logits, labels):
    with tf.variable_scope('loss') as scope:
        cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=logits, labels=labels,
                                                                       name='xentropy_per_example')
        loss = tf.reduce_mean(cross_entropy, name='loss')
        tf.summary.scalar(scope.name + '/loss', loss)
    return loss


def trainning(loss, learning_rate):
    with tf.name_scope('optimizer'):
        optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate)
        global_step = tf.Variable(0, name='global_step', trainable=False)
        train_op = optimizer.minimize(loss, global_step=global_step)
    return train_op


def evaluation(logits, labels):
    with tf.variable_scope('accuracy') as scope:
        correct = tf.nn.in_top_k(logits, labels, 1)
        accuracy = tf.reduce_mean(tf.cast(correct, tf.float16))
        tf.summary.scalar(scope.name + '/accuracy', accuracy)

 

# 模型训练文件 train.py

# 数据预处理文件 prework.py 

 

 

参考博文

1、大话CNN经典模型:GoogLeNet(从Inception v1到v4的演进)

2、一文概览Inception家族的「奋斗史」

还有几篇参考文献忘记链接了,如有侵权,请与我联系!

参考代码

1、da-steve101/googlenet

2、PanJinquan/tensorflow_models_nets

 

附录

网络结构图


网络具体参数

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

故沉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值