vgg學習


LeNet-5是一個較簡單的卷積神經網絡。下圖顯示了其結構:輸入的二維圖像,先經過兩次卷積層到池化層,再經過全連接層,最后使用softmax分類作為輸出層。

 

 

AlexNet中包含了幾個比較新的技術點,也首次在 CNN中成功應用了ReLU、Dropout和LRN等Trick。同時AlexNet也使用了GPU進行運算加速。
AlexNet將LeNet的思想發揚光大,把CNN的基本原理應用到了很深很寬的網絡中。AlexNet主要使用到的新技術點如下:
(1)成功使用ReLU作為CNN的激活函數,並驗證其效果在較深的網絡超過了Sigmoid,成功解決了Sigmoid在網絡較深時的梯度彌散問題。雖然ReLU激活函數在很久之前就被提出了,但是直到AlexNet的出現才將其發揚光大。
(2)訓練時使用Dropout隨機忽略一部分神經元,以避免模型過擬合。Dropout雖有單獨的論文論述,但是AlexNet將其實用化,通過實踐證實了它的效果。在AlexNet中主要是最后幾個全連接層使用了Dropout。
(3)在CNN中使用重疊的最大池化。此前CNN中普遍使用平均池化,AlexNet全部使用最大池化,避免平均池化的模糊化效果。並且AlexNet中提出讓步長比池化核的尺寸小,這樣池化層的輸出之間會有重疊和覆蓋,提升了特征的豐富性。
(4)提出了LRN層,對局部神經元的活動創建競爭機制,使得其中響應比較大的值變得相對更大,並抑制其他反饋較小的神經元,增強了模型的泛化能力。
(5)使用CUDA加速深度卷積網絡的訓練,利用GPU強大的並行計算能力,處理神經網絡訓練時大量的矩陣運算。AlexNet使用了兩塊GTX 580 GPU進行訓練,單個GTX 580只有3GB顯存,這限制了可訓練的網絡的最大規模。因此作者將AlexNet分布在兩個GPU上,在每個GPU的顯存中儲存一半的神經元的參數。因為GPU之間通信方便,可以互相訪問顯存,而不需要通過主機內存,所以同時使用多塊GPU也是非常高效的。同時,AlexNet的設計讓GPU之間的通信只在網絡的某些層進行,控制了通信的性能損耗。 

(6)數據增強,隨機地從256*256的原始圖像中截取224*224大小的區域(以及水平翻轉的鏡像),相當於增加了2*(256-224)^2=2048倍的數據量。如果沒有數據增強,僅靠原始的數據量,參數眾多的CNN會陷入過擬合中,使用了數據增強后可以大大減輕過擬合,提升泛化能力。進行預測時,則是取圖片的四個角加中間共5個位置,並進行左右翻轉,一共獲得10張圖片,對他們進行預測並對10次結果求均值。同時,AlexNet論文中提到了會對圖像的RGB數據進行PCA處理,並對主成分做一個標准差為0.1的高斯擾動,增加一些噪聲,這個Trick可以讓錯誤率再下降1%。

# -*- coding=UTF-8 -*-  
import  tensorflow as tf  
# 輸入數據  
import  input_data  
mnist  =  input_data.read_data_sets( "/tmp/data/" , one_hot = True )  
# 定義網絡超參數  
learning_rate  =  0.001  
training_iters  =  200000  
batch_size  =  64  
display_step  =  20  
# 定義網絡參數  
n_input  =  784   # 輸入的維度  
n_classes  =  10  # 標簽的維度  
dropout  =  0.8   # Dropout 的概率  
# 占位符輸入  
=  tf.placeholder(tf.types.float32, [ None , n_input])  
=  tf.placeholder(tf.types.float32, [ None , n_classes])  
keep_prob  =  tf.placeholder(tf.types.float32)  
# 卷積操作  
def  conv2d(name, l_input, w, b):  
     return  tf.nn.relu(tf.nn.bias_add( \  
     tf.nn.conv2d(l_input, w, strides = [ 1 1 1 1 ], padding = 'SAME' ),b) \  
     , name = name)  
# 最大下采樣操作  
def  max_pool(name, l_input, k):  
     return  tf.nn.max_pool(l_input, ksize = [ 1 , k, k,  1 ], \  
     strides = [ 1 , k, k,  1 ], padding = 'SAME' , name = name)  
# 歸一化操作  
def  norm(name, l_input, lsize = 4 ):  
     return  tf.nn.lrn(l_input, lsize, bias = 1.0 , alpha = 0.001  /  9.0 , beta = 0.75 , name = name)  
