【Tensorflow_DL_Note6】Tensorflow實現卷積神經網路(1)

馬衛飛發表於2018-04-18

一 Tensorflow的遊樂場及其神經網路的簡介

       此塊,我們將通過Tensorflow的遊樂場來快速的介紹神經網路的主要功能。Tensorflow遊樂場的連結如下所示:https://playground.tensorflow.org,這是一個可以通過網路瀏覽器就可以訓練的簡單的神經網路,並可以實現視覺化訓練過程的工具。其具體的截圖如下所示:


      從上圖可以看出,Tensorflow遊樂場的左側,標號為1的紅色方框中提供了四種不同的【資料集合】用來測試神經網路。預設的資料集合被選擇出來,並且看起來非常清晰。被選中的資料也會顯示在右側的輸出端,例如途中標記為2的紅色方框下,【OUTPUT】欄的下面,在這個資料集合中,我們可以看到一個二維的平面上有兩種顏色的樣本點,藍色和橙色,每一個小點,代表一個【訓練樣本】,而【樣本點】的顏色,代表了樣本點的【類別標籤】。因為樣本點的顏色只有兩種,所以,這是一個二分類問題。我們點選按鈕執行後,這個樣本很快的被劃分為兩類,如下圖所示。


        關於二分類的問題,再此塊,我們可以舉一個例子,假設我們需要判斷某工廠生產的零件是否合格,那麼藍色的點可以表示工廠生產的零件不合格,橙色的表示零件和個,這樣就將一個零件是否合格轉化成了區分顏色的點。

        為例將一個在實際環境中遇到的問題轉化成二維平面上對應的點,就需要考慮如何將實際問題張的實體轉化成二維平面上的一個樣本點。這就是【特徵提取】需要解決問題。

        還是以零件為例,我們可以使用零件的長度和質量大致的描述一個零件,這樣一個物理意義上的零件就可以被轉化成長度和質量這兩個數字。在機器學習中,所有用於描述實體的陣列組合在一起,就是一個【實體】的【特徵向量】。在Tensorflow中的Feature一欄,對應的就是一個零件的特徵向量,在此塊,我們可以認為x1代表兩件的質量,x2代表零件的長度。

       【特徵向量】是【神經網路】的【輸入】,神經網路的主體,在上圖的中間部分。就目前而言,主流的神經網路都是分層的結構。第一層為【輸入層】,代表【特徵向量】中每一個特徵的取值或者【屬性】,而且每一層只和下一層連線,直到最後一層作為輸出層得到計算的結果。在二分類問題中,比如判斷零件是否合格,神經網路的輸出層往往只包含一個節點,這個節點最終的輸出輸一個實數。通過這個輸出值和一個事先設定的閾值,就可以得到分類的結果。

        在【輸入層】和【輸出層】之間的層叫做【隱藏層】,一般一個神經網路的【隱藏層】越多,這個網路的深度就越深。而所謂的深度神經網路或者深度學習的這個深度也是和神經網路的層數密切相關的。在Tensorflow遊樂場中點選+和-按鈕,就可以用來增加和減少神經網路的【隱藏層】。

        在Tensorflow的遊樂場中,除了可以選擇神經網路的深度,它也支援選擇神經網路每一層節點的【節點】的數量,以及:

               【1】學習率-------Learning Rate

               【2】啟用函式-----Activation Function

               【3】 正則化------Regularization

         在上圖中,一個小方框代表神經網路中的一個【節點】,方框與方框之間的邊代表節點之間的連線。,每一條【邊】代表了神經網路中的【一個引數】,它可以是【任意的實數】。【神經網路】就是通過對【引數】的【合理設定】來解決【分類】或者【迴歸問題】,邊上的顏色,代表了這個引數的取值,顏色越深,這個引數的絕對值越大。

         綜上所述,使用【神經網路】解決【分類問題】主要可以分為以下4個步驟:

               【1】提取【問題】中【實體】的【特徵向量】作為神經網路的【輸入】。

               【2】定義【神經網路的結構】,並定義如何從神經網路的輸入得到輸出,該過程就是【神經網路的前向傳播演算法】。

               【3】通過【訓練資料】來調整【神經網路】中【引數】的取值,這就是【訓練神經網路】的【過程】

               【4】使用【訓練好的神經網路】來預測未知的【資料】。

二 神經網路前向傳播演算法的簡介

       此塊,對於神經網路中的前向的傳播演算法僅僅只是進行一個簡單的簡介,更為詳細的神經網路的前向傳播演算法的推導及其數學分析,請關注隨後的學習筆記。

       在前面的介紹了【神經網路】可以將輸入的【特徵向量】經過層層的推導得到最後的【輸出】,並且通過這些輸出,解決【  分類】或者【迴歸】的問題。那麼,神經網路的輸入是如何得到的呢?這就是我們這塊要說的【前向傳播演算法】。

      不同的【神經網路結構】的【前向傳播方式】是不一樣的。此塊,我們介紹一下最簡單的【全連線神經網路】的【前向傳播  演算法】,並且將展示如何通過Tensorflow實現這個演算法。

      為了介紹【神經網路】的【前向傳播演算法】,我們需要首先了解一下【神經元】的結構,【神經元】是【神經網路】中最小的單元,對應神經網路中的【節點】。

                           

      如上圖所示,一個【神經元】有多個輸入和一個輸出,每個神經元的輸入既可以是其他神經元的輸出也可以是整個神經網路的輸入。所謂的不同的【神經網路結構】其實質就是不同【神經元】之間的【連線結構】。一個最簡單的【神經元結構】就是所有輸入的【加權和】,而不同輸入的【權重】就是神經網路的【引數】。【神經網路】的【優化過程】就是【優化神經元引數取值】的過程。

      計算【神經網路】的【前向傳播】結果需要【三部分資訊】。第一部分就是【神經網路】的【輸入】,這個輸入就是從實體中提取的【特徵向量】。第二部分就是【神經網路】得【連線結構】。

      經過一些列推導之後,我們可以將【神經網路】的【前向傳播演算法】使用【矩陣乘法】的方式表達出來,而在Tensorflow中,矩陣乘法是非常容易實現的。

