TensorFlow實戰Google深度學習框架1-4章學習筆記

目錄

第1章 深度學習簡介

第2章 TensorFlow環境搭建

第3章 TensorFlow入門

第4章 深層神經網絡

 

 


第1章 深度學習簡介

對於許多機器學習問題來說,特徵提取不是一件簡單的事情。在一些複雜問題上,要通過人工的方式設計有效的特徵集合,需要很多的時間和精力,有時甚至需要整個領域數十年的研究投入。

 

深度學習解決的核心問題之一就是自動地將簡單的特徵組合成更加複雜的特徵。並使用這些組合特徵解決問題。深度學習是機器學習的一個分支,它除了可以學習特徵和任務之間的關聯,還能自動從簡單特徵中提取更加複雜的特徵。

 

深度學習在很多領域都有非常出色的表現,例如在計算機視覺、語音識別、自然語言處理和人機博弈等。

 

 


第2章 TensorFlow環境搭建

TensorFlow主要依賴兩個工具包——Protocol Buffer和Bazel。

 

Protocol Buffer是谷歌開發的處理結構化數據的工具,和XML或者JSON格式的數據有較大的區別。首先Protocol Buffer序列化之後得到的數據不是可讀的字符串,而是二進制流。其次,XML或JSON格式的數據信息都包含在了序列化之後的數據中,不需要任何其他信息就能還原序列化之後的數據。但使用Protocol Buffer時需要先定義數據的格式,還原一個序列化之後的數據將需要使用到這個定義好的數據格式。因爲這樣的差別,Protocol Buffer序列化出來的數據要比XML格式的數據小3到10倍,解析時間快20到100倍。以下是Protocol Buffer格式的一個定義示例:

message user{
         optional string name = 1;
         required int32 id = 2;
         repeated string email = 3;
}

Bazel是從谷歌開源的自動化構建工具,谷歌內部絕大部分的應用都是通過它來編譯的。相比傳統的Makefile、Ant或者Maven,Bazel在速度、可伸縮性、靈活性以及對不同程序語言和平臺的支持上都要更加出色。TensorFlow本身以及谷歌給出的很多官方樣例都是通過Bazel來編譯的。

 

 


第3章 TensorFlow入門

TensorFlow的名字中已經說明了它最重要的兩個概念——Tensor和Flow。Tensor就是張量,可以被簡單地理解爲多維數組。Flow翻譯成中文就是“流”,它直觀地表達了張量之間通過計算相互轉化的過程。TensorFlow是一個通過計算圖的形式來表述計算的編程系統,每一個計算都是計算圖上的一個節點,而節點之間的邊描述了計算之間的依賴關係。計算圖不僅僅可以用來隔離張量和計算,它還提供了管理張量和計算的機制。

 

在TensorFlow程序中,所有的數據都可以通過張量的形式來表示。從功能的角度來看,張量可以被簡單理解爲多維數組。其中零階張量表示標量(scalar),也就是一個數;第一階張量爲向量(vector),也就是一個一維數組;第n階張量可以理解爲一個n維數組。在張量中並沒有真正保存數字,它保存的是如何得到這些數字的計算過程。例如以下輸出結果:

Tensor("add:0", shape=(2,), dtype=float32)

會話擁有並管理TensorFlow程序運行時的所有資源,所有計算完成之後需要關閉會話來幫助系統回收資源,否則就可能出現資源泄露問題。以下代碼顯示其中一個會話使用模式:

with tf.Session() as sess:
    print(sess.run(result))

TensorFlow遊樂場使用鏈接:http://playground.tensorflow.org

 

在TensorFlow中,變量(tf.Variable)的作用就是保存和更新神經網絡中的參數,和其他編程語言類似,TensorFlow中的變量也需要指定初始值。因爲在神經網絡中,給參數賦予隨機初始值最爲常見,所以一般也使用隨機數給TensorFlow中的變量初始化。

 

以下代碼給出了一個完整神經網絡實現樣例,包含一個隱藏層。

import tensorflow as tf
from numpy.random import RandomState

batch_size = 8
w1= tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))
w2= tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))
x = tf.placeholder(tf.float32, shape=(None, 2), name="x-input")
y_= tf.placeholder(tf.float32, shape=(None, 1), name='y-input')

