近年來,Machine Learning 在許多領域上已然取得了可喜的成就,很是火熱。就我我的來說,有意將業餘 Sport Programming 的範圍擴展一下,譬如 Topcoder Marathon。在解決實際問題中,方法太 Naive 每每效果不怎麼樣,依舊須要學習一下相關的基礎知識。
本系列文章主要基於 Coursera 的 Machine Learning,我社內部 Machine Learning 課裏能說的一部分,wikipedia,以及一些其餘的讀物。算法
對於某類任務T和性能度量P,若是一個計算機程序在T上以P衡量的性能隨着經驗E而自我完善,那麼咱們稱這個計算機程序從經驗E中學習。
這是一個比較嚴謹的界定機器學習問題的 Guideline。若是有什麼問題搞不清楚是否是這個範疇,能夠嘗試套用定義來檢查:任務是什麼,性能度量是什麼,經驗是什麼,性能是否因爲經驗而提高。機器學習
我的理解,模型表明着你如何看待這個問題。譬如識別一個東西是否是汽車,若是你認爲識別的依據是:金屬殼 + 車燈 + 反光鏡 + 車輪子 … = 汽車,這個思路就比較接近基於規則,決策樹,貝葉斯;若是你考慮這個東西和見過的什麼東西比較類似,就是 KNN 的思路。以後咱們要不斷學習的實際上都是模型。ide
常見的兩個策略是經驗風險最小化和結構風險最小化。經驗風險最小化意味着咱們傾向於對訓練數據取得精準的預測。這個想法很直接,且有必定道理:模型在訓練數據上表現不佳,更沒法期望在測試數據上取得好結果。可是,在訓練集上表現好的模型,未必在測試集上表現好。一般來說,簡單的模型會更有通用性,而複雜的模型,每每會有一些 hardcode 了訓練數據的感受,效果反而不必定好。結構風險最小化在經驗風險最小化的狀況下,加入一些因子來限制模型的複雜度。函數
根據策略,能夠列出一個須要最優化的式子。算法就是求這個式子最優或者較優解的方法。最多見的方法是梯度降低,其餘技能尚未 get,就暫不討論了。性能
暫時忘記機器學習,如今須要優化一個形如 \( y = f(\theta) \) 的式子,求 \( x = argmax f(\theta) \) 或 \( x = argmin f(\theta) \),有什麼好的辦法麼?
梯度降低法,基於這樣的觀察:若是實值函數\( F(x) \)在點 a 處可微且有定義,那麼函數 \( F(x) \)在 a 點沿着梯度相反的方向 \( -F\nabla(a) \) 降低最快。所以,若是 \( b = a - \gamma\nabla F(a) \) 對於 \( \gamma > 0 \) 且爲一個夠小數時成立,那麼 \( F(a) \geq F(b) \)。換句話說,咱們給出一個對極值的估計 a,不斷迭代求 \( a = a - \gamma\nabla F(a) \) ,就能取得一個極值。學習
用一個實際例子來演示一下:對二次函數 \( f(y) = x^{2} + 2x + 10 \) ,使用梯度降低法求 \( min f(x) \) 和 \( argmin f(x) \),函數圖像以下:測試
結論不管是從圖像仍是初中數學的角度來看都很簡單。咱們看看梯度降低算法是如何進行的:優化
f <- function(x) { x^2 + 2 * x + 10 } df <- function(x) { 2 * x + 2 } x <- 5 y <- f(x) learning.rate <- 0.3 plot(f, -5, 5) while (TRUE) { nx = x - df(x) * learning.rate ny = f(nx) if (abs(x - nx) < 0.01) break arrows(x, y, nx, ny, col = "red") x = nx y = ny print(c(x, ny)) }
## [1] 1.40 14.76 ## [1] -0.040 9.922 ## [1] -0.616 9.147 ## [1] -0.8464 9.0236 ## [1] -0.9386 9.0038 ## [1] -0.9754 9.0006 ## [1] -0.9902 9.0001
不管是簡單問題仍是複雜問題,參數 learning.rate,也就是前文中提到的\( \gamma \)的選擇很是重要。Learning rate 太小則須要更多的迭代。Learning rate 過大則會出現之字降低,甚至之字上升。網站
看一個非凸,多元函數的例子:Rosenbrock函數:\( f(x, y) = (1-x)^2 + 100(y-x^2)^2 \) 很顯然 x = y = 1 的時候能夠取得最優解,可是求解過程倒是很坑的。我們把 x = y = 1 附近的圖像畫出來:ui
再研究一下 x = 1 時的切面:
大概能看出來,這個函數在解附近有個很大的很平的底。。。貼一段代碼,你們能夠 play 一下:
f <- function(x, y) { (1 - x) ** 2 + 100 * (y - x ** 2) ** 2} df.dx <- function(x, y) { x * 2 - 2 - 400 * y + 400 * x ** 3} df.dy <- function(x, y) { 200 * y - 200 } x <- runif(1, 0, 2) y <- runif(1, 0, 2) z = f(x, y) learning.rate = 1E-6 eps <- 1E-10 while (TRUE) { new.x = x - df.dx(x, y) * learning.rate new.y = y - df.dy(x, y) * learning.rate new.z = f(new.x, new.y) if (abs(new.z - z) < eps) break x = new.x y = new.y z = new.z print(c(x, y, z)) }
能夠調整一些參數,譬如 learning.rate,eps 去看看某些現象。咱們能夠看到他最後幾步的收斂極爲緩慢,若是 learning.rate 過大,還會之字上升等等。總的來說,選擇一個合適的 learning rate 是很是重要的,除去經驗性的技巧,每每也只好枚舉了,看看 cost function 的變化狀況,若是降低過慢,則須要增大 learning rate,若是反而增加了,則須要減小 learning rate。這也就是爲何某些時候咱們須要一個比較小的 validate set,咱們能夠按期的在訓練中的模型上跑一下 validate set,看一下 cost function 的變化,從而決定 learning rate 的調整。
以 Stanford Machine Learning 爲例:根據房子的面積預測房價。我們來把一些概念對上號:
策略:\[ minimize J(\theta_{0}, \theta_{1}) = \sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \]
算法:注意此時咱們要求解的是 \( \theta_{0},\theta_{1} \),而 \( x_{i},y_{i} \) 都是已知量,能夠考慮求偏導,而後用梯度降低求解,這就是技能範圍之內的東西了,由於每次迭代用了全部的 Training Data,因此這個作法叫 Batch Gradient Descent。
實際應用中,比較好用的算法是 Stochastic Gradient Descent,Batch Gradient Descent 每次迭代,對 \( \sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \) 求導,至關於 \[ \theta_{0} = \theta_{0} - 2\alpha\sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})x_{i} \] \[ \theta_{1} = \theta_{1} - 2\alpha\sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i}) \] 而 Stochastic Gradient Descent 至關與把 Batch Gradient Descent 的 1 次迭代拆成了 m 次,每次對 \( (\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \) 求導,而後 \[ \theta_{0} = \theta_{0} - 2\alpha(\theta_{0}x_{i} + \theta_{1} - y_{i})x_{i} \] \[ \theta_{1} = \theta_{1} - 2\alpha(\theta_{0}x_{i} + \theta_{1} - y_{i}) \]
Batch Gradient Descent 能夠求得更精確的解,可是若是模型複雜,或者數據量大,就很難直接 Batch Gradient Descent 了。