1. 程式人生 > >用tensorflow實現AlexNet網路

用tensorflow實現AlexNet網路

AlexNet網路:

2012年,Alex...提出了深度學習卷積神經網路模型Alexnet,其中包含了幾個當時新穎的技術點。獲得了2012年ILSVRC比賽第一名。Alexnet主要使用的技術點如下:

1.成功使用ReLU作為卷積神經網路的啟用函式,驗證了在深層卷積神經網路的效果超過Sigmoid,成功解決Sigmoid在網路較深層神經網路的梯度消失問題。

2.訓練使用dropout,忽略一部分神經元,以避免過擬合。主要是在最後的幾個全連線層使用了dropout。

3.LRN層(Local Response Normalization),提升泛化能力。實際上好像沒什麼用。而且還降低訓練速度。

4.使用最大池化,避免了平均池化的模糊效果,另外提出了讓步長比池化核小的最大池化方法。可以保證池化出的特徵有重疊,提升特徵的豐富性。

5.資料增強,隨機從256*256的原始影象中隨機擷取224*224大小的區域(並進行水平翻轉)這個操作相當於把資料量曾加了(256-224)*(256*224)*2倍=2048倍。如果沒有資料增強,只靠原始的資料量,眾多的引數會陷入過擬閤中。使用資料增強同業可以提高泛化能力。

額 

第一個卷積層使用了較大的卷積核尺寸11*11,步長為4,有96個卷積核;然後是有個3*3步長為2的池化層。只有第一層卷積核比較大,後面的幾層卷積核都比較小,都是5*5或者3*3的卷積核。

#首先匯入幾個需要使用的庫
from datetime import datetime
import math
import time
import tensorflow as tf
#這裡設定一個batch為30,共100個batch的資料
batch_size = 32
num_batch  = 100
#定義了一個可以列印每一層的名稱(t.op.name)並以列表的方式列印輸入尺寸資訊
def print_activation(t):
    print(t.op.name,'\n',t.get_shape().as_list())