# 定義整個網絡   
def  alex_net(_X, _weights, _biases, _dropout):  
     _X  =  tf.reshape(_X, shape = [ - 1 28 28 1 ])  # 向量轉為矩陣  
     # 卷積層  
     conv1  =  conv2d( 'conv1' , _X, _weights[ 'wc1' ], _biases[ 'bc1' ])  
     # 下采樣層  
     pool1  =  max_pool( 'pool1' , conv1, k = 2 )  
     # 歸一化層  
     norm1  =  norm( 'norm1' , pool1, lsize = 4 )  
     # Dropout  
     norm1  =  tf.nn.dropout(norm1, _dropout)  
   
     # 卷積  
     conv2  =  conv2d( 'conv2' , norm1, _weights[ 'wc2' ], _biases[ 'bc2' ])  
     # 下采樣  
     pool2  =  max_pool( 'pool2' , conv2, k = 2 )  
     # 歸一化  
     norm2  =  norm( 'norm2' , pool2, lsize = 4 )  
     # Dropout  
     norm2  =  tf.nn.dropout(norm2, _dropout)  
   
     # 卷積  
     conv3  =  conv2d( 'conv3' , norm2, _weights[ 'wc3' ], _biases[ 'bc3' ])  
     # 下采樣  
     pool3  =  max_pool( 'pool3' , conv3, k = 2 )  
     # 歸一化  
     norm3  =  norm( 'norm3' , pool3, lsize = 4 )  
     # Dropout  
     norm3  =  tf.nn.dropout(norm3, _dropout)  
   
     # 全連接層,先把特征圖轉為向量  
     dense1  =  tf.reshape(norm3, [ - 1 , _weights[ 'wd1' ].get_shape().as_list()[ 0 ]])   
     dense1  =  tf.nn.relu(tf.matmul(dense1, _weights[ 'wd1' ])  +  _biases[ 'bd1' ], name = 'fc1' )   
     # 全連接層  
     dense2  =  tf.nn.relu(tf.matmul(dense1, _weights[ 'wd2' ])  +  _biases[ 'bd2' ], name = 'fc2'
     # Relu activation  
     # 網絡輸出層  
     out  =  tf.matmul(dense2, _weights[ 'out' ])  +  _biases[ 'out' ]  
     return  out  
   
# 存儲所有的網絡參數  
weights  =  {  
     'wc1' : tf.Variable(tf.random_normal([ 3 3 1 64 ])),  
     'wc2' : tf.Variable(tf.random_normal([ 3 3 64 128 ])),  
     'wc3' : tf.Variable(tf.random_normal([ 3 3 128 256 ])),  
     'wd1' : tf.Variable(tf.random_normal([ 4 * 4 * 256 1024 ])),  
     'wd2' : tf.Variable(tf.random_normal([ 1024 1024 ])),  
     'out' : tf.Variable(tf.random_normal([ 1024 10 ]))  
}  
biases  =  {  
     'bc1' : tf.Variable(tf.random_normal([ 64 ])),  
     'bc2' : tf.Variable(tf.random_normal([ 128 ])),  
     'bc3' : tf.Variable(tf.random_normal([ 256 ])),  
     'bd1' : tf.Variable(tf.random_normal([ 1024 ])),  
     'bd2' : tf.Variable(tf.random_normal([ 1024 ])),  
     'out' : tf.Variable(tf.random_normal([n_classes]))  
}  
# 構建模型  
pred  =  alex_net(x, weights, biases, keep_prob)  
# 定義損失函數和學習步驟  
cost  =  tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(pred, y))  
optimizer  =  tf.train.AdamOptimizer(learning_rate = learning_rate).minimize(cost)  
# 測試網絡  
correct_pred  =  tf.equal(tf.argmax(pred, 1 ), tf.argmax(y, 1 ))  
accuracy  =  tf.reduce_mean(tf.cast(correct_pred, tf.float32))  
# 初始化所有的共享變量  
init  =  tf.initialize_all_variables()  
# 開啟一個訓練  
with tf.Session() as sess:  
     sess.run(init)  
     step  =  1  
     # Keep training until reach max iterations  
     while  step  *  batch_size < training_iters:  
         batch_xs, batch_ys  =  mnist.train.next_batch(batch_size)  
         # 獲取批數據  
         sess.run(optimizer, feed_dict = {x: batch_xs, y: batch_ys, keep_prob: dropout})  
         if  step  %  display_step  = =  0 :  
             # 計算精度  
             acc  =  sess.run(accuracy, feed_dict = {x: batch_xs, y: batch_ys, keep_prob:  1. })  
             # 計算損失值  
             loss  =  sess.run(cost, feed_dict = {x: batch_xs, y: batch_ys, keep_prob:  1. })  
             print  "Iter "  +  str (step * batch_size)  +  ", Minibatch Loss= "  +  "{:.6f}" . format (loss)  +  ", Training Accuracy= "  +  "{:.5f}" . format (acc)  
         step  + =  1  
     print  "Optimization Finished!"  
     # 計算測試精度  
     print  "Testing Accuracy:" , sess.run(accuracy, feed_dict = {x: mnist.test.images[: 256 ], y: mnist.test.labels[: 256 ], keep_prob:  1. })  
 
以上代碼忽略了部分卷積層,全連接層使用了特定的權重。
 