a = tf.matmul(x, w1)
y = tf.matmul(a, w2)
y = tf.sigmoid(y)
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)))
train_step = tf.train.AdamOptimizer(0.001).minimize(cross_entropy)
rdm = RandomState(1)
X = rdm.rand(128,2)
Y = [[int(x1+x2 < 1)] for (x1, x2) in X]

 

with tf.Session() as sess:
    init_op = tf.global_variables_initializer()
    sess.run(init_op)
   
    # 輸出目前(未經訓練)的參數取值。
    print(sess.run(w1))
    print(sess.run(w2))
    print("\n")
   
    # 訓練模型。
    STEPS = 5000
    for i in range(STEPS):
        start = (i*batch_size) % 128
        end = (i*batch_size) % 128 + batch_size
        sess.run([train_step, y, y_], feed_dict={x: X[start:end], y_: Y[start:end]})
        if i % 1000 == 0:
            total_cross_entropy = sess.run(cross_entropy, feed_dict={x: X, y_: Y})
            print("After %d training step(s), cross entropy on all data is %g" % (i, total_cross_entropy))
 
    # 輸出訓練後的參數取值。
    print("\n")
    print(sess.run(w1))
    print(sess.run(w2))

輸出結果:

[[-0.8113182   1.4845988   0.06532937]
 [-2.4427042   0.0992484   0.5912243 ]]
[[-0.8113182 ]
 [ 1.4845988 ]
 [ 0.06532937]]
 
After 0 training step(s), cross entropy on all data is 1.89805
After 1000 training step(s), cross entropy on all data is 0.655075
After 2000 training step(s), cross entropy on all data is 0.626172
After 3000 training step(s), cross entropy on all data is 0.615096
After 4000 training step(s), cross entropy on all data is 0.610309
 
[[ 0.02476983  0.56948674  1.6921941 ]
 [-2.1977348  -0.23668921  1.1143895 ]]
[[-0.45544702]
 [ 0.49110925]
 [-0.98110336]]

以上程序實現了訓練神經網絡的全部過程。這段程序可以總結出訓練神經網絡的過程可以分爲以下三個步驟:

(1)定義神經網絡的結構和前向傳播的輸出結果

(2)定義損失函數以及選擇反向傳播優化的算法

(3)生成會話(tf.Session),並且在訓練數據上反覆運行反向傳播優化算法

無論神經網絡的結構如何變化嗎,這三個步驟都是不變的。

 

 


第4章 深層神經網絡

維基百科對深度學習的精度定義爲“一類通過多層非線性變換對高複雜性數據建模算法的合集”。因爲深層神經網絡是實現“多層非線性變換”最常用的一種方法,所以在實際中基本上可以認爲深度學習就是深層神經網絡的代名詞。從維基百科給出的定義可以看出,深度學習有兩個非常重要的特性——多層和非線性。

 

如果在深層神經網絡中,前向傳播使用線性模型,那麼通過線性變換,任意層的全連接神經網絡和單層的神經網絡並沒有區別,而且他們都是線性模型。這就是線性模型最大的侷限性,也是爲什麼深度學習要強調非線性。

 

分類問題和迴歸問題是監督學習的兩大種類。分類問題希望解決的是將不同的樣本分到事先定義好的類別中。交叉熵刻畫了兩個概率分佈之間的距離,它是分類問題中使用比較廣泛的一種損失函數。

 

交叉熵是一個信息論中的概念,它原本是用來估計平均編碼長度的。給定兩個概率分佈p和q,通過q來表示p的交叉熵爲:

如何將神經網絡前向傳播得到的結果變成概率分佈呢?SOftmax迴歸是一個非常常用的方法。假設原始的神經網絡輸出爲

,那麼經過Softmax迴歸處理之後的輸出爲:

與分類問題不同,迴歸問題解決的是對具體數值的預測。比如房價預測、銷量預測等都是迴歸問題。對於迴歸問題,最常用的損失函數是均方誤差(MSE,mean squared error)。它的定義如下:

梯度下降算法主要用於優化單個參數的取值,而反向傳播算法給出了一個高效的方式在所有參數上使用梯度下降算法,從而使神經網絡模型在訓練數據上的損失函數儘可能小。反向傳播算法是訓練神經網絡的核心算法,它可以根據定義好的損失函數優化神經網絡中參數的取值,從而使神經網絡模型在訓練數據集上的損失函數達到一個較小值。

 

