GoogleNet网络详解与keras实现
GoogleNet網絡詳解與keras實現
- GoogleNet網絡詳解與keras實現
- GoogleNet系列網絡的概覽
- Pascal_VOC數據集
- 第一層目錄
- 第二層目錄
- 第三層目錄
- InceptionV1模塊介紹
- Inception的架構
- GoogleNet的圖片
- Keras代碼實現
- 為了搭建Inception網絡我們使用了以下策略
- 整個代碼的流程如下
- 實驗結果
- 實驗結果分析
- 本博客相關引用
本博客旨在給經典的GoogleNet網絡進行詳解與代碼實現,如有不足或者其他的見解,請在本博客下面留言。
GoogleNet系列網絡的概覽
在本篇博客中,我們將實現一個類似于InceptionV2的結構,并用VOC2012的數據集進行網絡的訓練,驗證,與測試。為了快速開發,本次我們把Keras作為代碼的框架。
Pascal_VOC數據集
Pascal VOC為圖像識別,檢測與分割提供了一整套標準化的優秀的數據集,每一年都會舉辦一次圖像識別競賽。下面是VOC2012,訓練集(包括驗證集)的下載地址。
VOC2012里面有20類物體的圖片,圖片總共有1.7萬張。我把數據集分成了3個部分,訓練集,驗證集,測試集,比例為8:1:1。
下面是部分截圖:
第一層目錄
第二層目錄
第三層目錄
接著我們使用keras代碼來使用這個數據集,代碼如下:
IM_WIDTH=224 #圖片寬度 IM_HEIGHT=224 #圖片高度 batch_size=32 #批的大小#train data train_datagen = ImageDataGenerator(rotation_range=30, width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True )train_generator = train_datagen.flow_from_directory(train_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )#vaild data vaild_datagen = ImageDataGenerator(rotation_range=30,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True ) vaild_generator = train_datagen.flow_from_directory(vaildation_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )#test data test_datagen = ImageDataGenerator(rotation_range=30,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True ) test_generator = train_datagen.flow_from_directory(test_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )我使用了3個ImageDataGenerator,分別來使用訓練集,驗證集與測試集的數據。使用ImageDataGenerator需要導入相應的模塊,==from keras.preprocessing.image import ImageDataGenerator==。ImageDataGenrator可以用來做數據增強,提高模型的魯棒性.它里面提供了許多變換,包括圖片旋轉,對稱,平移等等操作。里面的flow_from_directory方法可以從相應的目錄里面批量獲取圖片,這樣就可以不用一次性讀取所有圖片(防止內存不足)。
InceptionV1模塊介紹
要想理解Googlenet的結構,第一步必須先知道Inception的結構,因為它是由多個Inception的結構組合而成的。如下圖Fig.2所示,(a)表示樸素的版本的inception v1示意圖,(b)表示降維版本的Inception v1示意圖。
Inception的主要思想基于——一個卷積網絡里面的局部稀疏最優結構往往可以由簡單可復用的密集組合來近似或者替代。就像(a)里面,1x1,3x3,5x5的卷積層,與3x3的池化層的組合一個inception。這樣做的幾點說明:
- 不同尺寸的卷積核可以提取不同尺度的信息。
- 采用1x1,3x3,5x5可以方便對齊,padding分別為0,1,2就可以對齊。
- 由于池化層在CNN網絡里面的成功運用,也把池化層當做組合的一部分。
- 由于Googlenet是好幾個Inception模塊的堆疊,而且往往越后面的Inception模塊提取的是更加高級抽象的特征,而由于高級抽象的特征的時域聯系會降低。(在這里加上一點個人理解,當提取的特征比較簡單,比如邊緣,輪廓的時候,往往只需要提取某個像素附近的幾個像素就行了,這時卷積核比較小,沒有問題。但是當提取的特征變得復雜的時候,比如提取的是人的鼻子,耳朵的時候,需要的可能就是某個像素旁邊幾十或者幾百個像素了。當然我說的這些像素指的是特征圖里面的像素。)因此為了獲取這些高級信息,我們在后面的Inception模塊里面需要增大3x3,5x5這些大卷積核的比例。
但是這么做,問題又來了,如果提高大卷積核的比例,那么這會意味著計算復雜度的飆升。為此,google的工程師們又提出(b)的這個Inception結構。
Inception的架構
下面的Table.1給出了Googlenet是怎么由Inception模塊和一些傳統的卷積層與池化層構成的。比較Inception(3a)和Inception(5b),我們可以看到大卷積核的濾波器的個數的比例已經提高了。最后需要注意兩點,該網絡的使用了avg pool來替代第一層全連接層,大大降低了參數的個數。后面在avg pool后面加入全連接層則是為了方便微調的操作。
GoogleNet的圖片
根據上面的表格我們可以畫出這樣的一幅圖。
Keras代碼實現
#-*- coding: UTF-8 -*-from keras.layers import Conv2D, MaxPooling2D, AveragePooling2D, ZeroPadding2D from keras.layers import Flatten, Dense, Dropout,BatchNormalization from keras.layers import Input, concatenate from keras.models import Model,load_model from keras.preprocessing.image import ImageDataGenerator from keras.utils import plot_model,np_utils from keras import regularizers import keras.metrics as metric import os# Global Constants NB_CLASS=20 LEARNING_RATE=0.01 MOMENTUM=0.9 ALPHA=0.0001 BETA=0.75 GAMMA=0.1 DROPOUT=0.4 WEIGHT_DECAY=0.0005 LRN2D_NORM=True DATA_FORMAT='channels_last' # Theano:'channels_first' Tensorflow:'channels_last' USE_BN=True IM_WIDTH=224 IM_HEIGHT=224 EPOCH=50train_root='/home/faith/keras/dataset/traindata/' vaildation_root='/home/faith/keras/dataset/vaildationdata/' test_root='/home/faith/keras/dataset/testdata/'IM_WIDTH=224 IM_HEIGHT=224 batch_size=32#train data train_datagen = ImageDataGenerator(rotation_range=30,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True ) train_generator = train_datagen.flow_from_directory(train_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )#vaild data vaild_datagen = ImageDataGenerator(rotation_range=30,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True ) vaild_generator = train_datagen.flow_from_directory(vaildation_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )#test data test_datagen = ImageDataGenerator(rotation_range=30,width_shift_range=0.2,height_shift_range=0.2,shear_range=0.2,zoom_range=0.2,horizontal_flip=True,featurewise_center=True ) test_generator = train_datagen.flow_from_directory(test_root,target_size=(IM_WIDTH, IM_HEIGHT),batch_size=batch_size, )#normalization def conv2D_lrn2d(x,filters,kernel_size,strides=(1,1),padding='same',data_format=DATA_FORMAT,dilation_rate=(1,1),activation='relu',use_bias=True,kernel_initializer='glorot_uniform',bias_initializer='zeros',kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,kernel_constraint=None,bias_constraint=None,lrn2d_norm=LRN2D_NORM,weight_decay=WEIGHT_DECAY):#l2 normalizationif weight_decay:kernel_regularizer=regularizers.l2(weight_decay)bias_regularizer=regularizers.l2(weight_decay)else:kernel_regularizer=Nonebias_regularizer=Nonex=Conv2D(filters=filters,kernel_size=kernel_size,strides=strides,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(x)if lrn2d_norm:#batch normalizationx=BatchNormalization()(x)return xdef inception_module(x,params,concat_axis,padding='same',data_format=DATA_FORMAT,dilation_rate=(1,1),activation='relu',use_bias=True,kernel_initializer='glorot_uniform',bias_initializer='zeros',kernel_regularizer=None,bias_regularizer=None,activity_regularizer=None,kernel_constraint=None,bias_constraint=None,lrn2d_norm=LRN2D_NORM,weight_decay=None):(branch1,branch2,branch3,branch4)=paramsif weight_decay:kernel_regularizer=regularizers.l2(weight_decay)bias_regularizer=regularizers.l2(weight_decay)else:kernel_regularizer=Nonebias_regularizer=None#1x1pathway1=Conv2D(filters=branch1[0],kernel_size=(1,1),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(x)#1x1->3x3pathway2=Conv2D(filters=branch2[0],kernel_size=(1,1),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(x)pathway2=Conv2D(filters=branch2[1],kernel_size=(3,3),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(pathway2)#1x1->5x5pathway3=Conv2D(filters=branch3[0],kernel_size=(1,1),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(x)pathway3=Conv2D(filters=branch3[1],kernel_size=(5,5),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(pathway3)#3x3->1x1pathway4=MaxPooling2D(pool_size=(3,3),strides=1,padding=padding,data_format=DATA_FORMAT)(x)pathway4=Conv2D(filters=branch4[0],kernel_size=(1,1),strides=1,padding=padding,data_format=data_format,dilation_rate=dilation_rate,activation=activation,use_bias=use_bias,kernel_initializer=kernel_initializer,bias_initializer=bias_initializer,kernel_regularizer=kernel_regularizer,bias_regularizer=bias_regularizer,activity_regularizer=activity_regularizer,kernel_constraint=kernel_constraint,bias_constraint=bias_constraint)(pathway4)return concatenate([pathway1,pathway2,pathway3,pathway4],axis=concat_axis)def create_model():#Data format:tensorflow,channels_last;theano,channels_lastif DATA_FORMAT=='channels_first':INP_SHAPE=(3,224,224)img_input=Input(shape=INP_SHAPE)CONCAT_AXIS=1elif DATA_FORMAT=='channels_last':INP_SHAPE=(224,224,3)img_input=Input(shape=INP_SHAPE)CONCAT_AXIS=3else:raise Exception('Invalid Dim Ordering')x=conv2D_lrn2d(img_input,64,(7,7),2,padding='same',lrn2d_norm=False)x=MaxPooling2D(pool_size=(3,3),strides=2,padding='same',data_format=DATA_FORMAT)(x)x=BatchNormalization()(x)x=conv2D_lrn2d(x,64,(1,1),1,padding='same',lrn2d_norm=False)x=conv2D_lrn2d(x,192,(3,3),1,padding='same',lrn2d_norm=True)x=MaxPooling2D(pool_size=(3,3),strides=2,padding='same',data_format=DATA_FORMAT)(x)x=inception_module(x,params=[(64,),(96,128),(16,32),(32,)],concat_axis=CONCAT_AXIS) #3ax=inception_module(x,params=[(128,),(128,192),(32,96),(64,)],concat_axis=CONCAT_AXIS) #3bx=MaxPooling2D(pool_size=(3,3),strides=2,padding='same',data_format=DATA_FORMAT)(x)x=inception_module(x,params=[(192,),(96,208),(16,48),(64,)],concat_axis=CONCAT_AXIS) #4ax=inception_module(x,params=[(160,),(112,224),(24,64),(64,)],concat_axis=CONCAT_AXIS) #4bx=inception_module(x,params=[(128,),(128,256),(24,64),(64,)],concat_axis=CONCAT_AXIS) #4cx=inception_module(x,params=[(112,),(144,288),(32,64),(64,)],concat_axis=CONCAT_AXIS) #4dx=inception_module(x,params=[(256,),(160,320),(32,128),(128,)],concat_axis=CONCAT_AXIS) #4ex=MaxPooling2D(pool_size=(3,3),strides=2,padding='same',data_format=DATA_FORMAT)(x)x=inception_module(x,params=[(256,),(160,320),(32,128),(128,)],concat_axis=CONCAT_AXIS) #5ax=inception_module(x,params=[(384,),(192,384),(48,128),(128,)],concat_axis=CONCAT_AXIS) #5bx=AveragePooling2D(pool_size=(7,7),strides=1,padding='valid',data_format=DATA_FORMAT)(x)x=Flatten()(x)x=Dropout(DROPOUT)(x)x=Dense(output_dim=NB_CLASS,activation='linear')(x)x=Dense(output_dim=NB_CLASS,activation='softmax')(x)return x,img_input,CONCAT_AXIS,INP_SHAPE,DATA_FORMATdef check_print():# Create the Modelx,img_input,CONCAT_AXIS,INP_SHAPE,DATA_FORMAT=create_model()# Create a Keras Modelmodel=Model(input=img_input,output=[x])model.summary()# Save a PNG of the Model Buildplot_model(model,to_file='GoogLeNet.png')model.compile(optimizer='adam',loss='categorical_crossentropy',metrics=['acc',metric.top_k_categorical_accuracy])print 'Model Compiled'return modelif __name__=='__main__':if os.path.exists('inception_1.h5'):model=load_model('inception_1.h5')else:model=check_print()model.fit_generator(train_generator,validation_data=vaild_generator,epochs=EPOCH,steps_per_epoch=train_generator.n/batch_size,validation_steps=vaild_generator.n/batch_size)model.save('inception_1.h5')model.metrics=['acc',metric.top_k_categorical_accuracy]loss,acc,top_acc=model.evaluate_generator(test_generator,steps=test_generator.n/batch_size)print 'Test result:loss:%f,acc:%f,top_acc:%f'%(loss,acc,top_acc)為了搭建Inception網絡,我們使用了以下策略:
- 使用了inception_module這個函數構造每個inception模塊,里面有4路,分別對應著1x1,(1x1,3x3),(1x1,5x5),(3x3,1x1) 這四路。
- 使用了3個正則化的手段,分別是L2正則化,BatchNormalization,dropout,來防止模型過擬合。
- create_model這個函數里面的網絡搭建可以參考Tabel.1,可以邊看表里面的具體參數邊搭網絡。
整個代碼的流程如下:
- 導入相應庫
- 模型參數設置以及其它配置
- 生成訓練集,測試集,驗證集的三個迭代器
- Inception module函數的編寫
- create model函數編寫,仿照Table.1
- 模型編譯,畫出模型的圖
- 模型訓練與驗證
- 模型保存
- 模型在測試集上測試
實驗結果
| Training set | 1.85 | 39.9% | 85.3% |
| Vaildation set | 2.01 | 36.6% | 82.0% |
| Testing set | 2.08 | 35.7% | 78.1% |
實驗結果分析
我們可以發現模型最后在測試集上的效果與訓練集上的效果有一定程度上的差距,模型出現了一點過擬合。以下是個人對此問題的一些分析:由于采用了L2正則化,BatchNormalization,Dropout等等方法,但是還是出現了過擬合,可能是由于VOC數據比較少,20類物體才1.7萬張,相當于每個物體850張左右,要想取得比較好的效果,每個類別物體的圖片至少得幾千張。所以可以通過降低網絡層數,增加數據量,增加訓練次數等手段來提高網絡的性能。
本博客相關引用
以下是本博客的引用,再次本人對每個引用的作者表示感謝。讀者如果對googlenet這個網絡仍然存在一些疑慮,或者想要有更深的理解,可以參考以下的引用。
引用博客1
引用博客2
引用博客3
引用文獻1:InceptionV1
引用文獻2:InceptionV2
引用文獻3:InceptionV3
引用文獻4:InceptionV4!
總結
以上是生活随笔為你收集整理的GoogleNet网络详解与keras实现的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【课题总结】OpenCV 抠图项目实战(
- 下一篇: 在大数据时代下金融风控的分类