CNN-3: VGGNet 卷积神经网络模型
1、VGGNet 模型簡介
VGG Net由牛津大學的視覺幾何組(Visual Geometry Group)和 Google DeepMind公司的研究員一起研發的的深度卷積神經網絡,在 ILSVRC 2014 上取得了第二名的成績,將 Top-5錯誤率降到7.3%。它主要的貢獻是展示出網絡的深度(depth)是算法優良性能的關鍵部分。目前使用比較多的網絡結構主要有ResNet(152-1000層),GooleNet(22層),VGGNet(19層),大多數模型都是基于這幾個模型上改進,采用新的優化算法,多模型融合等。到目前為止,VGG Net 依然經常被用來提取圖像特征。
2、VGGNet的特點?
1) 結構簡潔
VGG由5層卷積層、3層全連接層、softmax輸出層構成,層與層之間使用max-pooling(最大化池)分開,所有隱層的激活單元都采用ReLU函數。
2) 小卷積核和多卷積子層
VGG使用多個較小卷積核(3x3)的卷積層代替一個卷積核較大的卷積層,一方面可以減少參數,另一方面相當于進行了更多的非線性映射,可以增加網絡的擬合/表達能力。 小卷積核是VGG的一個重要特點,雖然VGG是在模仿AlexNet的網絡結構,但沒有采用AlexNet中比較大的卷積核尺寸(如7x7),而是通過降低卷積核的大小(3x3),增加卷積子層數來達到同樣的性能(VGG:從1到4卷積子層,AlexNet:1子層)。 VGG的作者認為兩個3x3的卷積堆疊獲得的感受野大小,相當一個5x5的卷積;而3個3x3卷積的堆疊獲取到的感受野相當于一個7x7的卷積。這樣可以增加非線性映射,也能很好地減少參數(例如7x7的參數為49個,而3個3x3的參數為27)。
3) 小池化核
相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核。
4) 通道數多
VGG網絡第一層的通道數為64,后面每層都進行了翻倍,最多到512個通道,通道數的增加,使得更多的信息可以被提取出來。
5) 層數更深、特征圖更寬
由于卷積核專注于擴大通道數、池化專注于縮小寬和高,使得模型架構上更深更寬的同時,控制了計算量的增加規模。
6) 全連接轉卷積(測試階段)
這也是VGG的一個特點,在網絡測試階段將訓練階段的三個全連接替換為三個卷積,使得測試得到的全卷積網絡因為沒有全連接的限制,因而可以接收任意寬或高為的輸入,這在測試階段很重要。
3、VGGNet的網絡結構
?分別使用了A、A-LRN、B、C、D、E這6種網絡結構進行測試,這6種網絡結構相似,都是由5層卷積層、3層全連接層組成,其中區別在于每個卷積層的子層數量不同,從A至E依次增加(子層數量從1到4),總的網絡深度從11層到19層(添加的層以粗體顯示),表格中的卷積層參數表示為“conv?感受野大小?-通道數?”,例如con3-128,表示使用3x3的卷積核,通道數為128。為了簡潔起見,在表格中不顯示ReLU激活功能。 其中,網絡結構D就是著名的VGG16,網絡結構E就是著名的VGG19。
以網絡結構D(VGG16)為例,介紹其處理過程如下:
1)輸入224x224x3的圖片,經64個3x3的卷積核作兩次卷積+ReLU,卷積后的尺寸變為224x224x64
2)作max pooling(最大化池化),池化單元尺寸為2x2(效果為圖像尺寸減半),池化后的尺寸變為112x112x64
3)經128個3x3的卷積核作兩次卷積+ReLU,尺寸變為112x112x128
4)作2x2的max pooling池化,尺寸變為56x56x128
5)經256個3x3的卷積核作三次卷積+ReLU,尺寸變為56x56x256
6)作2x2的max pooling池化,尺寸變為28x28x256
7)經512個3x3的卷積核作三次卷積+ReLU,尺寸變為28x28x512
8)作2x2的max pooling池化,尺寸變為14x14x512
9)經512個3x3的卷積核作三次卷積+ReLU,尺寸變為14x14x512
10)作2x2的max pooling池化,尺寸變為7x7x512
11)與兩層1x1x4096,一層1x1x1000進行全連接+ReLU(共三層)
12)通過softmax輸出1000個預測結果
?A、A-LRN、B、C、D、E這6種網絡結構比較:
?A、A-LRN、B、C、D、E這6種網絡結構的深度雖然從11層增加至19層,但參數量變化不大,這是由于基本上都是采用了小卷積核(3x3,只有9個參數),這6種結構的參數數量(百萬級)并未發生太大變化,這是因為在網絡中,參數主要集中在全連接層。
A、A-LRN、B、C、D、E這6種網絡結構進行單尺度的評估,錯誤率結果如下:
?
從上表可以看出:
1)LRN層無性能增益(A-LRN) VGG作者通過網絡A-LRN發現,AlexNet曾經用到的LRN層(local response normalization,局部響應歸一化)并沒有帶來性能的提升,因此在其它組的網絡中均沒再出現LRN層。
2)隨著深度增加,分類性能逐漸提高(A、B、C、D、E) 從11層的A到19層的E,網絡深度增加對top1和top5的錯誤率下降很明顯。
多個小卷積核比單個大卷積核性能好(B) VGG作者做了實驗用B和自己一個不在實驗組里的較淺網絡比較,較淺網絡用conv5x5來代替B的兩個conv3x3,結果顯示多個小卷積核比單個大卷積核效果要好。
總結:
1)通過增加深度能有效地提升性能;
2)最佳模型:VGG16,從頭到尾只有3x3卷積與2x2池化,簡潔優美;
3)卷積可代替全連接,可適應各種尺寸的圖片。
4? VGGNet 模型TensorFlow實現
開發環境:?Python - 3.0、TensorFlow - 1.4.0、無GPU
# -*- coding: utf-8 -*- """ Created on 2017 @author: 黃文堅、唐源 """from datetime import datetime import math import time import tensorflow as tfdef conv_op(input_op, name, kh, kw, n_out, dh, dw, p):n_in = input_op.get_shape()[-1].valuewith tf.name_scope(name) as scope:#定義卷積層參數:前兩個為尺寸 ?*?、第三個為當前層節點矩陣的深度 、第四個為卷積層的深度kernel = tf.get_variable(scope+"w",shape=[kh, kw, n_in, n_out],dtype=tf.float32, initializer=tf.contrib.layers.xavier_initializer_conv2d())#tf.nn.conv2d 提供了一個方便的卷積層前向傳播函數#參數1:當前層的節點矩陣,四維矩陣,第一維度對應一個輸入batch,如第一張圖片,第二張圖片..#參數2:卷積層參數#參數3:不同維度上的步長(第一維、最后一維必須為1)#參數4:提供'SAME'和'VALLD'選擇,'SAME'為添加全0填充,'VALLD'為不添加conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding='SAME')#定義偏置項,及下一層節點矩陣的深度 (參數共享)bias_init_val = tf.constant(0.0, shape=[n_out], dtype=tf.float32)biases = tf.Variable(bias_init_val, trainable=True, name='b')#tf.nn.bias_add提供給每個conv節點加上偏置項z = tf.nn.bias_add(conv, biases)#將計算結果通過ReLU激活函數完成去線性化activation = tf.nn.relu(z, name=scope)p += [kernel, biases]return activationdef fc_op(input_op, name, n_out, p):n_in = input_op.get_shape()[-1].valuewith tf.name_scope(name) as scope:kernel = tf.get_variable(scope+"w",shape=[n_in, n_out],dtype=tf.float32, initializer=tf.contrib.layers.xavier_initializer())biases = tf.Variable(tf.constant(0.1, shape=[n_out], dtype=tf.float32), name='b')activation = tf.nn.relu_layer(input_op, kernel, biases, name=scope)p += [kernel, biases]return activationdef mpool_op(input_op, name, kh, kw, dh, dw):#tf.nn.max_pool 提供了一個方便的最大池化層的前向傳播過程。#tf.nn.avg_pool 提供了一個方便的平均池化層的前向傳播過程,兩者參數一致。#參數1:四維矩陣,第一維度對應一個輸入batch,如第一張圖片,第二張圖片..#參數2:ksize為過濾器參數,常為[1, 2, 2, 1]、[1, 3, 3, 1]#參數3:不同維度上的步長(第一維、最后一維必須為1)#參數4:提供'SAME'和'VALLD'選擇,'SAME'為添加全0填充,'VALLD'為不添加return tf.nn.max_pool(input_op,ksize=[1, kh, kw, 1],strides=[1, dh, dw, 1],padding='SAME',name=name)def inference_op(input_op, keep_prob): p = []# assume input_op shape is 224x224x3# block 1 -- outputs 112x112x64conv1_1 = conv_op(input_op, name="conv1_1", kh=3, kw=3, n_out=64, dh=1, dw=1, p=p)conv1_2 = conv_op(conv1_1, name="conv1_2", kh=3, kw=3, n_out=64, dh=1, dw=1, p=p)pool1 = mpool_op(conv1_2, name="pool1", kh=2, kw=2, dw=2, dh=2)# block 2 -- outputs 56x56x128conv2_1 = conv_op(pool1, name="conv2_1", kh=3, kw=3, n_out=128, dh=1, dw=1, p=p)conv2_2 = conv_op(conv2_1, name="conv2_2", kh=3, kw=3, n_out=128, dh=1, dw=1, p=p)pool2 = mpool_op(conv2_2, name="pool2", kh=2, kw=2, dh=2, dw=2)# # block 3 -- outputs 28x28x256conv3_1 = conv_op(pool2, name="conv3_1", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p)conv3_2 = conv_op(conv3_1, name="conv3_2", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p)conv3_3 = conv_op(conv3_2, name="conv3_3", kh=3, kw=3, n_out=256, dh=1, dw=1, p=p) pool3 = mpool_op(conv3_3, name="pool3", kh=2, kw=2, dh=2, dw=2)# block 4 -- outputs 14x14x512conv4_1 = conv_op(pool3, name="conv4_1", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)conv4_2 = conv_op(conv4_1, name="conv4_2", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)conv4_3 = conv_op(conv4_2, name="conv4_3", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)pool4 = mpool_op(conv4_3, name="pool4", kh=2, kw=2, dh=2, dw=2)# block 5 -- outputs 7x7x512conv5_1 = conv_op(pool4, name="conv5_1", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)conv5_2 = conv_op(conv5_1, name="conv5_2", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)conv5_3 = conv_op(conv5_2, name="conv5_3", kh=3, kw=3, n_out=512, dh=1, dw=1, p=p)pool5 = mpool_op(conv5_3, name="pool5", kh=2, kw=2, dw=2, dh=2)# flatten#將第五段卷積網絡的輸出結果扁平化,轉化為 7*7*512=25088的一維向量shp = pool5.get_shape()flattened_shape = shp[1].value * shp[2].value * shp[3].valueresh1 = tf.reshape(pool5, [-1, flattened_shape], name="resh1")# fully connected#連接一個隱含節點為4096的全連接層,激活函數為ReLU,然后連接一個Dropout層fc6 = fc_op(resh1, name="fc6", n_out=4096, p=p)fc6_drop = tf.nn.dropout(fc6, keep_prob, name="fc6_drop")#連接一個隱含節點為4096的全連接層,激活函數為ReLU,然后連接一個Dropout層fc7 = fc_op(fc6_drop, name="fc7", n_out=4096, p=p)fc7_drop = tf.nn.dropout(fc7, keep_prob, name="fc7_drop")#連接一個隱含節點為4096的全連接層,激活函數為ReLU,然后連接一個Softmax進行處理得到分類輸出概率fc8 = fc_op(fc7_drop, name="fc8", n_out=1000, p=p)softmax = tf.nn.softmax(fc8)predictions = tf.argmax(softmax, 1)return predictions, softmax, fc8, pdef time_tensorflow_run(session, target, feed, info_string):num_steps_burn_in = 10total_duration = 0.0total_duration_squared = 0.0for i in range(num_batches + num_steps_burn_in):start_time = time.time()_ = session.run(target, feed_dict=feed)duration = time.time() - start_timeif i >= num_steps_burn_in:if not i % 10:print ('%s: step %d, duration = %.3f' %(datetime.now(), i - num_steps_burn_in, duration))total_duration += durationtotal_duration_squared += duration * durationmn = total_duration / num_batchesvr = total_duration_squared / num_batches - mn * mnsd = math.sqrt(vr)print ('%s: %s across %d steps, %.3f +/- %.3f sec / batch' %(datetime.now(), info_string, num_batches, mn, sd))def run_benchmark():with tf.Graph().as_default():image_size = 224images = tf.Variable(tf.random_normal([batch_size,image_size,image_size, 3],dtype=tf.float32,stddev=1e-1))keep_prob = tf.placeholder(tf.float32)predictions, softmax, fc8, p = inference_op(images, keep_prob)init = tf.global_variables_initializer()config = tf.ConfigProto()config.gpu_options.allocator_type = 'BFC'sess = tf.Session(config=config)sess.run(init)time_tensorflow_run(sess, predictions, {keep_prob:1.0}, "Forward")objective = tf.nn.l2_loss(fc8)grad = tf.gradients(objective, p)time_tensorflow_run(sess, grad, {keep_prob:0.5}, "Forward-backward")if __name__ == "__main__":batch_size=32num_batches=100run_benchmark() View Code參考文獻
[1]?https://my.oschina.net/u/876354/blog/1634322
[2]?Simonyan K , Zisserman A . Very Deep Convolutional Networks for Large-Scale Image Recognition[J]. Computer Science, 2014.
[3]?黃文堅、唐源等.?TensorFlow 實戰 [M] , 北京:電子工業出版社,2017.
轉載于:https://www.cnblogs.com/ai-learning-blogs/p/11110391.html
總結
以上是生活随笔為你收集整理的CNN-3: VGGNet 卷积神经网络模型的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts2的CRUD
- 下一篇: Tensorflow框架初尝试————搭