经典卷积网络进阶--GoolgleNet详解
一.GoolgleNet概述
GoogLeNet是google推出的基于Inception模塊的深度神經網絡模型,在2014年的ImageNet競賽中奪得了冠軍。其性能比vgg網絡更好。通常來說提高網路性能最直接的方法就是增加網絡結構的深度和寬度,但這種方法往往伴隨著參數計算量的增加,而且更容易出現過擬合現象。GoogLeNet提出將全連接層甚至一般的卷積都轉化為稀疏連接。不同于vgg網絡,提出了inception模塊結構,這個創新點使得googlenet可以擁有更深,更寬的網絡結構。
什么是Inception
Inception就是把多個卷積或池化操作,放在一起組裝成一個網絡模塊,設計神經網絡時以模塊為單位去組裝整個網絡結構。inception結構的主要貢獻有兩個:一是使用1x1的卷積來進行升降維;二是在多個尺寸上同時進行卷積再聚合。
不同大小的卷積核意味著不同大小的局部感受野,將不同卷積核的輸出進行拼接意味著不同特征信息的融合。為了使各個卷積層輸出的特征直接進行拼接,需要這些特征的輸出具有相同的維度,因此設置卷積層相關參數時,步長固定為1,當卷積核大小分別為1*1,3*3,5*5時,像素填充padding分別取0,1,2。池化層的加入會是網絡性能更好;為了減少大小為3*3和5*5的卷積核直接卷積帶來的參數過大的問題,可采用1*1的卷積核先進性降維。
模塊如下圖所示
1x1卷積的作用
作用1:在相同尺寸的感受野中疊加更多的卷積,能提取到更豐富的特征(在相同的感受野范圍能提取更強的非線性)。
作用2:使用1x1卷積進行降維,降低了計算復雜度。上圖中間3x3卷積和5x5卷積前的1x1卷積都起到了這個作用。當某個卷積層輸入的特征數較多,對這個輸入進行卷積運算將產生巨大的計算量;如果對輸入先進行降維,減少特征數后再做卷積計算量就會顯著減少。圖1是優化前后兩種方案的乘法次數比較,同樣是輸入一組有192個特征、32x32大小,輸出256組特征的數據,圖1第一張圖直接用3x3卷積實現,需要192x256x3x3x32x32=452984832次乘法;圖1第二張圖先用1x1的卷積降到96個特征,再用3x3卷積恢復出256組特征,需要192x96x1x1x32x32+96x256x3x3x32x32=245366784次乘法,使用1x1卷積降維的方法節省了一半的計算量。有人會問,用1x1卷積降到96個特征后特征數不就減少了么,會影響最后訓練的效果么?答案是否定的,只要最后輸出的特征數不變(256組),中間的降維類似于壓縮的效果,并不影響最終訓練的結果
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?圖1
GoogLeNet的整體結構
GoogLeNet網絡由輸入層,輸出層,卷積層和大量Inception層組成,如下圖:
二.GoogLeNet實現MNIST分類
基于keras框架
代碼:
#從keras.model中導入model模塊,為函數api搭建網絡做準備 from keras.models import Model from keras.layers import Flatten,Dense,Dropout,BatchNormalization,Input,ZeroPadding2D,concatenate from keras.layers.convolutional import Conv2D, MaxPooling2D, AveragePooling2D from keras import regularizers #正則化 from keras.optimizers import RMSprop #優化選擇器 from keras.layers import AveragePooling2D from keras.datasets import mnist from keras.utils import np_utils #數據處理 (X_train,Y_train),(X_test,Y_test)=mnist.load_data() X_test1=X_test Y_test1=Y_test X_train=X_train.reshape(-1,28,28,1).astype("float32")/255.0 X_test=X_test.reshape(-1,28,28,1).astype("float32")/255.0 Y_train=np_utils.to_categorical(Y_train,10) Y_test=np_utils.to_categorical(Y_test,10) print(X_train.shape) print(Y_train.shape) print(X_train.shape)DATA_FORMAT="channels_last" #通道在前或在后的方式 #定義COV2D_lrn()函數,為方便建立googlenet網絡 #這是個卷積層與局部反應歸一化聯合的函數 def cov2d_lrn(x,filters,kernel_size,strides=1,padding="same",activation="relu",use_bias=True,kernel_initializer='glorot_uniform', bias_initializer='zeros',kernel_regularizer=None,biass_regularizer=None,lrn_norm=True,weight_decay=0.0005):#處理權重核偏置的正則化if weight_decay:kernel_regularizer=regularizers.l2(weight_decay)biass_regularizer=regularizers.l2(weight_decay)else:kernel_regularizer=Nonebiass_regularizer=None#搭建卷積層x=Conv2D(filters=filters,kernel_size=kernel_size,strides=strides,padding=padding,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(x)if lrn_norm: #是否需要添加lrn層進行歸一化x=BatchNormalization()(x)return x#建立inception函數 def inception_model(x,param,concat_axis,padding="same",active="relu",use_bias=True,kernel_initializer='glorot_uniform',bias_initializer='zeros',kernel_regularizer=None,biass_regularizer=None,lrn=True,weight_decay=None):#param是inception里面各個卷積層的核的個數的列表,比如[(2,),(3,4),(8,9)],類似(branch1,branch2,branch3,branch4)=param(branch1,branch2,branch3,branch4)=param #各個路徑的各層卷積核的個數由用戶決定的,核的大小,步長都是固定的if weight_decay: #處理正則化kernel_regularizer=regularizers.l2(weight_decay)biass_regularizer=regularizers.l2(weight_decay)else:kernel_regularizer=Nonebiass_regularizer=None#inception里第一條路徑path1=Conv2D(filters=branch1[0],kernel_size=(1,1),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer, #權重的正則化bias_regularizer=biass_regularizer#偏置的正則化)(x)#第二條路徑path2=Conv2D(filters=branch2[0],kernel_size=(1,1),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(x)path2=Conv2D(filters=branch2[1],kernel_size=(3,3),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(path2)#第三條路徑path3=Conv2D(filters=branch3[0],kernel_size=(1,1),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(x)path3=Conv2D(filters=branch3[1],kernel_size=(5,5),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(path3)#第四條路徑path4=MaxPooling2D(pool_size=(3,3),strides=1,padding=padding,data_format=DATA_FORMAT)(x)path4=Conv2D(filters=branch4[0],kernel_size=(1,1),strides=1,padding=padding,activation=active,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=biass_regularizer)(path4)#接下來返回所有路徑的拼接,concat_axis是拼接的維度#path=Concatenate(axis=concat_axis)([path1,path2,path3,path4])path=concatenate([path1, path2, path3, path4], axis=concat_axis)return path#搭建Googlenet網絡 def googlenet():CONCAT_AXIS =3x_input = Input((28, 28, 1)) # 輸入數據形狀28*28*1#x_input=Input(shape=(28,28,1)) #輸入數據形狀28*28*1x_input1=ZeroPadding2D((3,3))(x_input) #對輸入數據進行補0填充x=cov2d_lrn(x_input1,64,(7,7),2,padding="same",lrn_norm=False)#搭建池化層x=MaxPooling2D(pool_size=(2,2),strides=2,padding="same")(x)#搭建BN層,局部響應歸一化x=BatchNormalization()(x)x=cov2d_lrn(x,64,(1,1),1,padding="same",lrn_norm=False)x=cov2d_lrn(x,192,(3,3),1,padding="same",lrn_norm=True)x=MaxPooling2D(pool_size=(2,2),strides=2,padding="same")(x)#搭建inception部分#搭建inception3a層x=inception_model(x,param=[(64,),(96,128),(16,32),(32,)],concat_axis=CONCAT_AXIS )#搭建inception3b層x=inception_model(x,param=[(128,),(128,192),(32,96),(64,)],concat_axis=CONCAT_AXIS )#搭建池化層x=MaxPooling2D(pool_size=(2,2),strides=2,padding="same")(x)#搭建inception4a層x=inception_model(x,param=[(192,),(96,208),(16,48),(64,)],concat_axis=CONCAT_AXIS )#搭建inception4bcx=inception_model(x,param=[(160,),(112,224),(24,64),(64,)],concat_axis=CONCAT_AXIS )#搭建inception4cx=inception_model(x,param=[(128,),(128,256),(24,64),(64,)],concat_axis=CONCAT_AXIS )#搭建inception4d層x=inception_model(x,param=[(112,),(144,288),(32,64),(64,)],concat_axis=CONCAT_AXIS )#搭建inception4e層x=inception_model(x,param=[(256,),(160,320),(32,128),(128,)],concat_axis=CONCAT_AXIS )x=MaxPooling2D(pool_size=(2,2),strides=2,padding="same")(x)#搭建inception5a層x=inception_model(x,param=[(256,),(160,320),(32,128),(128,)],concat_axis=CONCAT_AXIS )#搭建inception5b層x=inception_model(x,param=[(384,),(192,384),(48,128),(128,)],concat_axis=CONCAT_AXIS )#搭建平均池化層x=AveragePooling2D(pool_size=(1,1),strides=1,padding="valid")(x)#建立平坦層x=Flatten()(x)#搭建DROPOUT層x=Dropout(0.4)(x)#搭建全連接層,即輸出層x=Dense(units=10,activation="softmax")(x)#調用MDOEL函數,定義該網絡模型的輸入層為X_input,輸出層為x.即全連接層model=Model(inputs=x_input,outputs=[x])#查看網絡模型的摘要model.summary()return model model= googlenet() optimizer=RMSprop(lr=1e-4) model.compile(loss="categorical_crossentropy",optimizer=optimizer,metrics=["accuracy"])#訓練加評估模型 n_epoch=4 batch_size=128 def run_model():training=model.fit(X_train,Y_train,batch_size=batch_size,epochs=n_epoch,validation_split=0.25,verbose=1)test=model.evaluate(X_train,Y_train,verbose=1)print("誤差:",test[0])print("準確率:",test[1])run_model()?
總結
以上是生活随笔為你收集整理的经典卷积网络进阶--GoolgleNet详解的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 经典卷积神经网络--AlexNet的详解
- 下一篇: 经典卷积网络进阶--ResNet详解