1. 程式人生 > >帶你入門機器學習

帶你入門機器學習

簡單 oss 運行 自動 oom 不可 ida 暫時 數據集

什麽是機器學習?

機器學習的核心思想是創造一種普適的算法,它能從數據中挖掘出有趣的東西,而不需要針對某個問題去寫代碼。你需要做的只是把數據“投餵”給普適算法,然後它會在數據上建立自己的邏輯。

比如說有一種算法,叫分類算法,它可以把數據分到不同的組別當中。一個識別手寫數字的分類算法,也可以用作判斷垃圾郵件,而無需修改一行代碼。算法是同一個算法,只是輸入了不同的訓練數據,便有了不同的分類邏輯。

技術分享圖片機器學習算法是個黑盒,且可以在不同分類問題中重復利用。

“機器學習”是個筐,什麽普適算法都往裏裝。


兩種機器學習算法

機器學習主要分為兩類——有監督學習和無監督學習,區別很簡單,卻很關鍵。

有監督學習

想想你是一家房產中介。你的業務正在增長,所以雇了一幫實習銷售來助拳。那麽問題來了——身經百戰的你,一眼就看穿一棟房子價值幾何,但是實習生可沒有這樣豐富的人生經驗,所以摸不準行情。

為了輔助實習生(以便解放自己度個假),你決定做個小程序,基於面積、周邊環境、相似房產成交價等等,來預估本地的房價。

所以你把3個月來本市的每一筆交易都拿小本本記了下來。對每處房產都整理了一大堆細節——房間數、面積、周邊環境等等,當然最重要的是,最終成交價:

技術分享圖片這就是我們的“訓練數據”

有了訓練數據,我們就想搞個程序去預估其他的房價:

技術分享圖片用訓練數據去預測別的房屋價格

這就是有監督學習。你是知道每處房產到底賣多少的,換言之,問題的答案是已知的,邏輯是可以反推的。

為了開發小程序,把每處房產的訓練數據導進機器學習算法裏,算法試圖摸索出其中的數學規律。

這有點像是去掉了符號的算術題答案:

技術分享圖片Oh no!一個熊孩子把參考答案裏的運算符號給塗沒了!

根據上圖,你能否推算出這些題目的原貌呢?顯然,我們需要對這些數字“動點手腳”,以使等式成立。

在有監督學習中,我們做的實際上就是讓電腦代替人來讓等式成立。一旦你學會了解決某一類問題,那麽這類問題裏的任何子問題都就迎刃而解了!

無監督學習

回到最開始那個賣房地產的例子。如果我們不知道具體每處房產的價格可咋整?即使僅知道面積、位置等信息,你也依然可以搞點動靜出來,這就叫無監督學習。

技術分享圖片即使不預測未知數(比如房價),機器學習也能帶來有趣的結論

這就好比有人給你一張紙,上面寫著一串數字,然後說“我也不知道啥意思,你可以猜猜這是什麽套路——好運!”

這些數據我們能做什麽呢?對於新手來講,可以得到一個算法,從數據中自動辨識出細分的市場定位。可能你會發現,當地大學附近的購房者偏好多臥室的小房子,而郊區的購房者則傾向於大套三。了解到不同類型消費者的存在可以指導市場行為。

另一個可以做的就是自動識別出那些少有相似點的特異房產。可能這些特異房產是豪華公館,那麽就可以調配最好的銷售人員專門負責這些大買賣。

後文主要專註於有監督學習,但並非因為無監督學習的作用小或者趣味少。實際上無監督學習的重要性與日俱增且發展迅速,因為不需要事先對正確答案對應的數據加標簽。

註:還有很多其他種類的機器學習算法,不過建議從這些基礎算法入手。


哎喲不錯,但是真的有可能“學習”到真實的房價嗎?

作為一個人類,你的大腦可以面對各種形勢,並且在無明確指導的情況下自主學習如何應對。如果你賣了很久的房子,就會慢慢地對房價、對銷售策略、對觀察客戶等問題產生一種“感覺”。強人工智能研究的目的就在於讓計算機掌握這種能力。

但是當前的機器學習算法還沒那麽厲害——它們只能對很具體、有限的問題生效。或許這裏的“學習”更應該定義為“基於樣本數據得出解決具體問題的等式”。

不幸的是,“讓機器基於樣本數據得出解決具體問題的等式”不是個好名字,所以我們還是回到了“機器學習”。

當然如果你在50年後,強人工智能都普及了時候看到本文,會覺得全文都很“古典”。別看了,讓你的機器人給你拿個包子吃,未來人類。


