【Tensorflow_DL_Note7】Tensorflow實現卷積神經網路(2)

馬衛飛發表於2018-04-18

一 通過Tensorflow訓練神經網路模型

       上一節介紹瞭如何通過Tensorflow中變數表示神經網路中的引數,並且給出了一個樣例完成了神經網路的前向傳播過程。在這份程式碼中,所有【變數】的取值都是【隨機】的。在使用【神經網路】解決實際的【分類】和【迴歸問題】時,需要更好的設定【引數】的【取值】。在本節,我們將簡答的介紹使用【監督學習】的方式來更加合理的設定【引數的取值】,同時,也將給出Tensorflow程式來完成這個過程。【設定神經網路引數的過程】就是【訓練神經網路】的【過程】。只有經過【有效訓練】的【神經網路模型】才可以真正的解決【分類】或者【迴歸問題】。

       基於【監督學習】的方式設定【神經網路的引數】需要有一個【標註好的訓練資料集合】。【監督學習】最重要的思想就是,在已知答案的【標註資料集】上,模型給出的預測結果要儘可能的接近真實的答案。通過【調整】整神經網路中的【引數】對訓練資料進行擬合,可以使得模型對於未知的樣本提供預測的能力。

       在神經網路中,最常用的方法是【反向傳播演算法】。【反向傳播演算法】的具體原理如下所示。本節將介紹【訓練】【神經網路】的【整體流程】以及Tensorflow對於這個【流程】的支援。

       訓練的整體流程如下所示:

      【反向傳播演算法】實現了一個【迭代】的【過程】。在每次迭代的開始,首先,需要選取【一小部分訓練資料】,這一小部分訓練資料叫做一個【batch】。然後,這個【batch】的樣例會通過【前向傳播演算法】得到【神經網路模型】的【預測結果】。因為,【訓練資料】都是有【正確答案標註】的,所以,可以計算出當前神經網路模型的【預測答案】和【正確  答案】之間的【誤差】;最後,基於這種【預測值】和【真實值】之間的【差距】,【反向傳播演算法】會相應的跟新【神經網路】中的【引數】的【取值】,使得這個batch上的神經網路模型的【預測結果】和【真實答案】更加的接近。

      通過Tensorflow實現【反向傳播演算法】的第一步是使用Tensorflow表達一個batch的資料,如下所示:

x = tf.constant([0.7,0.9])

      但是,如果每輪迭代中,選取的資料都要通過constant常量表示,那麼Tensorflow的【圖模型】將會太大。因為,每生成一個【常量】,Tensorflow都會在【圖】中增加一個節點。一般來說,一個【神經網路的訓練過程】需要經過幾百萬輪甚至幾億萬倫的迭代,這樣下來,【圖】將會非常的大,而且利用率很低。為了避免這個問題,Tensorflow提供了【placeholder機制】用於提供【輸入資料】。【placeholder】相當於定義了一個位置,這個位置中的資料在執行的時候再指定,和其他張量一樣,placeholde的資料型別是不可以改變。placeholder中的資料的維度資訊可以根據提供的資料推導得出,所以不一定要給出。下面給出了通過placeholder實現前向傳播演算法的程式碼。

import tensorflow as tf

w1 = tf.Variable(tf.random_normal([2,3],mean=0,stddev=1))
w2 = tf.Variable(tf.random_normal([3,1],mean=0,stddev=1))
#【1】定義placehoder作為存放輸入資料的地方,這裡維度也不一定要定義,但是,如果維度是確定的,那麼給出維度可以降低出錯的
#    概率
x  = tf.placeholder(tf.float32,shape=(1,2),name="input")
a  = tf.matmul(x,w1)
y  = tf.matmul(a,w2)

#【2】建立回話
sess = tf.Session()
#【3】在變數使用之前,初始化所有變數
init_op = tf.initialize_all_variables()
#【4】具體執行變數的初始化
sess.run(init_op)
print(sess.run(y,feed_dict={x:[0.7,0.9]}))

       在這段程式中,替換掉了原來通過常量定義的輸入x。在新的程式中。計算前向傳播結果時,需要提供一個feed_dict來指定x的取值。feed_dict是一個字典(map),在字典中需要給出每個用到的placeholder的取值。如果某個需要的placeholder沒有指定取值,那麼程式在執行時,就會報錯。

      上面的程式僅僅計算了一個樣本或者說一個樣例的前向傳播結果,但是,實際的神經網路,是需要每次提供一個batch的訓練樣例,對於這樣的需求,placeholder也可以很好的支援。在上面的樣例中,如果將輸入的1x2矩陣改為nx2的矩陣,那麼就可以得到n個樣例的矩陣,這個矩陣的每一行就代表了一個樣例/樣本的前向傳播結果。具體的程式如下所示:

#========================================================================================================
#函式原型:
#       def random_normal(shape,mean=0.0,stddev=1.0,dtype=dtypes.float32,seed=None,name=None)
#函式說明:
#       生成一個滿足【正太分佈】的隨機數集合,集合的維度為shapee,均值為mean,標準方差為stddev,
#========================================================================================================
import tensorflow as tf

w1 = tf.Variable(tf.random_normal([2,3],mean=0,stddev=1))
w2 = tf.Variable(tf.random_normal([3,1],mean=0,stddev=1))
#【1】定義placehoder作為存放輸入資料的地方,這裡維度也不一定要定義,但是,如果維度是確定的,那麼給出維度可以降低出錯的
#    概率
x  = tf.placeholder(tf.float32,shape=(3,2),name="input")
a  = tf.matmul(x,w1)
y  = tf.matmul(a,w2)

