VGG16
簡介
VGG是由Simonyan 和Zisserman在文獻《Very Deep Convolutional Networks for Large Scale Image Recognition》中提出卷積神經網絡模型,其名稱來源於作者所在的牛津大學視覺幾何組(Visual Geometry Group)的縮寫。
該模型參加2014年的 ImageNet圖像分類與定位挑戰賽,取得了優異成績:在分類任務上排名第二,在定位任務上排名第一。
結構
VGG中根據卷積核大小和卷積層數目的不同,可分為A
,A-LRN
,B
,C
,D
,E
共6個配置(ConvNet Configuration),其中以D
,E
兩種配置較為常用,分別稱為VGG16
和VGG19
。
下圖給出了VGG的六種結構配置:
上圖中,每一列對應一種結構配置。例如,圖中綠色部分即指明了VGG16所采用的結構。
我們針對VGG16進行具體分析發現,VGG16
共包含:
- 13個卷積層(Convolutional Layer),分別用conv3-XXX表示
- 3個全連接層(Fully connected Layer),分別用FC-XXXX表示
- 5個池化層(Pool layer),分別用maxpool表示
其中,卷積層和全連接層具有權重系數,因此也被稱為權重層
,總數目為13+3=16,這即是
VGG16中16的來源。(池化層不涉及權重,因此不屬於權重層,不被計數)。
特點
VGG16的突出特點是簡單,體現在:
-
卷積層均采用相同的卷積核參數
卷積層均表示為
conv3-XXX
,其中conv3
說明該卷積層采用的卷積核的尺寸(kernel size)是3,即寬(width)和高(height)均為3,3*3
是很小的卷積核尺寸,結合其它參數(步幅stride=1,填充方式padding=same),這樣就能夠使得每一個卷積層(張量)與前一層(張量)保持相同的寬和高。XXX
代表卷積層的通道數。 -
池化層均采用相同的池化核參數
池化層的參數均為2×
-
模型是由若干卷積層和池化層堆疊(stack)的方式構成,比較容易形成較深的網絡結構(在2014年,16層已經被認為很深了)。
綜合上述分析,可以概括VGG的優點為: Small filters, Deeper networks.
塊結構
我們注意上圖右側,VGG16的卷積層和池化層可以划分為不同的塊(Block),從前到后依次編號為Block1~block5。每一個塊內包含若干卷積層和一個池化層。例如:Block4
包含:
- 3個卷積層,conv3-512
- 1個池化層,maxpool
並且同一塊內,卷積層的通道(channel)數是相同的,例如:
block2
中包含2個卷積層,每個卷積層用conv3-128
表示,即卷積核為:3x3x3,通道數都是128
block3
中包含3個卷積層,每個卷積層用conv3-256
表示,即卷積核為:3x3x3,通道數都是256
下面給出按照塊划分的VGG16的結構圖,可以結合圖2進行理解:
VGG的輸入圖像是 224x224x3
通道數翻倍,由64依次增加到128,再到256,直至512保持不變,不再翻倍
高和寬變減半,由 224→112→56→28→14→7
權重參數
盡管VGG的結構簡單,但是所包含的權重數目卻很大,達到了驚人的139,357,544個參數。這些參數包括卷積核權重和全連接層權重。
-
例如,對於第一層卷積,由於輸入圖的通道數是3,網絡必須學習大小為3x3,通道數為3的的卷積核,這樣的卷積核有64個,因此總共有(3x3x3)x64 = 1728個參數
-
計算全連接層的權重參數數目的方法為:前一層節點數×本層的節點數前一層節點數×本層的節點數。因此,全連接層的參數分別為:
-
- 7x7x512x4096 = 1027,645,444
- 4096x4096 = 16,781,321
- 4096x1000 = 4096000
FeiFei Li在CS231的課件中給出了整個網絡的全部參數的計算過程(不考慮偏置),如下圖所示:
圖中藍色是計算權重參數數量的部分;紅色是計算所需存儲容量的部分。
VGG16具有如此之大的參數數目,可以預期它具有很高的擬合能力;但同時缺點也很明顯:
- 即訓練時間過長,調參難度大。
- 需要的存儲容量大,不利於部署。例如存儲VGG16權重值文件的大小為500多MB,不利於安裝到嵌入式系統中。
實踐
下面,我們應用Keras對VGG16的圖像分類能力進行試驗。
Keras是一個高層神經網絡API,Keras由純Python編寫 ,是tensorflow和Theano等底層深度學習庫的高級封裝 。使用Keras時,我們不需要直接調用底層API構建深度學習網絡,僅調用keras已經封裝好的函數即可。
基本流程:
- 載入相關模塊,keras ,matplotlib,numpy
- 下載已經訓練好的模型文件:
- 導入測試圖像
- 應用模型文件對圖像分類
源代碼如下:
import matplotlib.pyplot as plt
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input, decode_predictions
import numpy as np
def percent(value):
return '%.2f%%' % (value * 100)
# include_top=True,表示會載入完整的 VGG16 模型,包括加在最後3層的卷積層
# include_top=False,表示會載入 VGG16 的模型,不包括加在最後3層的卷積層,通常是取得 Features
# 若下載失敗,請先刪除 \.keras\models\vgg16_weights_tf_dim_ordering_tf_kernels.h5
model = VGG16(weights='imagenet', include_top=True)
# Input:要辨識的影像
img_path = 'tiger.png'
#img_path = 'tiger.jpg' 並轉化為224*224的標准尺寸
img = image.load_img(img_path, target_size=(224, 224))
x = image.img_to_array(img) #轉化為浮點型
x = np.expand_dims(x, axis=0)#轉化為張量size為(1, 224, 224, 3)
x = preprocess_input(x)
# 預測,取得features,維度為 (1,1000)
features = model.predict(x)
# 取得前五個最可能的類別及機率
pred=decode_predictions(features, top=5)[0]
#整理預測結果,value
values = []
bar_label = []
for element in pred:
values.append(element[2])
bar_label.append(element[1])
#繪圖並保存
fig=plt.figure(u"Top-5 預測結果")
ax = fig.add_subplot(111)
ax.bar(range(len(values)), values, tick_label=bar_label, width=0.5, fc='g')
ax.set_ylabel(u'probability')
ax.set_title(u'Top-5')
for a,b in zip(range(len(values)), values):
ax.text(a, b+0.0005, percent(b), ha='center', va = 'bottom', fontsize=7)
fig = plt.gcf()
plt.show()
name=img_path[0:-4]+'_pred'
fig.savefig(name, dpi=200)
#輸出模型的結構配置
print(model.summary())
輸出:
Model: "vgg16"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_1 (InputLayer) [(None, 224, 224, 3)] 0
_________________________________________________________________
block1_conv1 (Conv2D) (None, 224, 224, 64) 1792
_________________________________________________________________
block1_conv2 (Conv2D) (None, 224, 224, 64) 36928
_________________________________________________________________
block1_pool (MaxPooling2D) (None, 112, 112, 64) 0
_________________________________________________________________
block2_conv1 (Conv2D) (None, 112, 112, 128) 73856
_________________________________________________________________
block2_conv2 (Conv2D) (None, 112, 112, 128) 147584
_________________________________________________________________
block2_pool (MaxPooling2D) (None, 56, 56, 128) 0
_________________________________________________________________
block3_conv1 (Conv2D) (None, 56, 56, 256) 295168
_________________________________________________________________
block3_conv2 (Conv2D) (None, 56, 56, 256) 590080
_________________________________________________________________
block3_conv3 (Conv2D) (None, 56, 56, 256) 590080
_________________________________________________________________
block3_pool (MaxPooling2D) (None, 28, 28, 256) 0
_________________________________________________________________
block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160
_________________________________________________________________
block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808
_________________________________________________________________
block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808
_________________________________________________________________
block4_pool (MaxPooling2D) (None, 14, 14, 512) 0
_________________________________________________________________
block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808
_________________________________________________________________
block5_pool (MaxPooling2D) (None, 7, 7, 512) 0
_________________________________________________________________
flatten (Flatten) (None, 25088) 0
_________________________________________________________________
fc1 (Dense) (None, 4096) 102764544
_________________________________________________________________
fc2 (Dense) (None, 4096) 16781312
_________________________________________________________________
predictions (Dense) (None, 1000) 4097000
=================================================================
Total params: 138,357,544
Trainable params: 138,357,544
Non-trainable params: 0
_________________________________________________________________
None
關於程序運行:
-
程序運行過程中,語句
model = VGG16(weights='imagenet', include_top=True)
會下載已經訓練好的文件到\.keras\models
文件夾下,模型的文件名為vgg16_weights_tf_dim_ordering_tf_kernels.h5
,大小為527MB -
語句
pred=decode_predictions(features, top=5)[0]
會下載分類信息文件到\.keras\models
文件夾下,模型的文件名為imagenet_class_index.json
,該文件指明了ImageNet大賽所用的1000個圖像類的信息。(由於下載地址在aws上,梯子請自備) -
程序運行結束,會在工作目錄下生成測試圖片的預測圖,給出了最有可能的前5個類列。名稱為:
測試文件名_pred.png
對如下圖像進行分類:
分類結果為: