我們要解決的是一個過於簡單且不現實的問題,但其好的一面是便於我們瞭解機器學習和 TensorFlow 的概念。我們要預測一個基於單一特徵(房間面積/平方米)的單標量輸出(房價/美元)。這樣做消除了處理多維數據的需要,使我們能夠在 TensorFlow 中只專注於確定、實現以及訓練模型。
我們從一組收集到的數據點開始(見下圖),每個數據點代表兩個值之間的關係——輸出(房價)與影響因素(房子面積)。
然而我們無法預測沒有數據點的特徵的值(見下圖)。
我們可以使用機器學習來挖掘它們之間的關係(見下圖的「最佳擬合預測曲線」),即給定一個不屬於數據點的特徵值,我們可以準確地預測出輸出(特徵值和預測線的交點)。
為了使用機器學習來做預測,我們需要選擇一個能夠擬合收集到的數據的最佳模型。
我們可以選擇一個線性(直線)模型,並通過改變其陡度/梯度和位置對其進行調整,從而匹配數據點。
我們也可以選擇一個指數(曲線)模型,並通過改變其曲率(curvature)和位置對其進行調整,從而匹配同一數據點集。
為了比較哪個模型擬合得更嚴密,數學上我們將最佳擬合定義為一個需要被最小化的成本函數。 成本函數的一個簡單樣例是每個數據點所代表的實際輸出與預測輸出之間偏差的絕對值總和(實際結果到最佳擬合曲線的垂直投影)。用圖表表示,成本函數被描述為下表中藍色線段的長度和。
注意:更準確地說,成本函數往往是實際輸出和預測輸出之間的方差,因為差值有時是負數;這也稱為最小二乘法。
秉持簡潔精神,我們將使用線性模型來對數據點進行建模。線性模型的數學表示是:
為了調整模型來更好地擬合數據點,我們可以這樣做:
調整 W 來改變線性模型的梯度
調整 b 來改變線性模型的位置
通過使用許多個 W、b 的值,最終我們可以找到一個最佳擬合線性模型,能夠將成本函數降到最小。
除了隨機嘗試不同的值,有沒有一個更好的方法來快速找到 W、b 的值?
如果你試圖從山上下降到最低點,你的視角就是這個樣子。
下降趨勢並不明顯!其最佳方式是執行梯度下降:
在當前位置以最陡的下降梯度確定方向
在該方向上採取步長 X
重複 & 刷新;這就是訓練過程
最小化成本函數是類似的,因為成本函數就像是起伏的山,我們想要找到其中的最低點,我們可以通過梯度下降類似地實現。
現在我們有了線性模型、成本函數和梯度下降的概念,可以開始使用 TensorFlow 了。
TensorFlow 的2個基本組件是:
佔位符(Placeholder):表示執行梯度下降時將實際數據值輸入到模型中的一個入口點。例如房子面積 (x) 和房價 (y_)。
變量:表示我們試圖尋找的能夠使成本函數降到最小的「good」值的變量,例如 W 和 b。
然後 TensorFlow 中的線性模型 (y = W.x + b) 就是:
與將數據點的實際房價 (y_) 輸入模型類似,我們創建一個佔位符。
成本函數的最小方差就是:
由於沒有房價(y_) 和房子面積 (x) 的實際數據點,我們就生成它們。
簡單起見,我們將房價 (ys) 設置成永遠是房子面積 (xs) 的 2 倍。
有了線性模型、成本函數和數據,我們就可以開始執行梯度下降從而最小化代價函數,以獲得 W、b 的「good」值。
0.00001 是我們每次進行訓練時在最陡的梯度方向上所採取的「步」長;它也被稱作學習率(learning rate)。
訓練包含以預先確定好的次數執行梯度下降,或者是直到成本函數低於某個預先確定的臨界值為止。
1.TensorFlow 的怪異
所有變量都需要在訓練開始時進行初始化,否則它們可能會帶有之前執行過程中的殘餘值。
2.TensorFlow 會話
雖然 TensorFlow 是一個 Python 庫,Python 是一種解釋性的語言,但是默認情況下不把 TensorFlow 運算用作解釋性能的原因,因此不執行上面的 init 。相反 TensorFlow 是在一個會話中進行;創建一個會話 (sess) 然後使用 sess.run() 去執行。。
類似地我們在一個循環中調用 withinsess.run() 來執行上面的 train_step。
你需要將由 x, y_ 所組成的實際數據輸入再提供給輸入,因為 TensorFlow 將 train_step 分解為它的從屬項:
從屬項的底部是佔位符 x,y_;而且正如我們之前提到的,tf.placeholders 是用來表示所要提供的實際數據點值房價 (y_) 和房子面積 (x) 的位置。
結果
循環中的 print 語句將顯示 TensorFlow 如何在每次迭代中學習 W 和 b 的「good」值。
我們已經以最簡單的形式學習了機器學習;從一個單一特徵預測結果。(為簡單起見)我們選擇了一個線性模型來擬合我們的數據點,定義一個成本函數來表示最佳擬合,並通過反覆調整其梯度變量 W 與位置變量 b 來訓練我們的模型,使成本函數降到最小。
代碼: Github
幻燈片: SlideShare
視頻: YouTube
在上一部分,我們使用 TensorFlow 構建並學習了一個帶有單一特徵的線性迴歸模型——給定一個特徵值(房屋面積/平方米),我們可以預測輸出(房價/美元)。
下面是一些總結:
我們有一些房屋面積和房價的數據(灰色點)
我們使用線性迴歸對這些數據進行了建模(紅色虛線)
我們通過訓練該線性迴歸模型的 W(權重)和 b(偏置)找到了最小化「成本」(豎直藍色實線的長度總和,這些藍線代表了預測和實際輸出之間的差異)的「最好」模型
給定任意房屋面積,我們可以使用該線性模型預測房價(帶箭頭的藍色虛線)
一張圖解釋線性迴歸
在機器學習文獻中,我們常常看到「訓練(training)」這個詞。在這一部分,我們將在 TensorFlow 中理解「訓練」的含義。
線性迴歸建模
線性迴歸的目標是尋找 W 和 b,這樣對於給定的任意特徵值 x,我們可以通過將 W、b 和 x 的值代入到模型中得到預測 y。
但是為了找到能準確做出預測的 W 和 b 的值,我們需要使用可用的數據(許多實際特徵 x 和實際輸出 y_ 的配對,注意下劃線)來「訓練」該模型。
解釋「訓練」
為了找到最佳的 W 和 b 值,我們可以從任意的 W 和 b 值開始。我們也需要定義一個成本函數,該函數可以衡量對於一個給定特徵值 x 預測輸出 y 和實際輸出 y_ 之間差異。為了簡單起見,我們使用最簡單的最小均方誤差(MSE:minimum squared error)作為我們的成本函數。
通過最小化成本函數,我們可以得到很好的 W 和 b 值。
我們的訓練代碼實際上非常簡單,並且用 [A, B, C, D] 進行了註釋,後面我們還會談到這些代碼。完整代碼請訪問:https://github.com/nethsix/gentle_tensorflow/blob/master/code/linear_regression_one_feature_using_mini_batch_with_tensorboard.py
我們的線性模型和成本函數[A]可以表示成下面的 TensorFlow 圖:
創造一個帶有模型和成本函數的 TensorFlow 圖,並使用一些值初始化 W 和 b
接下來,我們選擇一個數據點 (x, y_) [C],然後將其送入[D] TensorFlow 圖,從而得到預測 y 和相應的成本。
使用單個數據點計算預測 y 和成本
為了得到更好的 W 和 b,我們使用TensorFlow 的 tf.train.GradientDescentOptimizer [B]執行梯度下降以降低成本。用非技術的術語來說:給定當前成本,並基於成本歲其它變量(即 W 和 b)的變化方式,優化器(optimizer)將對 W 和 b 執行一些小調整(遞增或遞減)以使我們的預測更好地契合那個單個數據點。
基於當前的成本,決定如何調整 W 和 b 以提升預測 y 和降低成本
訓練週期中的最後步驟是在調整 W 和 b 對它們進行更新。注意這裡的「週期」用機器學習的術語來說是「epoch」。
在下一訓練 epoch 的迭代前,通過調整 W 和 b 對它們進行更新
在下一訓練 epoch 中,重複這些步驟,但使用一個不同的數據點!
使用不同的數據點進行訓練
使用各種數據點泛化(generalize)我們的模型,即學習可被用於預測任何特徵值的 W 和 b 值。注意:
在大部分情況下,數據點越多,模型的學習和泛化就越好
如果你訓練的 epoch 比數據點還多,你可以重複使用數據點,這不成問題。梯度下降優化總是會同時使用數據點及其成本(根據該 epoch 的 W 和 b 值從數據點中計算得到)來對 W 和 b 值進行調整;該優化器也許之前已經見過了這個數據點,但成本並不一樣,因此它還是可以學到新的東西,並以不同的方式調整 W 和 b 值。
你可以用固定數量的 epoch 訓練一個模型,直到其達到令人滿意的成本閾值。
訓練變量1.隨機、mini-batch、batch
在上面的訓練中,我們在每個 epoch 送入單個數據點。這被稱為隨機梯度下降(stochastic gradient descent)。我們也可以在每個 epoch 送入一堆數據點,這被稱為 mini-batch 梯度下降,或者甚至在一個 epoch 一次性送入所有的數據點,這被稱為 batch 梯度下降。請看下圖的比較,注意這 3 張圖的 2 處不同:
每個 epoch 送入 TensorFlow 圖(TF.Graph)的數據點的數量(圖右上方)
梯度下降優化在調整 W 和 b 值時所考慮的數據點的數量(圖右下方)
隨機梯度下降
mini-batch 梯度下降
batch 梯度下降
每張圖中的數據點的數量有 2 個含義。當數據點更多時:
計算成本和執行梯度下降所需的計算資源(減法、平方、加法)會增加
模型的學習和泛化的速度增加
選擇隨機、mini-batch、batch 梯度下降的優缺點總結在下圖中:
選擇隨機、mini-batch、batch 梯度下降的優缺點
要在隨機/mini-batch/batch 梯度下降之間切換,我們只需要在將數據點送入訓練步驟[D]之前將這些數據點分成不同的 batch 大小,即為 [C] 使用如下的代碼片段:
2.學習率變化
學習率(learn rate)是指梯度下降調整 W 和 b 遞增或遞減的速度。學習率較小時,處理過程會更慢,但肯定能得到更小成本;而當學習率更大時,我們可以更快地得到最小成本,但有「衝過頭」的風險,導致我們沒法找到最小成本。
為了克服這一問題,許多機器學習實踐者選擇開始時使用較大的學習率(假設開始時的成本離最小成本還很遠),然後隨每個 epoch 而逐漸降低學習率。
TensorFlow 提供了 2 種方法可以做到這一點,詳細解釋可參考:http://stackoverflow.com/questions/33919948/how-to-set-adaptive-learning-rate-for-gradientdescentoptimizer;但這裡進行了總結。
使用梯度下降優化的變體
TensorFlow 帶有多種支持學習率變化的梯度下降優化器,例如 tf.train.AdagradientOptimizer 和 tf.train.AdamOptimizer.
使用 tf.placeholder 調整學習率
如同前面所看到的,如果我們在這個例子中聲明瞭 tf.placeholder 來設置學習率,然後在 tf.train.GradientDescentOptimizer 中使用它,我們可以在每個訓練 epoch 向其送入一個不同的值,這很像我們給 x 和 y_ 送入不同的數據點,這也是每個 epoch 的 tf.placeholders.
我們需要 2 個小修改:
小結
我們解釋了機器學習中「訓練(training)」的含義,以及在 TensorFlow 中通過模型和成本定義、然後循環通過訓練步驟(將數據點送入梯度下降優化器)來進行訓練的方式。我們還討論了訓練中的常見變量,即改變模型學習時每個 epoch 所用的數據點的大小和改變梯度下降優化器的學習率。
後續內容
創建 Tensor Board 來可視化 Tensorflow 的執行,從而檢測我們的模型、成本函數或梯度下降中的問題
使用多個特徵表達線性迴歸