#設計網路結構,以圖片作為輸入,返回pool5和所有需要訓練的模型引數
def Alexnet_structure(images):
    #定義一個列表
    parameters = []
    #定義第一層卷積層
    #可以將scope段內所有定義的變數自動命名為conv1/xxx
    with tf.name_scope('conv1') as scope:
        #第一層的卷積核,11*11*3,共64個,tf.truncated_normal一種設定正態分佈的方法
        kernel = tf.Variable(tf.truncated_normal([11,11,3,64],dtype=tf.float32,stddev=1e-1),name='weigths')
        #設定第一層卷積層,卷積核是上面初始化後的卷積核,步長為4,4,填充為SAME
        conv   = tf.nn.conv2d(images,kernel,[1,4,4,1],padding='SAME')
        #設定第一層的偏置,初始值為0
        biases = tf.Variable(tf.constant(0.0,shape=[64],dtype=tf.float32),trainable=True,name='biases')
        #設定w*x+b,之後用啟用函式處理。作為第一層的輸出
        W_x_plus_b   = tf.nn.bias_add(conv,biases)
        conv1  = tf.nn.relu(W_x_plus_b,name=scope)
        #啟用最開始定義的列印層資訊的函式,把輸出尺寸打印出來
        print_activation(conv1)
        parameters += [kernel,biases]
        #LRN層個人感覺與PCA的效果差不多,PCA實現的是降維,把主要的特徵保留
        # LRN實現的是將主要特徵的貢獻放大,將不重要的特徵縮小
        #由於效果並不明顯,且執行速度回慢三倍,很多神經網路已經放棄了加入LRN層
        #lrn1=tf.nn.lrn(conv1,4,bias=1.0,alpha=0.001/9,beta=0.75,name='lrn1')
        #pool1=tf.nn.max_pool(lrn1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='VALID',name='pool1')
        pool1=tf.nn.max_pool(conv1,ksize=[1,3,3,1],strides=[1,2,2,1],padding='VALID',name='pool1')
        print_activation(pool1)

    #定義第二個網路層
    with tf.name_scope('conv2')as scope:
        #定義卷積核5*5,192個,
        kernel = tf.Variable(tf.truncated_normal([5,5,64,192],dtype=tf.float32,stddev=1e-1),name='weigtths')
        #定義了一個卷積操作,步長為1,經過這次卷積後圖像尺寸大小沒有改變
        conv   = tf.nn.conv2d(pool1, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0,shape=[192],dtype=tf.float32),trainable=True,name='biases')
        W_x_plus_b   = tf.nn.bias_add(conv, biases)
        #同樣用了relu啟用函式
        conv2  = tf.nn.relu(W_x_plus_b, name=scope)
        parameters += [kernel, biases]
        print_activation(conv2)
        #lrn2  = tf.nn.lrn(conv2, 4, bias=1.0, alpha=0.001 / 9, beta=0.75, name='lrn2')
        #pool2 = tf.nn.max_pool(lrn2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool2')
        #池化層,3*3,步長為2,2,池化後由 [32, 27, 27, 192]--->[32, 13, 13, 192]
        #這個每一層第一個引數歐式32,這個是batch_size,即每次送入的圖片的數目
        pool2 = tf.nn.max_pool(conv2, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool2')
        print_activation(pool2)

    #定義第三層卷積層
    with tf.name_scope('conv3')as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 192, 384], dtype=tf.float32, stddev=1e-1), name='weigtths')
        conv   = tf.nn.conv2d(pool2, kernel, [1, 1, 1, 1], padding='SAME')
        biases =tf.Variable(tf.constant(0.0,shape=[384],dtype=tf.float32),trainable=True,name='biases')
        W_x_plus_b   = tf.nn.bias_add(conv, biases)
        conv3  = tf.nn.relu(W_x_plus_b, name=scope)
        parameters += [kernel, biases]
        print_activation(conv3)

    #定義第四層卷積層
    with tf.name_scope('conv4')as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 384, 256], dtype=tf.float32, stddev=1e-1), name='weigtths')
        conv   = tf.nn.conv2d(conv3, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0,shape=[256],dtype=tf.float32),trainable=True,name='biases')
        W_x_plus_b   = tf.nn.bias_add(conv, biases)
        conv4  = tf.nn.relu(W_x_plus_b, name=scope)
        parameters += [kernel, biases]
        print_activation(conv4)

    #定義第五層卷積層
    with tf.name_scope('conv5')as scope:
        kernel = tf.Variable(tf.truncated_normal([3, 3, 256, 256], dtype=tf.float32, stddev=1e-1), name='weigtths')
        conv   = tf.nn.conv2d(conv4, kernel, [1, 1, 1, 1], padding='SAME')
        biases = tf.Variable(tf.constant(0.0,shape=[256],dtype=tf.float32),trainable=True,name='biases')
        W_x_plus_b   = tf.nn.bias_add(conv, biases)
        conv5  = tf.nn.relu(W_x_plus_b, name=scope)
        parameters += [kernel, biases]
        print_activation(conv5)
        #根據原網路設計,第五層卷積層後緊跟一個池化層
        pool5  = tf.nn.max_pool(conv5, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding='VALID', name='pool5')
        print_activation(pool5)
        return pool5,parameters

#評估Alexnet每輪計算時間的函式
def time_Alexnet_run(session,target,info_string):
    num_steps_burn_in = 10
    total_duration    = 0.0
    total_duration_squared = 0.0
    for i in range(num_batch+num_steps_burn_in):
        start_time = time.time()
        tar = session.run(target)
        duration = time.time()-start_time
        if 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+=duration
            total_duration_squared+=duration*duration
    mn=total_duration/num_batch
    vr=total_duration_squared/num_batch-mn*mn
    sd=math.sqrt(vr)
    print('%s:s% accoss %d steps,%.3f +/-%.3f sec/batch ' % (datetime.now(), info_string,num_batch,mn,sd))

#主函式
def main():
    with tf.Graph().as_default():
        image_size = 224
        images = tf.Variable(tf.random_normal([batch_size,image_size,image_size,3],dtype=tf.float32,stddev=1e-1))
        pool5 , parmeters = Alexnet_structure(images)
        #初始化所有變數
        init   =  tf.global_variables_initializer()
        sess   =  tf.Session()
        sess.run(init)
        #統計計算時間
        time_Alexnet_run(sess,pool5,"Forward")
        objective = tf.nn.l2_loss(pool5)
        grad      = tf.gradients(objective,parmeters)
        time_Alexnet_run(sess,grad,"Forward-backward")
        print(len(parmeters))

main()

參考書籍:《Tensorflow實戰》黃文堅,唐源,電子工業出版社,第六章。