需要注意的是,梯度下降算法並不能保證被優化的函數達到全局最優解。而且,參數的初始值會很大程度影響最後得到的結果。只有當損失函數爲凸函數時,梯度下降算法才能保證達到全局最優解。梯度下降算法另一個問題就是計算時間太長,因爲要在全部訓練數據上最小化損失,所以損失函數J( )是在所有訓練數據上的損失和。

 

在訓練神經網絡時,需要設置學習率(learning rate)控制參數更新的速度。如果學習率設置過大,更新的幅度就比那大,那麼可能導致參數在極優值的兩側來回移動。如果學習率設置過小,會導致訓練的時間變長。爲了解決設定學習率的我呢提,TensorFlow提供了一種更加靈活的學習率設置方法——指數衰減法。tf.train.exponential_decay函數實現了指數衰減學習率。以下代碼給出了尋找 的最小值,使用梯度下降法來實現:

TRAINING_STEPS = 100
global_step = tf.Variable(0)
LEARNING_RATE = tf.train.exponential_decay(0.1, global_step, 1, 0.96, staircase=True)

 
x = tf.Variable(tf.constant(5, dtype=tf.float32), name="x")
y = tf.square(x)
train_op = tf.train.GradientDescentOptimizer(LEARNING_RATE).minimize(y, global_step=global_step)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for i in range(TRAINING_STEPS):
        sess.run(train_op)
        if i % 10 == 0:
            LEARNING_RATE_value = sess.run(LEARNING_RATE)
            x_value = sess.run(x)
            print ("After %s iteration(s): x%s is %f, learning rate is %f."% (i+1, i+1, x_value, LEARNING_RATE_value))

運行結果:

After 1 iteration(s): x1 is 4.000000, learning rate is 0.096000.
After 11 iteration(s): x11 is 0.690561, learning rate is 0.063824.
After 21 iteration(s): x21 is 0.222583, learning rate is 0.042432.
After 31 iteration(s): x31 is 0.106405, learning rate is 0.028210.
After 41 iteration(s): x41 is 0.065548, learning rate is 0.018755.
After 51 iteration(s): x51 is 0.047625, learning rate is 0.012469.
After 61 iteration(s): x61 is 0.038558, learning rate is 0.008290.
After 71 iteration(s): x71 is 0.033523, learning rate is 0.005511.
After 81 iteration(s): x81 is 0.030553, learning rate is 0.003664.
After 91 iteration(s): x91 is 0.028727, learning rate is 0.002436.

 

在真實應用中想要的並不是讓模型儘量模擬訓練數據的行爲,而是希望通過訓練出來的模型對未知的數據給出判斷。模型在訓練數據上的表現並不一定代表了它在未知數據上的表現。過擬合,指的是當一個模型過爲複雜之後,它可以很好地”記憶“每一個訓練數據中隨機噪音的部分而忘記了要去“學習”訓練數據中通用的趨勢。

爲了避免過擬合問題,一個非常常用的方法時正則化(regularization)。正則化的思想就是在損失函數中加入刻畫模型複雜程度的指標。常用的刻畫模型複雜度的函數R(w)有兩種,一種時L1正則化,計算公式是:

另一種是L2正則化,計算公式是:

無論是哪一種正則化方法,基本的思想都是希望通過限制權重的大小,使得模型不能任意擬合訓練數據中的隨機噪音。但這兩種正則化的方法也有很大的區別。首先,L1正則化會讓參數變得更稀疏,而L2正則化不會讓參數變得稀疏的原因是當參數很小時,例如0.001,這個參數的平方基本上就可以忽略了。

 

在採用隨機梯度下降算法訓練神經網絡時,使用滑動平均模型在很多應用中都可以在一定程度提高最終模型在測試數據上的表現。在TensorFlow中提供了tf.train.ExponentialMovingAverage來實現滑動平均模型。在初始化ExponentialMovingAverage時,需要提供一個衰減率(decay)。這個衰減率將用於控制模型的更新速度。在實際應用中,decay一般會設置成非常接近1的數(例如0.999或者0.9999)。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章