import tensorflow as tf
a = tf.matmul(X,W1)
y = tf.matmul(A,W2)
#========================================================================================================
#【1】其中,X是一個行向量,具體的數值為X = [x1,x2],對應於神經網路輸入層的兩個節點
#【2】W對應全連線方式的第一層神經元節點的【權值】,是一個2行3列的矩陣,具體的數值為W=[[w11,w12,w13],[w21,w22,w23]]
#【3】則第一層的前向傳播為XW,用tensorflow中的程式碼表示就如上所示。
#========================================================================================================

      其中tf.matmul()實現了【矩陣乘法】的【功能】。到此為止,已經簡述了神經網路的前向傳播演算法,並且給出了Tensorflow的程式實現了這個過程。之後,我們將繼續介紹:

                    【1】偏置-------------bias

                    【2】啟用函式--------activation function

      等更加複雜的神經元結構。也將會介紹卷積神經網路Tensorflow的實現過程、LSTM結構等更加複雜的神經網路結構。對於這些更加複雜的神經網路,Tensorflow也提供了的支援。

三 神經網路的引數與Tensorflow的變數

     【神經網路】中的【引數】是【神經網路】實現【分類】或者【迴歸】問題中的重要部分。此塊,我們將更加具體的介紹Tensorflow是如何【組織】、【儲存】以及【使用】神經網路中的【引數】的。

       在Tensorflow中,變數tf.Variable()函式的作用就是【儲存】和【更新】神經網路中的【引數】。和其他的程式語言相似,Tensorflow中的變數而需要進行初始化。而在神經網路中,給引數賦予隨機的初始值是最為常見的,所以一般也使用Tensorflow的隨機數給Tensorflow中的變數初始化。下面的程式碼給出了一種在Tensorflow中宣告一個2x3的矩陣變數的方法:

weights =tf.Variable(tf.random_normal([2,3],mean=0,stddev=2))

       這段程式碼呼叫了Tensorflow中的【變數宣告函式】tf.Variable。在【變數宣告函式】中,給出了初始化這個變數的方法。Tensorflow中的變數的初始值可以設定成【隨機數】、【常數】或者呼叫其他變數的初始化計算得到。在上面的程式碼中,使用正太分佈的隨機函式random_normal產生了一個2行3列分矩陣。

       在【神經網路】中,【偏置項:bias】通常會使用【常數】來設定【初始值】。下面的程式碼給出了一個樣例。

bias = tf.Variable(tf.zeros[3])

       在Tensorflow中,一個變數的值,在被使用之前,這個變數的初始化必須被明確的呼叫。下面的樣例介紹瞭如何通過【變數】實現神經網路的【引數】並實現【神經網路】【前向傳播的過程】。

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

#【1】宣告w1、w2這兩個【變數】,這裡還通過seed引數設定了隨機種子,這樣可以保證每次執行得到的結果是一樣的。
w1 = tf.Variable(tf.random_normal([2,3],mean=0,stddev=1,seed=1))
w2 = tf.Variable(tf.random_normal([2,3],mean=0,stddev=1,seed=1))
#【2】暫時將【輸入的特徵向量】定義為一個【常量】,注意這裡的x是一個1行2列的矩陣
x = tf.constant([0.7,0.9])
#【3】通過矩陣乘法計算【神經網路】的【前向傳播】
a = tf.matmul(x,w1)
y = tf.matmul(a,w2)
#【4】網路定義好之後,即Tensorflow中的【圖】定義好之後,使用【會話】Session開始執行
sess = tf.Session()               #【1】建立一個【會話】Session
#【5】注意,這裡不能通過sess.run(y)來獲取y的值,因為w1和w2都還沒有執行初始化的過程。
sess.run(w1.initializer)          #【2】初始化w1
sess.run(w2.initializer)          #【3】初始化w2
#【6】輸出
print(sess.run(y))
sess.close()

       上面的這段程式,實現了【神經網路】的【前向傳播過程】。從這段的程式碼可以看到,當宣告瞭變數w1、為之後,可以通過w1和w2來定義神經網路中的前向傳播過程並得到中間的結果a和最後的答案y。定義w1、w2、a和y的部分對應的是第一步,則一步定義了Tensorflow【圖】中所有的計算,但是,這些被定義的計算在這不併沒有真正的執行。當需要執行這些計算並得到具體的數字的時候,需要進入到Tensorflow程式中的第二步。

       在Tensorflow程式中的第二步,會宣告一個【會話:Session】,並通過會話計算結果。在上面的程式碼中,當【會話Session】的定義之後,就可以執行定義好的計算了。但是,需要特別注意的一點是,在具體的執行之前,需要明確的初始化所有即將用到的【變數】。

      雖然,直接呼叫每個【變數】的【初始化】過程,是一個可行的方案,但是當【變數】的數目變多,或者【  變數】之間存在著依賴關係的時候,單個呼叫的方案就顯的比較麻煩。為例解決這個問題,Tensorflow提供了一種更加便捷的方式來完成【變數】的【初始化】過程。下面的程式展示了通過tf.initializer_all_variables函式實現所有【變數】初始化的過程。

init_op = tf.initialize_all_variables()
sess.run(init_op)
      通過tf.initialize_all_variables()函式,就不需要將變數一個一個的初始化,這個函式也會自動處理變數之間的依賴關係。



相關文章