【keras】GoogleNet 网络结构及其实现

深度学习模型常常通过增加模型的深度或者宽度来获得更高的性能。本文将就深度学习常见的网络结构进行介绍。

GoogLeNet是2014年Christian Szegedy提出的一种全新的深度学习结构,在这之前的AlexNet、VGG等结构都是通过增大网络的深度来获得更好的训练效果,但层数的增加会带来很多负作用,比如overfit、梯度消失、梯度爆炸等。

在介绍GoogLeNet之前,先介绍一下两种卷积模型,即 Inception 模型和 Residual (残差)模型是卷积神经网络中对卷积升级的两个操作。下面主要讲一下Inception模型。

【keras】GoogleNet 网络结构及其实现_第1张图片

上面的 Inception 模型的Keras实现代码如下所示。 

from keras.layers import Conv2D, MaxPooling2D, Input

input_img = Input(shape=(256, 256, 3))

tower_1 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_1 = Conv2D(64, (3, 3), padding='same', activation='relu')(tower_1)

tower_2 = Conv2D(64, (1, 1), padding='same', activation='relu')(input_img)
tower_2 = Conv2D(64, (5, 5), padding='same', activation='relu')(tower_2)

tower_3 = MaxPooling2D((3, 3), strides=(1, 1), padding='same')(input_img)
tower_3 = Conv2D(64, (1, 1), padding='same', activation='relu')(tower_3)

# concatenate是核心,其实就是连接在一起,比如两列向量和两列向量,连接成四列向量即可。
output = keras.layers.concatenate([tower_1, tower_2, tower_3], axis=1)

一般情况下,如果想降低特征图的大小,可以有如下两种方式:

先池化再作Inception卷积,或者先作Inception卷积再作池化。但是方法一:先作pooling(池化)会导致特征表示遇到瓶颈(特征缺失),方法二:正常缩小,但计算量很大。为了同时保持特征表示且降低计算量,将网络结构改为下图,使用两个并行化的模块来降低计算量(卷积、池化并行执行,再进行合并)。

GoogleNet 中的 Inception 模型如下所示:

【keras】GoogleNet 网络结构及其实现_第2张图片

深度:层数更深,文章采用了22层,为了避免上述提到的梯度消失问题,googlenet巧妙的在不同深度处增加了两个loss来保证梯度回传消失的现象。

宽度:增加了多种核 1x1,3x3,5x5,还有直接max pooling的,但是如果简单的将这些应用到feature map上的话,concat起来的feature map厚度将会很大,所以在googlenet中为了避免这一现象提出的inception具有如下结构,在3x3前,5x5前,max pooling后分别加上了1x1的卷积核起到了降低feature map厚度的作用。仅仅一层block就包含1*1卷积,3*3卷积,5*5卷积,3*3池化。这样,网络中每一层都能学习到“稀疏”或者“不稀疏”的特征。

实际上采用什么样的Inception Block最好,需要根据你的输出需要来定。比如要输出35*35尺寸的特征图,你不用费心调了,下面这个Inception Block最好:

【keras】GoogleNet 网络结构及其实现_第3张图片

 如果要输出17*17尺寸的特征图?没关系,这个Inception Block最好:

【keras】GoogleNet 网络结构及其实现_第4张图片

注意到每组卷积之前都有1*1卷积,之前我们说过,1*1的卷积是为了降低输入特征图个数,不至于到最后特征图泛滥。于是,像拼积木一样,把上述Blocks拼到Inception V4 中就可以了:

【keras】GoogleNet 网络结构及其实现_第5张图片

其中,Inception-A的block和Inception-B的block展开,正是上一张和上上一张图片的架构。可见,Inception V4的Block更像是模块化的拼接。

下面给出 GoogLeNet 的网络结构:

【keras】GoogleNet 网络结构及其实现_第6张图片

 网络的参数如下表所示。

【keras】GoogleNet 网络结构及其实现_第7张图片

 利用Keras实现代码如下所示。

#coding=utf-8
from keras.models import Model
from keras.layers import Input,Dense,Dropout,BatchNormalization,Conv2D,MaxPooling2D,AveragePooling2D,concatenate
from keras.layers.convolutional import Conv2D,MaxPooling2D,AveragePooling2D
import numpy as np
seed = 7
np.random.seed(seed)

# 卷积层和标准层组成的block
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

# Inception Block
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
 
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')
model.compile(loss='categorical_crossentropy',optimizer='sgd',metrics=['accuracy'])
model.summary()

本文参考自:不怕过拟合、keras搬砖系列-细读GoogleNet、大话CNN经典模型:GoogLeNet(从Inception v1到v4的演进)

你可能感兴趣的:(强化学习与人工智能)