VGG是在從Alex-net發展而來的網絡。主要修改一下兩個方面:
1,在第一個卷基層層使用更小的filter尺寸和間隔(3*3); 2,在整個圖片和multi-scale上訓練和測試圖片。
3*3 filter:
引入cs231n上面一段話:
幾個小濾波器卷積層的組合比一個大濾波器卷積層好:
假設你一層一層地重疊了3個3x3的卷積層(層與層之間有非線性激活函數)。在這個排列下,第一個卷積層中的每個神經元都對輸入數據體有一個3x3的視野。
第二個卷積層上的神經元對第一個卷積層有一個3x3的視野,也就是對輸入數據體有5x5的視野。同樣,在第三個卷積層上的神經元對第二個卷積層有3x3的視野,
也就是對輸入數據體有7x7的視野。假設不采用這3個3x3的卷積層,二是使用一個單獨的有7x7的感受野的卷積層,那么所有神經元的感受野也是7x7,但是就有一些缺點。
首先, 多個卷積層與非線性的激活層交替的結構,比單一卷積層的結構更能提取出深層的更好的特征。其次,假設所有的數據有C個通道,那么單獨的7x7卷積層將會包含
7*7*C=49C2個參數,而3個3x3的卷積層的組合僅有個3*(3*3*C)=27C2個參數。直觀說來,最好選擇帶有小濾波器的卷積層組合,而不是用一個帶有大的濾波器的卷積層。前者可以表達出輸入數據中更多個強力特征,
使用的參數也更少。唯一的不足是,在進行反向傳播時,中間的卷積層可能會導致占用更多的內存。
 
1*1 filter: 作用是在不影響輸入輸出維數的情況下,對輸入線進行線性形變,然后通過Relu進行非線性處理,增加網絡的非線性表達能力。 Pooling:2*2,間隔s=2。
 

VGG

VGG-16和VGG-19取名源自作者所處研究組名(Visual Geometry Group),后面的16 19代表了網絡的深度。

VGG-16/VGG-19 138M參數,ILSVRC 2014的亞軍網絡。

VGG-16結構的基本框架

conv1^2 (64) -> pool1 -> conv2^2 (128) -> pool2 -> conv3^3 (256) -> pool3 -> conv4^3 (512) -> pool4 -> conv5^3 (512) -> pool5 -> fc6 (4096) -> fc7 (4096) -> fc8 (1000) -> softmax。 ^3代表重復3次。

網絡輸入的224×224的圖像。

 

 

VGG網絡的特點

(1). 結構簡單,作者將卷積核全部替換為3×3(極少用了1×1);相比於AlexNet 的池化核,VGG全部使用2×2的池化核。

(2). 參數量大,而且大部分的參數集中在全連接層中。網絡名稱中有16表示它有16層conv/fc層。

(3). 合適的網絡初始化和使用批量歸一(batch normalization)層對訓練深層網絡很重要。

(4). VGG-19結構類似於VGG-16,有略好於VGG-16的性能,但VGG-19需要消耗更大的資源,因此實際中VGG-16使用得更多。由於VGG-16網絡結構十分簡單,並且很適合遷移學習,因此至今VGG-16仍在廣泛使用。

def VGG16(images, _dropout, n_cls):
    """
    此處權重初始化方式采用的是:
        卷積層使用預訓練模型中的參數
        全連接層使用xavier類型初始化
    """
    conv1_1 = conv(images, 64, 'conv1_1', fineturn=True) #1
    conv1_2 = conv(conv1_1, 64, 'conv1_2', fineturn=True) #2
    pool1   = maxpool(conv1_2, 'pool1')
 
    conv2_1 = conv(pool1, 128, 'conv2_1', fineturn=True) #3
    conv2_2 = conv(conv2_1, 128, 'conv2_2', fineturn=True) #4
    pool2   = maxpool(conv2_2, 'pool2')
 
    conv3_1 = conv(pool2, 256, 'conv3_1', fineturn=True) #5
    conv3_2 = conv(conv3_1, 256, 'conv3_2', fineturn=True) #6
    conv3_3 = conv(conv3_2, 256, 'conv3_3', fineturn=True) #7
    pool3   = maxpool(conv3_3, 'pool3')
 
    conv4_1 = conv(pool3, 512, 'conv4_1', fineturn=True) #8
    conv4_2 = conv(conv4_1, 512, 'conv4_2', fineturn=True) #9
    conv4_3 = conv(conv4_2, 512, 'conv4_3', fineturn=True) #10
    pool4   = maxpool(conv4_3, 'pool4')
 
    conv5_1 = conv(pool4, 512, 'conv5_1', fineturn=True) #11
    conv5_2 = conv(conv5_1, 512, 'conv5_2', fineturn=True) #12
    conv5_3 = conv(conv5_2, 512, 'conv5_3', fineturn=True) #13
    pool5   = maxpool(conv5_3, 'pool5')
 
    #因為訓練自己的數據,全連接層最好不要使用預訓練參數
    flatten  = tf.reshape(pool5, [-1, 7*7*512])
    fc6      = fc(flatten, 4096, 'fc6', xavier=True) #14
    dropout1 = tf.nn.dropout(fc6, _dropout)
 
    fc7      = fc(dropout1, 4096, 'fc7', xavier=True) #15
    dropout2 = tf.nn.dropout(fc7, _dropout)
    
    fc8      = fc(dropout2, n_cls, 'fc8', xavier=True) #16
 
    return fc8

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM