TensorFlow從0到1丨 第五篇:TensorFlow輕鬆搞定線性迴歸
上一篇 第一個機器學習問題 其實是一個線性迴歸問題(line regression),呈現了用資料來訓練模型的具體方式。本篇從平行世界返回,利用TensorFlow,重新解決一遍該問題。
TensorFlow的API有低階和高階之分。
底層的API基於TensorFlow核心,它主要用於研究或需要對模型進行完全控制的場合。如果你想使用TF來輔助實現某個特定演算法、呈現和控制演算法的每個細節,那麼就該使用低階的API。
高階API基於TensorFlow核心構建,遮蔽了繁雜的細節,適合大多數場景下使用。如果你有一個想法要驗證並快速獲得結果,那麼TF的高階API就是高效的構建工具。
本篇使用TF的低階API來呈現線性迴歸的每一個步驟。
第一個機器學習的TF實現
TensorFlow的計算分為兩個階段:
- 構建計算圖
- 執行計算圖
先給出“平行世界”版本,(a, b)初始值為(-1, 50),第二次嘗試(-1, 40)
程式輸出:
上面的python程式碼利用了在2 TensorFlow核心基礎 介紹的基本API實現了“第一個機器學習問題”。程式碼通過一步步構造計算圖,最後得到了loss節點。loss即4 第一個機器學習問題中定義過的損失函式,這裡再次給出其定義:
構建好計算圖,接下來開始執行。執行loss節點(同時提供基於tf.placeholder的訓練資料),得到loss的值為50。然後開始第二次訓練,修改基於tf.Variable的a和b的值,再次執行loss節點,loss的值為0,降到了最低。此時的a和b就是最佳的模型引數了。
還記得那個神祕力量嗎?到底是什麼讓機器在第二次訓練中將模型引數(a, b)的值從初始的隨機值(-1, 50)遷移到最優的(-1, 40)?如果不靠運氣的話,機器如何能自動的找到最優解呢?
梯度下降演算法
在此之前,或許你已經想到了隨機窮舉的辦法,因為機器不怕累。這的確是個辦法,但面臨的挑戰也不可接受:不可控。因為即便是隻有2個引數的模型訓練,其列舉域也是無限大的,這和靠運氣沒有分別。運氣差的話,等個幾百年也說不定。
不繞圈子,那個神祕力量就是:梯度下降演算法(gradient descent)。雖然它也是讓機器一小步一小步的去嘗試不同的(a, b)的組合,但是它能指導每次前進的方向,使得每嘗試一組新的值,loss就能變小一點點,直到趨於穩定。
而這一切TF已經把它封裝好了。 本篇先把它當個黑盒子使用。
tf.train API
程式碼幾乎和TensorFlow Get Started官方程式碼一致,主要區別在於訓練資料不同,以及初始值不同。
- TF官方的訓練資料是x_train = [1, 2, 3, 4],y_train = [0, -1, -2, -3],而我們的訓練資料是“平行世界”的觀察記錄x_train = [22, 25, 28, 30],y_train = [18, 15, 12, 10]。
- TF官方的(a, b)初始值是(.3, -.3), 我們的是(-1., 50.)。
- 或許你還發現在官方版本的loss函式末尾沒有
/ 8
,是因為我使用均方差的緣故,8由4x2得到(4個訓練資料)。
重點說下tf.train API。tf.train.GradientDescentOptimizer即封裝了梯度下降演算法。梯度下降在數學上屬於最優化領域,從其名字Optimizater也可體現出。其引數就是“學習率”(learning rate),先記住這個名詞,暫不展開,其基本的效用是決定待調整引數的調整幅度。學習率越大,調整幅度越大,學習的越快。反之亦然。可也並不是越大越好,是相對來說的。先取0.01。
另一個需要輸入給梯度下降演算法的就是loss,它是求最優化解的主體,通過optimizer.minimize(loss)傳入,並返回train節點。接下來在迴圈中執行train節點即可,迴圈的次數,即訓練的步數。
執行計算圖,程式輸出:
這個結果令人崩潰,僅僅換了下TF官方get started中例子中模型的訓練資料和初始值,它就不工作了。
先來看看問題在哪。一個除錯的小技巧就是列印每次訓練的情況,並調整loop的次數。
程式輸出:
TF實際是工作的,並沒有撂挑子。只是它訓練時每次調整(a, b)都幅度很大,接下來又矯枉過正且幅度越來越大,導致最終承載a和b的tf.float32溢位而產生了nan。這不是TF的一個bug,而是演算法本身、訓練資料、學習率、訓練次數共同導致的(它們有個共同的名字:超引數。)。可見,訓練是一門藝術。
直覺上,初始值或許有優劣之分,或許是離最優值越近的初始值越容易找到。可是訓練資料則應該是無差別的吧?實則不然。但是現在我還不打算把它解釋清楚,等後面分析完梯度下降演算法後再回來看這個問題。
遇到該問題的也不再少數,Stack Overflow上已經很好的回答了。我們先通過調整學習率和訓練次數來得到一個完美的Ending。
把學習率從0.01調製0.0028,然後將訓練次數從1000調整至70000。
程式輸出:
最終程式碼如下:
TensorBoard
TF的另一個強大之處就是視覺化演算法的TensorBoard,把構造的計算圖顯示出來。圖中顯示,每一個基本運算都被獨立成了一個節點。除了圖中我標註的Rank節點、range節點,start節點、delta節點外,其他節點都是由所寫程式碼構建出來的。
TensorBoard
詞彙表
- derivative; 導數;
- estimator: 估計;
- gradient descent: 梯度下降;
- inference: 推理;
- line regression:線性迴歸;
- loss function: 損失函式;
- magnitude: 量;
- optimal: 最優的;
- optimizers: 優化器;