原文:Machine Learning is Fun! Part 1 —— The world’s easiest introduction to Machine Learning
作者:Adam Geitgey
翻譯:Kaiser(微博:王司圖)
本文的多國語言版: 日本語, Português, Türkçe, Français, 한국어, العَرَبِيَّة, Español (México), Español (España) 或 Polski。
你是否也曾聽人們談起機器學習但是隻有一個朦朧的概念?你是否厭倦了在同事的高談闊論中頹然欲睡?此誠求變之機。
本教程適合所有對機器學習感到好奇,卻不知從何下手的讀者。我想應該有很多人試著讀了維基百科頁面,然後愈發迷惘、沉淪,盼望著有人能夠提供一個high-level的解釋,那你找對地方了。
我們的目標是讓所有人都能讀懂——這就難免有些泛泛而談。但是無妨,但凡本文能讓一個人真正對機器學習感興趣,那麼目的就算達到了。
什麼是機器學習?
機器學習的核心思想是創造一種普適的演算法,它能從資料中挖掘出有趣的東西,而不需要針對某個問題去寫程式碼。你需要做的只是把資料“投喂”給普適演算法,然後它會在資料上建立自己的邏輯。
比如說有一種演算法,叫分類演算法,它可以把資料分到不同的組別當中。一個識別手寫數字的分類演算法,也可以用作判斷垃圾郵件,而無需修改一行程式碼。演算法是同一個演算法,只是輸入了不同的訓練資料,便有了不同的分類邏輯。
“機器學習”是個筐,什麼普適演算法都往裡裝。
兩種機器學習演算法
機器學習主要分為兩類——有監督學習和無監督學習,區別很簡單,卻很關鍵。
有監督學習
想想你是一家房產中介。你的業務正在增長,所以僱了一幫實習銷售來助拳。那麼問題來了——身經百戰的你,一眼就看穿一棟房子價值幾何,但是實習生可沒有這樣豐富的人生經驗,所以摸不準行情。
為了輔助實習生(以便解放自己度個假),你決定做個小程式,基於面積、周邊環境、相似房產成交價等等,來預估本地的房價。
所以你把3個月來本市的每一筆交易都拿小本本記了下來。對每處房產都整理了一大堆細節——房間數、面積、周邊環境等等,當然最重要的是,最終成交價:
有了訓練資料,我們就想搞個程式去預估其他的房價:
這就是有監督學習。你是知道每處房產到底賣多少的,換言之,問題的答案是已知的,邏輯是可以反推的。
為了開發小程式,把每處房產的訓練資料導進機器學習演算法裡,演算法試圖摸索出其中的數學規律。
這有點像是去掉了符號的算術題答案:
根據上圖,你能否推算出這些題目的原貌呢?顯然,我們需要對這些數字“動點手腳”,以使等式成立。
在有監督學習中,我們做的實際上就是讓電腦代替人來讓等式成立。一旦你學會了解決某一類問題,那麼這類問題裡的任何子問題都就迎刃而解了!
無監督學習
回到最開始那個賣房地產的例子。如果我們不知道具體每處房產的價格可咋整?即使僅知道面積、位置等資訊,你也依然可以搞點動靜出來,這就叫無監督學習。
這就好比有人給你一張紙,上面寫著一串數字,然後說“我也不知道啥意思,你可以猜猜這是什麼套路——好運!”
這些資料我們能做什麼呢?對於新手來講,可以得到一個演算法,從資料中自動辨識出細分的市場定位。可能你會發現,當地大學附近的購房者偏好多臥室的小房子,而郊區的購房者則傾向於大套三。瞭解到不同型別消費者的存在可以指導市場行為。
另一個可以做的就是自動識別出那些少有相似點的特異房產。可能這些特異房產是豪華公館,那麼就可以調配最好的銷售人員專門負責這些大買賣。
後文主要專注於有監督學習,但並非因為無監督學習的作用小或者趣味少。實際上無監督學習的重要性與日俱增且發展迅速,因為不需要事先對正確答案對應的資料加標籤。
注:還有很多其他種類的機器學習演算法,不過建議從這些基礎演算法入手。
哎喲不錯,但是真的有可能“學習”到真實的房價嗎?
作為一個人類,你的大腦可以面對各種形勢,並且在無明確指導的情況下自主學習如何應對。如果你賣了很久的房子,就會慢慢地對房價、對銷售策略、對觀察客戶等問題產生一種“感覺”。強人工智慧研究的目的就在於讓計算機掌握這種能力。
但是當前的機器學習演算法還沒那麼厲害——它們只能對很具體、有限的問題生效。或許這裡的“學習”更應該定義為“基於樣本資料得出解決具體問題的等式”。
不幸的是,“讓機器基於樣本資料得出解決具體問題的等式”不是個好名字,所以我們還是回到了“機器學習”。
當然如果你在50年後,強人工智慧都普及了時候看到本文,會覺得全文都很“古典”。別看了,讓你的機器人給你拿個包子吃,未來人類。
放碼過來!
然,上面例子裡的預測房價程式應該怎麼寫呢?思考一秒,然後接著看。
如果你對機器學習一無所知,可能會嘗試依照預測房價的基本規律,寫出如下程式碼:
[amalthea_exercise lang="python" executable="false" writable="false"]
[amalthea_sample_code]
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
# 這一片的均價是200美元一平米
price_per_sqft = 200
if neighborhood == "hipsterton":
# 有的區更貴
price_per_sqft = 400
elif neighborhood == "skid row":
# 有的區便宜
price_per_sqft = 100
# 根據基準價和麵積預測實際價格
price = price_per_sqft * sqft
# 根據房間數調整預測
if num_of_bedrooms == 0:
# 公寓稍微便宜點
price = price — 20000
else:
# 臥室多的房子貴
price = price + (num_of_bedrooms * 1000)
return price[/amalthea_sample_code]
[/amalthea_exercise]
複製程式碼
如果順著寫上幾個小時,或許也能得到一個能跑的程式。但勢必存在隱患,而且無法應對價格變化。
如果計算機能自己發現如何應用這些方程,那豈不是好得多?只要能得到正確的數字,誰管具體方程是什麼呢?
[amalthea_exercise lang="python" executable="false" writable="false"]
[amalthea_sample_code]
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 賈維斯,幫我算一下
return price
[/amalthea_sample_code]
[/amalthea_exercise]
複製程式碼
這個問題可以想象成:價格是道燉菜,配方是臥室數量,面積和周邊環境。如果你能算出每種成分對最終價格的影響是多少,或許那就是配方“攪合”最終價格的確切權重。
這可以使原程式(滿是if/else)變得簡單如下:
[amalthea_exercise lang="python" executable="false" writable="false"]
[amalthea_sample_code]
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
# 加少許配方1
price += num_of_bedrooms * .841231951398213
# 加大把配方2
price += sqft * 1231.1231231
# 適量的配方3
price += neighborhood * 2.3242341421
# 最後來點鹽
price += 201.23432095
return price
[/amalthea_sample_code]
[/amalthea_exercise]
複製程式碼
注意這些奇妙深刻的加粗數字——.841231951398213、 1231.1231231、2.3242341421和201.23432095,這就是我們的權重。只要我們能找到準確的權重,那就可以預測房價了。
一個比較粗暴的權重計算方法大致如下:
第一步:
把所有權重都設為1.0:
[amalthea_exercise lang="python" executable="false" writable="false"]
[amalthea_sample_code]
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
# 加少許配方1
price += num_of_bedrooms * 1.0
# 加大把配方2
price += sqft * 1.0
# 適量的配方3
price += neighborhood * 1.0
# 最後來點鹽
price += 1.0
return price
[/amalthea_sample_code]
[/amalthea_exercise]
複製程式碼
第2步:
把每個房產的引數代入公式,計算預測結果和實際價格的誤差:
比如第一個房子實際賣了$250,000,但是你的方程卻預測的是$178,000,但這一個房子就少了$72,000。
現在把每個房子對應誤差的平方加起來,比方你有500單交易,那麼誤差的平方和就有$86,123,373,可謂謬以千里。再把平方和除以500得到平均每個房子的誤差,這一平均誤差值就是方程的代價(即最小二乘法,平方是為了防止誤差正負相抵)。
如果我們能通過調整權重將代價降為零,那方程就完美了。這表示在所有例子中,方程都準確無誤地基於輸入資料猜中了房價。這就是我們的目標——嘗試不同的權重,讓代價儘量低。
第3步:
不斷地重複第2步,嘗試每一種可能的權重值組合。哪個組合能讓代價最接近於0就選哪一組。找到那一組權重,就解決了問題!
腦洞時間
挺簡單的對吧?回想一下剛才的所做,拿到一些資料,填進三個普適的、簡單的步驟裡,然後得到一個能猜房價的方程。Zillow(美國房價預測網站)面臨著嚴重的威脅!
但是有這麼幾個激動人心的事實:
-
過去40年裡,很多領域(如語言學/翻譯學)的研究已經表明,“攪合數字燉菜”(作者自己打的比方)的普適性學習演算法已經超越了那些,由真人嘗試自己發現顯式規律的人方法。機器學習的“暴力”方法最終擊敗了人類專家。
-
剛才得出的方程其實是很笨的。它並不知道“平方米”和“臥室”到底是什麼,它只知道“攪拌”多少數字可以得到正確答案。
-
你大概並不知道為什麼某一組權重就是好的,而只是寫了一個自己都不明白的方程,但卻證明是好用的。
-
假設我們不用“平方米”和”臥室數“這些引數,而是讀入一個數列。比方說每個數字代表的是”從車頂上拍的照片的某一畫素的亮度”,然後我們預測的結果也不是“房價”了,而是“方向盤轉過的角度”。這就是一個人自動駕駛的風方程了?
瘋了,對吧?
第3步的“嘗試每個數字”
當然你不可能真的嘗試每一種可能權重組合來尋找最優解,實際情況是永遠嘗試不完。
為了避免這一情況,數學家們發現了很多機智辦法來儘快找到一個不錯的結果。以下就是其中一種:
第一,寫一個能夠代表上面“第2步”的方程:
然後用機器學習界的黑話(暫時可以忽略)重新寫一遍:
這個等式代表了在當前的權重組合下,我們的價格預測有多麼離譜。
如果把房間數和平方米所有可能權重值視覺化,可以得到類似下圖的影像:
這個圖裡的藍色最低點就是代價的最低點——方程誤差最小處,最高點即是最離譜的情況。所以如果我們找到一組權重值,使得方程對應最低點,那就是答案!
所以我們只需要以“下山”的方式來調整權重,逼近最低點。如果每一次微小的調整都向著最低點進發,那遲早能夠到達。
函式的導數就是切線的斜率,換句話說,這告訴我們哪條路可以“下山”。
因此如果計算代價函式對每個權重的偏微分,然後再從權重裡減去這個值,這可以讓我們離谷底更近。重複執行,最終我們會到達谷底並獲得權重的最優解(如果沒看懂,不要擔心,繼續看)。
這是一種尋找方程最佳權重方式的高度概括,叫作批梯度下降(batch gradient descent)。如果你對此感興趣,不要害怕,瞭解更多細節。
當你使用機器學習庫來解決實際問題的時候,這些都會自動完成,但是瞭解究竟發生了什麼還是很有用的。
還略過了什麼?
上述的三步演算法即是多變數線性迴歸,針對一條穿過房產資料的直線來進行預測目標等式,並用這一等式去猜測此前未曾見過的房屋價格,解決實際問題的時候這非常行之有效。
但是以上方法或許只對特別簡單的例子好使,並非萬金油。其中一個原因就是房價不總是簡單到能用一條連續直線來代表。
好在另有很多方法解決,很多機器學習演算法可以處理非線性資料(如神經網路
或
有核
的支援向量機)。同樣也有演算法是以更加聰明的方式使用線性迴歸以擬合更復雜的直線。但不論哪一方法,最根本的思想都是找到最佳的權重。
並且我忽略了過擬合問題。對於已有的原始資料,找到一組很棒的權重值不難,但是卻有可能對訓練集以外新的房子不適用。有很多方法可以避免這一現象(如正則化和使用交叉驗證資料集),這是成功應用機器學習演算法的關鍵命題。
儘管基本概念很簡單,但是要用機器學習取得有用的結果,還是需要技巧和經驗的。不過這些技巧是每一個開發者,都能夠學會的!
機器學習是魔法嗎?
看到機器學習技術如此輕易就解決了看起來非常困難的問題(如手寫識別),你可能會感覺只要有足夠多的資料,什麼問題都不是問題了。匯入資料,然後等著計算機變出一個適合資料的式子!
但需要記住的事,機器學習要想生效,必須滿足一個條件,就是目標問題對已有資料確實是可解的。
比如建立一個模型,根據房子裡種的植物種類預測房價,這肯定不管用。因為房裡的植物和售價本來就沒有關係,不管再怎麼試,計算機還是無法找出這種關係。
所以如果一位人類專家不能用資料解決某個問題,計算機也不行。相反,計算機的優勢在於,對於人類能解決的問題,計算機可以更快地完成。
如何學習更多機器學習
在我看來,機器學習目前最大的問題在於其主要還是存在於學術界,對於廣大隻是想稍微瞭解、而並非想成為專家的人們,通俗易懂的材料還是不夠豐富,當然這一情況已經在好轉。
吳恩達的Machine Learning class on Coursera相當驚豔,我強烈推薦從這裡開始。對於CS專業的人,只要還記得一丁點數學,就可以學。
你也可以通過下載安裝Scikit-learn,來自己嘗試海量的機器學習演算法,這是一個提供“黑盒”版標準演算法的Python框架。