放碼過來!

然,上面例子裏的預測房價程序應該怎麽寫呢?思考一秒,然後接著看。

如果你對機器學習一無所知,可能會嘗試依照預測房價的基本規律,寫出如下代碼(此代碼可以在我們的網站上直接運行和修改https://jizhi.im/blog/post/ml_is_fun_01):

[python] view plain copy
  1. def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
  2. price = 0
  3. # 這一片的均價是200美元一平米
  4. price_per_sqft = 200
  5. if neighborhood == "hipsterton":
  6. # 有的區更貴
  7. price_per_sqft = 400
  8. elif neighborhood == "skid row":
  9. # 有的區便宜
  10. price_per_sqft = 100
  11. # 根據基準價和面積預測實際價格
  12. price = price_per_sqft * sqft
  13. # 根據房間數調整預測
  14. if num_of_bedrooms == 0:
  15. # 公寓稍微便宜點
  16. price = price?—?20000
  17. else:
  18. # 臥室多的房子貴
  19. price = price + (num_of_bedrooms * 1000)
  20. return price



如果順著寫上幾個小時,或許也能得到一個能跑的程序。但勢必存在隱患,而且無法應對價格變化。

如果計算機能自己發現如何應用這些方程,那豈不是好得多?只要能得到正確的數字,誰管具體方程是什麽呢?

[python] view plain copy
  1. def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
  2. price = 賈維斯,幫我算一下
  3. return price



這個問題可以想象成:價格是道燉菜,配方是臥室數量,面積和周邊環境。如果你能算出每種成分對最終價格的影響是多少,或許那就是配方“攪合”最終價格的確切權重。

這可以使原程序(滿是if/else)變得簡單如下:

[python] view plain copy
  1. def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
  2. price = 0
  3. # 加少許配方1
  4. price += num_of_bedrooms * .841231951398213
  5. # 加大把配方2
  6. price += sqft * 1231.1231231
  7. # 適量的配方3
  8. price += neighborhood * 2.3242341421
  9. # 最後來點鹽
  10. price += 201.23432095
  11. return price



註意這些奇妙深刻的加粗數字——.841231951398213、 1231.1231231、2.3242341421和201.23432095,這就是我們的權重。只要我們能找到準確的權重,那就可以預測房價了。

一個比較粗暴的權重計算方法大致如下:

第一步:

把所有權重都設為1.0:

[python] view plain copy
  1. def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
  2. price = 0
  3. # 加少許配方1
  4. price += num_of_bedrooms * 1.0
  5. # 加大把配方2
  6. price += sqft * 1.0
  7. # 適量的配方3
  8. price += neighborhood * 1.0
  9. # 最後來點鹽
  10. price += 1.0
  11. return price



第2步:

把每個房產的參數代入公式,計算預測結果和實際價格的誤差:

技術分享圖片用你的方程來猜房價

比如第一個房子實際賣了178,000,但這一個房子就少了$72,000。

現在把每個房子對應誤差的平方加起來,比方你有500單交易,那麽誤差的平方和就有$86,123,373,可謂謬以千裏。再把平方和除以500得到平均每個房子的誤差,這一平均誤差值就是方程的代價(即最小二乘法,平方是為了防止誤差正負相抵)。

如果我們能通過調整權重將代價降為零,那方程就完美了。這表示在所有例子中,方程都準確無誤地基於輸入數據猜中了房價。這就是我們的目標——嘗試不同的權重,讓代價盡量低。

第3步:

不斷地重復第2步,嘗試每一種可能的權重值組合。哪個組合能讓代價最接近於0就選哪一組。找到那一組權重,就解決了問題!


腦洞時間

挺簡單的對吧?回想一下剛才的所做,拿到一些數據,填進三個普適的、簡單的步驟裏,然後得到一個能猜房價的方程。Zillow(美國房價預測網站)面臨著嚴重的威脅!

但是有這麽幾個激動人心的事實:

  1. 過去40年裏,很多領域(如語言學/翻譯學)的研究已經表明,“攪合數字燉菜”(作者自己打的比方)的普適性學習算法已經超越了那些,由真人嘗試自己發現顯式規律的人方法。機器學習的“暴力”方法最終擊敗了人類專家。

  2. 剛才得出的方程其實是很笨的。它並不知道“平方米”和“臥室”到底是什麽,它只知道“攪拌”多少數字可以得到正確答案。

  3. 你大概並不知道為什麽某一組權重就是好的,而只是寫了一個自己都不明白的方程,但卻證明是好用的。

  4. 假設我們不用“平方米”和”臥室數“這些參數,而是讀入一個數列。比方說每個數字代表的是”從車頂上拍的照片的某一像素的亮度”,然後我們預測的結果也不是“房價”了,而是“方向盤轉過的角度”。這就是一個人自動駕駛的風方程了?

瘋了,對吧?


第3步的“嘗試每個數字”

當然你不可能真的嘗試每一種可能權重組合來尋找最優解,實際情況是永遠嘗試不完。

為了避免這一情況,數學家們發現了很多機智辦法來盡快找到一個不錯的結果。以下就是其中一種:

第一,寫一個能夠代表上面“第2步”的方程:

技術分享圖片這就是代價函數

然後用機器學習界的黑話(暫時可以忽略)重新寫一遍:

技術分享圖片代表當前權重。是當前權重的代價值。

這個等式代表了在當前的權重組合下,我們的價格預測有多麽離譜。

如果把房間數和平方米所有可能權重值可視化,可以得到類似下圖的圖像:

技術分享圖片代價函數的圖像像個碗。豎直軸表示代價。

這個圖裏的藍色最低點就是代價的最低點——方程誤差最小處,最高點即是最離譜的情況。所以如果我們找到一組權重值,使得方程對應最低點,那就是答案!

技術分享圖片

所以我們只需要以“下山”的方式來調整權重,逼近最低點。如果每一次微小的調整都向著最低點進發,那遲早能夠到達。

函數的導數就是切線的斜率,換句話說,這告訴我們哪條路可以“下山”。

因此如果計算代價函數對每個權重的偏微分,然後再從權重裏減去這個值,這可以讓我們離谷底更近。重復執行,最終我們會到達谷底並獲得權重的最優解(如果沒看懂,不要擔心,繼續看)。

這是一種尋找方程最佳權重方式的高度概括,叫作批梯度下降(batch gradient descent)。如果你對此感興趣,不要害怕,了解更多細節。

當你使用機器學習庫來解決實際問題的時候,這些都會自動完成,但是了解究竟發生了什麽還是很有用的。


還略過了什麽?

上述的三步算法即是多變量線性回歸,針對一條穿過房產數據的直線來進行預測目標等式,並用這一等式去猜測此前未曾見過的房屋價格,解決實際問題的時候這非常行之有效。

但是以上方法或許只對特別簡單的例子好使,並非萬金油。其中一個原因就是房價不總是簡單到能用一條連續直線來代表。

好在另有很多方法解決,很多機器學習算法可以處理非線性數據(如神經網絡 或 有核 的支持向量機)。同樣也有算法是以更加聰明的方式使用線性回歸以擬合更復雜的直線。但不論哪一方法,最根本的思想都是找到最佳的權重。

並且我忽略了過擬合問題。對於已有的原始數據,找到一組很棒的權重值不難,但是卻有可能對訓練集以外新的房子不適用。有很多方法可以避免這一現象(如正則化和使用交叉驗證數據集),這是成功應用機器學習算法的關鍵命題。

盡管基本概念很簡單,但是要用機器學習取得有用的結果,還是需要技巧和經驗的。不過這些技巧是每一個開發者,都能夠學會的!


機器學習是魔法嗎?

看到機器學習技術如此輕易就解決了看起來非常困難的問題(如手寫識別),你可能會感覺只要有足夠多的數據,什麽問題都不是問題了。導入數據,然後等著計算機變出一個適合數據的式子!

但需要記住的事,機器學習要想生效,必須滿足一個條件,就是目標問題對已有數據確實是可解的。

比如建立一個模型,根據房子裏種的植物種類預測房價,這肯定不管用。因為房裏的植物和售價本來就沒有關系,不管再怎麽試,計算機還是無法找出這種關系。

技術分享圖片只有實際存在的關系才能建模

所以如果一位人類專家不能用數據解決某個問題,計算機也不行。相反,計算機的優勢在於,對於人類能解決的問題,計算機可以更快地完成。


如何學習更多機器學習

在我看來,機器學習目前最大的問題在於其主要還是存在於學術界,對於廣大只是想稍微了解、而並非想成為專家的人們,通俗易懂的材料還是不夠豐富,當然這一情況已經在好轉。

吳恩達的Machine Learning class on Coursera相當驚艷,我強烈推薦從這裏開始。對於CS專業的人,只要還記得一丁點數學,就可以學。

你也可以通過下載安裝Scikit-learn,來自己嘗試海量的機器學習算法,這是一個提供“黑盒”版標準算法的Python框架。

帶你入門機器學習