CNN-3: VGGNet 卷积神经网络模型
1、VGGNet 模型簡介
VGG Net由牛津大學(xué)的視覺幾何組(Visual Geometry Group)和 Google DeepMind公司的研究員一起研發(fā)的的深度卷積神經(jīng)網(wǎng)絡(luò),在 ILSVRC 2014 上取得了第二名的成績,將 Top-5錯(cuò)誤率降到7.3%。它主要的貢獻(xiàn)是展示出網(wǎng)絡(luò)的深度(depth)是算法優(yōu)良性能的關(guān)鍵部分。目前使用比較多的網(wǎng)絡(luò)結(jié)構(gòu)主要有ResNet(152-1000層),GooleNet(22層),VGGNet(19層),大多數(shù)模型都是基于這幾個(gè)模型上改進(jìn),采用新的優(yōu)化算法,多模型融合等。到目前為止,VGG Net 依然經(jīng)常被用來提取圖像特征。
2、VGGNet的特點(diǎn)?
1) 結(jié)構(gòu)簡潔
VGG由5層卷積層、3層全連接層、softmax輸出層構(gòu)成,層與層之間使用max-pooling(最大化池)分開,所有隱層的激活單元都采用ReLU函數(shù)。
2) 小卷積核和多卷積子層
VGG使用多個(gè)較小卷積核(3x3)的卷積層代替一個(gè)卷積核較大的卷積層,一方面可以減少參數(shù),另一方面相當(dāng)于進(jìn)行了更多的非線性映射,可以增加網(wǎng)絡(luò)的擬合/表達(dá)能力。 小卷積核是VGG的一個(gè)重要特點(diǎn),雖然VGG是在模仿AlexNet的網(wǎng)絡(luò)結(jié)構(gòu),但沒有采用AlexNet中比較大的卷積核尺寸(如7x7),而是通過降低卷積核的大小(3x3),增加卷積子層數(shù)來達(dá)到同樣的性能(VGG:從1到4卷積子層,AlexNet:1子層)。 VGG的作者認(rèn)為兩個(gè)3x3的卷積堆疊獲得的感受野大小,相當(dāng)一個(gè)5x5的卷積;而3個(gè)3x3卷積的堆疊獲取到的感受野相當(dāng)于一個(gè)7x7的卷積。這樣可以增加非線性映射,也能很好地減少參數(shù)(例如7x7的參數(shù)為49個(gè),而3個(gè)3x3的參數(shù)為27)。
3) 小池化核
相比AlexNet的3x3的池化核,VGG全部采用2x2的池化核。
4) 通道數(shù)多
VGG網(wǎng)絡(luò)第一層的通道數(shù)為64,后面每層都進(jìn)行了翻倍,最多到512個(gè)通道,通道數(shù)的增加,使得更多的信息可以被提取出來。
5) 層數(shù)更深、特征圖更寬
由于卷積核專注于擴(kuò)大通道數(shù)、池化專注于縮小寬和高,使得模型架構(gòu)上更深更寬的同時(shí),控制了計(jì)算量的增加規(guī)模。
6) 全連接轉(zhuǎn)卷積(測試階段)
這也是VGG的一個(gè)特點(diǎn),在網(wǎng)絡(luò)測試階段將訓(xùn)練階段的三個(gè)全連接替換為三個(gè)卷積,使得測試得到的全卷積網(wǎng)絡(luò)因?yàn)闆]有全連接的限制,因而可以接收任意寬或高為的輸入,這在測試階段很重要。
3、VGGNet的網(wǎng)絡(luò)結(jié)構(gòu)
?分別使用了A、A-LRN、B、C、D、E這6種網(wǎng)絡(luò)結(jié)構(gòu)進(jìn)行測試,這6種網(wǎng)絡(luò)結(jié)構(gòu)相似,都是由5層卷積層、3層全連接層組成,其中區(qū)別在于每個(gè)卷積層的子層數(shù)量不同,從A至E依次增加(子層數(shù)量從1到4),總的網(wǎng)絡(luò)深度從11層到19層(添加的層以粗體顯示),表格中的卷積層參數(shù)表示為“conv?感受野大小?-通道數(shù)?”,例如con3-128,表示使用3x3的卷積核,通道數(shù)為128。為了簡潔起見,在表格中不顯示ReLU激活功能。 其中,網(wǎng)絡(luò)結(jié)構(gòu)D就是著名的VGG16,網(wǎng)絡(luò)結(jié)構(gòu)E就是著名的VGG19。
以網(wǎng)絡(luò)結(jié)構(gòu)D(VGG16)為例,介紹其處理過程如下:
1)輸入224x224x3的圖片,經(jīng)64個(gè)3x3的卷積核作兩次卷積+ReLU,卷積后的尺寸變?yōu)?24x224x64
2)作max pooling(最大化池化),池化單元尺寸為2x2(效果為圖像尺寸減半),池化后的尺寸變?yōu)?12x112x64
3)經(jīng)128個(gè)3x3的卷積核作兩次卷積+ReLU,尺寸變?yōu)?12x112x128
4)作2x2的max pooling池化,尺寸變?yōu)?6x56x128
5)經(jīng)256個(gè)3x3的卷積核作三次卷積+ReLU,尺寸變?yōu)?6x56x256
6)作2x2的max pooling池化,尺寸變?yōu)?8x28x256
7)經(jīng)512個(gè)3x3的卷積核作三次卷積+ReLU,尺寸變?yōu)?8x28x512
8)作2x2的max pooling池化,尺寸變?yōu)?4x14x512
9)經(jīng)512個(gè)3x3的卷積核作三次卷積+ReLU,尺寸變?yōu)?4x14x512
10)作2x2的max pooling池化,尺寸變?yōu)?x7x512
11)與兩層1x1x4096,一層1x1x1000進(jìn)行全連接+ReLU(共三層)
12)通過softmax輸出1000個(gè)預(yù)測結(jié)果
?A、A-LRN、B、C、D、E這6種網(wǎng)絡(luò)結(jié)構(gòu)比較:
?A、A-LRN、B、C、D、E這6種網(wǎng)絡(luò)結(jié)構(gòu)的深度雖然從11層增加至19層,但參數(shù)量變化不大,這是由于基本上都是采用了小卷積核(3x3,只有9個(gè)參數(shù)),這6種結(jié)構(gòu)的參數(shù)數(shù)量(百萬級)并未發(fā)生太大變化,這是因?yàn)樵诰W(wǎng)絡(luò)中,參數(shù)主要集中在全連接層。
A、A-LRN、B、C、D、E這6種網(wǎng)絡(luò)結(jié)構(gòu)進(jìn)行單尺度的評估,錯(cuò)誤率結(jié)果如下:
?
從上表可以看出:
1)LRN層無性能增益(A-LRN) VGG作者通過網(wǎng)絡(luò)A-LRN發(fā)現(xiàn),AlexNet曾經(jīng)用到的LRN層(local response normalization,局部響應(yīng)歸一化)并沒有帶來性能的提升,因此在其它組的網(wǎng)絡(luò)中均沒再出現(xiàn)LRN層。
2)隨著深度增加,分類性能逐漸提高(A、B、C、D、E) 從11層的A到19層的E,網(wǎng)絡(luò)深度增加對top1和top5的錯(cuò)誤率下降很明顯。
多個(gè)小卷積核比單個(gè)大卷積核性能好(B) VGG作者做了實(shí)驗(yàn)用B和自己一個(gè)不在實(shí)驗(yàn)組里的較淺網(wǎng)絡(luò)比較,較淺網(wǎng)絡(luò)用conv5x5來代替B的兩個(gè)conv3x3,結(jié)果顯示多個(gè)小卷積核比單個(gè)大卷積核效果要好。
總結(jié):
1)通過增加深度能有效地提升性能;
2)最佳模型:VGG16,從頭到尾只有3x3卷積與2x2池化,簡潔優(yōu)美;
3)卷積可代替全連接,可適應(yīng)各種尺寸的圖片。
4? VGGNet 模型TensorFlow實(shí)現(xiàn)
開發(fā)環(huán)境:?Python - 3.0、TensorFlow - 1.4.0、無GPU
# -*- coding: utf-8 -*- """ Created on 2017 @author: 黃文堅(jiān)、唐源 """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:#定義卷積層參數(shù):前兩個(gè)為尺寸 ?*?、第三個(gè)為當(dāng)前層節(jié)點(diǎn)矩陣的深度 、第四個(gè)為卷積層的深度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 提供了一個(gè)方便的卷積層前向傳播函數(shù)#參數(shù)1:當(dāng)前層的節(jié)點(diǎn)矩陣,四維矩陣,第一維度對應(yīng)一個(gè)輸入batch,如第一張圖片,第二張圖片..#參數(shù)2:卷積層參數(shù)#參數(shù)3:不同維度上的步長(第一維、最后一維必須為1)#參數(shù)4:提供'SAME'和'VALLD'選擇,'SAME'為添加全0填充,'VALLD'為不添加conv = tf.nn.conv2d(input_op, kernel, (1, dh, dw, 1), padding='SAME')#定義偏置項(xiàng),及下一層節(jié)點(diǎn)矩陣的深度 (參數(shù)共享)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提供給每個(gè)conv節(jié)點(diǎn)加上偏置項(xiàng)z = tf.nn.bias_add(conv, biases)#將計(jì)算結(jié)果通過ReLU激活函數(shù)完成去線性化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 提供了一個(gè)方便的最大池化層的前向傳播過程。#tf.nn.avg_pool 提供了一個(gè)方便的平均池化層的前向傳播過程,兩者參數(shù)一致。#參數(shù)1:四維矩陣,第一維度對應(yīng)一個(gè)輸入batch,如第一張圖片,第二張圖片..#參數(shù)2:ksize為過濾器參數(shù),常為[1, 2, 2, 1]、[1, 3, 3, 1]#參數(shù)3:不同維度上的步長(第一維、最后一維必須為1)#參數(shù)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#將第五段卷積網(wǎng)絡(luò)的輸出結(jié)果扁平化,轉(zhuǎn)化為 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#連接一個(gè)隱含節(jié)點(diǎn)為4096的全連接層,激活函數(shù)為ReLU,然后連接一個(gè)Dropout層fc6 = fc_op(resh1, name="fc6", n_out=4096, p=p)fc6_drop = tf.nn.dropout(fc6, keep_prob, name="fc6_drop")#連接一個(gè)隱含節(jié)點(diǎn)為4096的全連接層,激活函數(shù)為ReLU,然后連接一個(gè)Dropout層fc7 = fc_op(fc6_drop, name="fc7", n_out=4096, p=p)fc7_drop = tf.nn.dropout(fc7, keep_prob, name="fc7_drop")#連接一個(gè)隱含節(jié)點(diǎn)為4096的全連接層,激活函數(shù)為ReLU,然后連接一個(gè)Softmax進(jìn)行處理得到分類輸出概率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參考文獻(xiàn)
[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]?黃文堅(jiān)、唐源等.?TensorFlow 實(shí)戰(zhàn) [M] , 北京:電子工業(yè)出版社,2017.
轉(zhuǎn)載于:https://www.cnblogs.com/ai-learning-blogs/p/11110391.html
總結(jié)
以上是生活随笔為你收集整理的CNN-3: VGGNet 卷积神经网络模型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Struts2的CRUD
- 下一篇: C++ | 内联函数 inline