1. 程式人生 > >演算法工程師修仙之路:TensorFlow(七)

演算法工程師修仙之路:TensorFlow(七)

TensorFlow 入門

TensorFlow實現神經網路


通過 TensorFlow 訓練神經網路模型

  • 設定神經網路引數的過程就是神經網路的訓練過程。只有經過有效訓練的神經網路模型才可以真正地解決分類或者回歸問題。

  • 使用監督學習的方式設定神經網路引數需要有一個標註好的訓練資料集。

  • 在 Tensorflow 遊樂場有兩種顏色,一種黃色,一種藍色。任意一種顏色越深,都代表判斷的信心越大。

  • 監督學習最重要的思想就是,在己知答案的標註資料集上,模型給出的預測結果要儘量接近真實的答案。通過調整神經網路中的引數對訓練資料進行擬合,可以使得模型對未知的樣本提供預測的能力。

  • 在神經網路優化演算法中,最常用的方法是反向傳播演算法(backpropagation)。

  • 神經網路反向傳播優化流程圖
    在這裡插入圖片描述

  • 反向傳播演算法實現了 一個迭代的過程。

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

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

    # 計算單個輸入batch的前向傳播結果。
    import tensorflow as tf 
    
    # 若不加seed=1,每次的輸出是不一樣的
    w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) 
    w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
    
    """ 
    定義placeholder作為存放輸入資料的地方。
    這裡維度也不一定要定義,但如果維度是確定的,那麼給出維度可以降低出錯的概率。
    """
    x = tf.placeholder(tf.float32, shape=(1, 2), name="input")
    a = tf.matmul(x, w1)
    y = tf.matmul(a, w2)
    
    sess = tf.Session()
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    
    """ 
    下面一行將報錯:InvalidArgumentError (see above for traceback): 
    You must feed a value for placeholder tensor 'input' with dtype float and shape [1,2] 
    [[{{node input}} = Placeholder[dtype=DT_FLOAT, shape=[1,2], _device="/job:localhost/replica:0/task:0/device:GPU:0"]()]]
    """
    # print(sess.run(y))
    
    # 下面一行將會得到輸出結果:[[ 3.95757794]]
    print(sess.run(y, feed_dict={x:[[0.7, 0.9]]}))
    
  • 在新的程式中計算前向傳播結果時,需要提供一個 feed_dict 來指定 x 的取值。feed_dict 是一個字典(map),在字典中需要給出每個用到的 placeholder 的取值。如果某個需要的 placeholder 沒有被指定取值,那麼程式在執行時將會報錯。

  • 在訓練神經網路時需要每次提供一個 batch 的訓練樣例。對於這樣的需求,placeholder 也可以很好地支援。如果將輸入的 1 2 1*2 矩陣改為 n 2 n*2 的矩陣,那麼就可以得到 n 個樣例的前向傳播結果了。其中 n 2 n*2 的矩陣的每一行為一個樣例資料。這樣前向傳播的結果為 n 1 n*1 的矩陣,這個矩陣的每一行就代表了一個樣例的前向傳播結果。

    # 一次性計算多個樣例的前向傳播結果。
    import tensorflow as tf 
    
    # 若不加seed=1,每次的輸出是不一樣的
    w1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1)) 
    w2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
    
    """ 
    定義placeholder作為存放輸入資料的地方。
    這裡維度也不一定要定義,但如果維度是確定的,那麼給出維度可以降低出錯的概率。
    """
    # 輸入的維度為n*2,此處n取3
    x = tf.placeholder(tf.float32, shape=(3, 2), name="input") 
    a = tf.matmul(x, w1)
    y = tf.matmul(a, w2)
    
    sess = tf.Session()
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
    
    feed_dict = {x:[[0.7, 0.9], [0.1, 0.4], [0.5, 0.8]]}
    # 因為x在定義時指定了n為3,所以在執行前向傳播過程時需要提供3個樣例資料。
    # 下面一行將會得到輸出結果:[[ 3.95757794], [ 1.15376544], [ 3.16749239]]
    print(sess.run(y, feed_dict))
    
  • 在得到一個 batch 的前向傳播結果之後,需要定義一個損失函式來刻畫當前的預測值和真實答案之間的差距,然後通過反向傳播演算法來調整神經網路引數的取值,使得差距可以被縮小。

    # 以下程式碼定義了 一個簡單的損失函式,並通過TensorFlow定義了反向傳播演算法。
    
    """ 
    使用sigmoid函式將y轉換為0~ 1之間的數值。
    轉換後y代表預測是正樣本的概率。
    1-y代表預測是負樣本的概率。
    """
    
    y = tf.sigmoid(y)
    
    # 定義損失函式來刻畫預測值與真實值的差距。
    # cross_entropy定義了真實值和預測值之間的交叉熵,這是分類問題中一個常用的損失函式。
    cross_entropy = -tf.reduce_mean(y*tf.log(tf.clip_by_value(y, 1e-10, 1.0)) +
                     (1-y)*tf.log(tf.clip_by_value(1-y, 1e-10, 1.0)) )
    
    # 定義學習率
    learning_rate = 0.001
    
    # 定義反向傳播演算法來優化神經網路中的引數。 
    train_step = tf.train.AdamOptimizer(learning_rate).minimize(cross_entropy)
    
  • 比較常用的優化方法有三種:

    • tf.train.GradientDescentOptimizer;
    • tf.train.AdamOptimizer;
    • tf.train.MomentumOptimizer。
  • 在定義了反向傳播演算法之後,通過執行 sess.run(train_ step)就可以對所有在 GraphKeys.TRAINABLE_VARIABLES 集合中的變數進行優化,使得在當前 batch 下損失函式更小。