#【2】建立回話
sess = tf.Session()
#【3】在變數使用之前,初始化所有變數
#init_op = tf.initialize_all_variables()
init_op =tf.global_variables_initializer()
#【4】具體執行變數的初始化
sess.run(init_op)
print(sess.run(y,feed_dict={x:[[0.7,0.9],[0.1,0.4],[0.5,0.8]]}))

       上面的樣例,展示了一次計算多個樣例的前向傳播結果。在執行的時候,需要將3個樣本/樣例的資料組成一個3行2列的矩陣傳入到placehodelr。計算得到的結果為一個3行1列的列向量。其中第一個數值2.5060797是第一個樣本的預測結果。需要注意的是,再此塊,我們將變數的初始化函式換成了最新的初始化函式。如下所示:

init_op =tf.global_variables_initializer()

       在得到一個batch的前向傳播結果之後,需要定義一個【損失函式】來計算【當前預測值】和【真實答案】之間的【差距】。然後,再通過【反向傳播演算法】來【調整】【神經網路引數】的【取值】,使得【誤差損失Loss】可以被縮小。下面的程式碼定義了一個簡單的【損失函式】,並通過Tensorflow定義了方向傳播演算法。   

#【1】定義【損失函式】來描述【預測值】和【真實值】之間的【差距】
cross_entropy = -tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
#【2】定義【學習率】
learning_rate = 0.001
#【3】定義反向傳播演算法來優化神經網路中的引數。
train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)

        在上面的程式碼中,cross_entropy定義了【真實值】和【預測值】之間的【交叉上】(cross_entropy),這是分類問題中一個常用的【損失函式】。第三行train_step定義了反向傳播的優化方法,且,目前Tensorflow支援7種不同的優化器。

二 完整神經網路的樣例程式

#coding=UTF-8
#========================================================================================================
#檔案說明:
#       【1】完整神經網路的樣例程式
#       【2】本節將在一個【模擬資料集】上訓練【神經網路】,下面給出了一個完整的程式來訓【練神經網路】,解決網路的【二分
#           類】問題。
#開發環境:
#       Win10+Tensorflow+OpenCv3.3+Python3.5+PyCharm5.0.3
#時間地點:
#       陝西師範大學 文集樓 2018.4.9
#========================================================================================================
import tensorflow as tf

#【1】NumPy是一個【科學計算的工具包】,這裡通過【NumPy】工具包生成【模擬資料集】。
from  numpy.random import RandomState
#【2】定義訓練資料batch的大小
batch_size = 8
#【3】定義【神經網路】的【引數】
w1 = tf.Variable(tf.random_normal([2,3],mean=0,stddev=1.0,seed=1))
w2 = tf.Variable(tf.random_normal([3,1],mean=0,stddev=1.0,seed=1))
#【4】在shape的一個維度上,使用None可以方便使用不大的batch的大小。在訓練時,需要把資料分成比較小的batch,但是在測試時,
#    可以一次性使用全部的資源資料。當【資料集】比較小時,這樣比較方便測試,但是,當資料集比較大時,將大量的資料放入一個
#    batch可能會導致記憶體溢位。
x  = tf.placeholder(tf.float32,shape=(None,2),name="x-input")
y_ = tf.placeholder(tf.float32,shape=(None,1),name="y-input")
#【5】定義【神經網路】的【前向傳播過程】
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
#【6】定義【損失函式】和【反向傳播演算法】
cross_entropy = -tf.reduce_mean(y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
train_step    = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
#========================================================================================================
#模組說明:
#       上面模組的程式碼實現了Tensorflow程式設計模型的第一階段:
#                                                  【1】圖的定義
#                                                  【2】定義【神經網路的結構】和【前向傳播的計算】
#========================================================================================================
#【1】通過隨機數生成一個【模擬資料集合】
rdm          = RandomState(1)
dataset_Size = 128
X = rdm.rand(dataset_Size,2)
#【2】定義規則來給出樣本的標籤,在這裡所有x1+x2<1的樣例都被認為是正樣本,而其他被認為是負樣本
Y = [[int(x1+x2<1)] for (x1,x2) in X]
#========================================================================================================
#模組說明:
#       上面的模組程式碼實現了為神經網路的訓練準備【訓練資料】
#========================================================================================================
#【1】建立一個會話來執行Tensorflow程式
with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    print(sess.run(w1))
    print(sess.run(w2))
    #【2】設定訓練的輪數
    STEPS = 5000
    for i in range(STEPS):
        #【1】每次選取batch_size個樣本進行訓練
        start = (i*batch_size)%dataset_Size
        end   = min(start+batch_size,dataset_Size)
        #【2】通過選取的樣本訓練神經網路並更新引數引數
        sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]})
        if i%10 ==0:
            total_cross_entropy = sess.run(cross_entropy,feed_dict={x:X,y_:Y})
            print("After %d training step,cross entropy on all data is %g"%(i,total_cross_entropy))
        #print(sess.run(w1))
        #print(sess.run(w2))
#========================================================================================================
#模組說明:
#       上面的模組程式碼實現了:
#                         【1】定義了【損失函式】以及【反向傳播優化演算法】
#                         【2】生成會話Session,並且在訓練資料上反覆執行反向傳播優化演算法。
#說   明:
#       無論神經網路的結構如何變化,Tensorflow的這三個變成步驟是不會發生變化的
#========================================================================================================



相關文章