您的位置:

InceptionV1网络架构

一、历史背景

深度学习自从2012年AlexNet问世以来,神经网络的规模和复杂度越来越高,而且高性能显卡的出现使得深度神经网络(DNN)被广泛使用。但是,DNN本身的特性也在这一过程中表现出来,如网络中间层之间的映射关系、全连接层带来的计算负担等问题导致了网络的训练的低效性和精度问题。

在这个背景下,Google团队在2014年推出了InceptionV1网络架构,该网络的主要目的是解决深度神经网络模型训练中的低效性问题和精度问题。

二、网络架构

InceptionV1架构主要由多个包含不同卷积和池化核的并行卷积层组成。其中,每个卷积层都作用于输入的相同维度且相加作为该层的输出。这种方式的独特优势在于可以摆脱神经网络不同层之间精度和效率权衡的限制。

InceptionV1网络的架构可以简化为以下结构:

Layer         Output Shape     Kernel Size/Stride
================================================
Input         (224, 224, 3)    -  
Conv1         (112, 112, 64)   3x3/2  
MaxPool1      (56, 56, 64)     3x3/2 
Conv2         (28, 28, 192)    3x3/1  
MaxPool2      (14, 14, 192)    3x3/2  
Inception3a   (14, 14, 256)    -  
Inception3b   (14, 14, 480)    -  
MaxPool3      (7, 7, 480)      3x3/2  
Inception4a   (7, 7, 512)      -  
Inception4b   (7, 7, 512)      -  
Inception4c   (7, 7, 512)      -  
Inception4d   (7, 7, 528)      -  
Inception4e   (7, 7, 832)      -  
MaxPool4      (3, 3, 832)      3x3/2  
Inception5a   (3, 3, 832)      -  
Inception5b   (3, 3, 1024)     -  
AvgPool       (1, 1, 1024)     5x5/1  
Dropout       (1, 1, 1024)     -  
Output        (1, 1, 1000)     -  

三、Inception模块

Inception模块是InceptionV1的核心模块,它是由几种局部网络混合而成,每种局部网络都是由卷积、池化、卷积和卷积组成的。该模块结构如下所示:

 Layer         Output Shape     Kernel Size/Stride
================================================
Input         (28, 28, 192)    -  
Conv1x1       (28,28,64)       1x1/1  
Conv3x3       (28,28,96)       3x3/1  
Conv5x5       (28,28,16)       5x5/1  
MaxPool3      (28,28,32)       3x3/1  
concat        (28, 28, 192)    -  

Inception模块串联起来形成了InceptionV1的整个网络。这种混合的方式增加了网络的宽度和深度,且使用了稀疏卷积计算,使得网络更加有效和高效。

四、训练方法和效果

为了训练InceptionV1网络,Google团队在ImageNet数据集上训练了3M张图片,参数数目达到了500万。该网络在ImageNet数据集上实现了top-5准确率为89.9%的结果,这个结果让该网络成为2014年ImageNet比赛的冠军。

五、代码示例

InceptionV1的代码示例可以在TensorFlow框架中找到,以下为示例代码:

import tensorflow as tf

def inception_v1(inputs, num_classes=1000, is_training=True, dropout_keep_prob=0.4):
    '''
    inception v1网络
    :param inputs: 输入图像数据,形状[batch_size, height, width, channels]
    :param num_classes: 分类数目
    :param is_training: 是否为训练模式
    :param dropout_keep_prob: dropout保留比例
    :return: 最后一层的logits输出,shape=[batch_size, num_classes]
    '''
    def inception_module(inputs, filters):
        '''
        inception module
        :param inputs:输入 
        :param filters: 卷积核数目
        :return: 输出
        '''
        # 1x1卷积网络
        conv1x1 = tf.layers.conv2d(inputs=inputs,
                                   filters=filters[0],
                                   kernel_size=1,
                                   strides=1,
                                   activation=tf.nn.relu,
                                   padding='same')

        # 3x3卷积网络
        conv3x3_reduce = tf.layers.conv2d(inputs=inputs,
                                          filters=filters[1],
                                          kernel_size=1,
                                          strides=1,
                                          activation=tf.nn.relu,
                                          padding='same')
        conv3x3 = tf.layers.conv2d(inputs=conv3x3_reduce,
                                   filters=filters[2],
                                   kernel_size=3,
                                   strides=1,
                                   activation=tf.nn.relu,
                                   padding='same')

   
        # 5x5卷积网络
        conv5x5_reduce = tf.layers.conv2d(inputs=inputs,
                                          filters=filters[3],
                                          kernel_size=1,
                                          strides=1,
                                          activation=tf.nn.relu,
                                          padding='same')
        conv5x5 = tf.layers.conv2d(inputs=conv5x5_reduce,
                                   filters=filters[4],
                                   kernel_size=5,
                                   strides=1,
                                   activation=tf.nn.relu,
                                   padding='same')

        # 3x3最大池化网络
        max_pool = tf.layers.max_pooling2d(inputs=inputs,
                                           pool_size=3,
                                           strides=1,
                                           padding='same')
        max_pool_project = tf.layers.conv2d(inputs=max_pool,
                                            filters=filters[5],
                                            kernel_size=1,
                                            strides=1,
                                            activation=tf.nn.relu,
                                            padding='same')

        # 将所有的分支在通道维度上连接起来
        outputs = tf.concat([conv1x1, conv3x3, conv5x5, max_pool_project], axis=-1)

        return outputs

    # 开始搭建网络
    conv1 = tf.layers.conv2d(inputs, 64, 7, strides=2, padding='same', activation=tf.nn.relu)
    max_pool1 = tf.layers.max_pooling2d(conv1, 3, 2, padding='same')
    conv2_reduce = tf.layers.conv2d(max_pool1, 64, 1, strides=1, padding='same', activation=tf.nn.relu)
    conv2 = tf.layers.conv2d(conv2_reduce, 192, 3, strides=1, padding='same', activation=tf.nn.relu)
    max_pool2 = tf.layers.max_pooling2d(conv2, 3, 2, padding='same')

    inception3a = inception_module(max_pool2, [64, 96, 128, 16, 32, 32])
    inception3b = inception_module(inception3a, [128, 128, 192, 32, 96, 64])
    max_pool3 = tf.layers.max_pooling2d(inception3b, 3, 2, padding='same')

    inception4a = inception_module(max_pool3, [192, 96, 208, 16, 48, 64])
    inception4b = inception_module(inception4a, [160, 112, 224, 24, 64, 64])
    inception4c = inception_module(inception4b, [128, 128, 256, 24, 64, 64])
    inception4d = inception_module(inception4c, [112, 144, 288, 32, 64, 64])
    inception4e = inception_module(inception4d, [256, 160, 320, 32, 128, 128])
    max_pool4 = tf.layers.max_pooling2d(inception4e, 3, 2, padding='same')

    inception5a = inception_module(max_pool4, [256, 160, 320, 32, 128, 128])
    inception5b = inception_module(inception5a, [384, 192, 384, 48, 128, 128])
    # 利用平均池化进行预测
    avg_pool = tf.layers.average_pooling2d(inception5b, 7, 1)
    flatten = tf.layers.flatten(avg_pool)
    # 对最后一层进行dropout降低过拟合风险
    dropout = tf.layers.dropout(flatten, dropout_keep_prob, training=is_training)
    logits = tf.layers.dense(dropout, num_classes)
    
    return logits