機器學習愛好者必讀的入門指南
本指南適用于任何對機器學習(Machine Learning,ML)感興趣但不知道從何開始的人。
我們的目標是讓任何人都可以理解,這意味著文中會有很多概述。但誰在乎呢?如果能使一些人對機器學習更感興趣,我們將倍感欣慰。
什么是機器學習?
機器學習的概念是用一些通用算法告訴你關于一組數據的一些有趣的事情,而不需要你編寫任何特定于問題的自定義代碼。你不需要編寫代碼,而是將數據提供給通用算法,它將根據數據構建自己的邏輯。
例如,其中一種算法是分類算法。它可以將數據放入不同的組中。同樣的分類算法可以用于識別手寫數字,也可以用于將電子郵件分為垃圾郵件和非垃圾郵件,卻不需要改變一行代碼。使用相同的算法,但輸入不同的訓練數據,算法就會產生不同的分類邏輯。
這種機器學習算法是一個黑箱,可以被用于許多不同的分類問題。
“機器學習”是一個涵蓋了大量這類通用算法的總稱。
兩種機器學習算法
你可以將機器學習算法分為兩大類——監督學習和無監督學習。區別很簡單,但非常重要。
監督學習
假設你是一個房地產經紀人。你的業務正在增長,因此你聘請了一批新的實習生來幫助你。但是有一個問題:你能夠隨便看一下房子就能對房子的價格有一個很好的估計,但是你的實習生沒有你的經驗,所以他們不知道該如何定價。
為了幫助你的實習生(也許還能為你騰出時間去度假),你決定寫一個小應用程序,根據你所在地區的房子的大小、社區等,以及類似房屋的售價來估算房屋的價格。
因此,每當有人在你所在城市出售房屋,你都需要記錄下來,持續 3 個月。對于每套房子,你都要記錄大量細節:臥室的數量、平方英尺為統一單位的面積、社區等。但最重要的是,你要記錄最終的銷售價格:
這是我們的“訓練數據”。
利用這些訓練數據,我們想創建一個程序,可以估算出所在地區其他房屋的價格:
我們想用訓練數據來預測其他房屋的價格
這就是監督學習。你知道每套房子賣多少錢,換句話說,你知道問題的答案,并且可以從那里逆向計算出邏輯。
為了構建應用程序,你需要把每套房子的訓練數據輸入到你的機器學習算法中。該算法會嘗試找出需要做什么樣的數學運算才能算出數字。
這類似于擁有數學考試的答案,但是中間的運算符號都被擦去了:
一個狡猾的學生擦掉了老師的答案上的算術符號!
從這里,你能得出考試中的數學問題是什么嗎?你需要知道你應該用左邊的數字“做點什么運算” 來得到右邊的每個答案。
在監督學習中,就是讓計算機為你計算這種關系。一旦你知道解決這組特定的問題需要什么數學知識,你就可以回答任何同類型的問題!
無監督的學習
讓我們回到最初房地產經紀人的例子。如果你不知道每套房子的售價怎么辦?即使你只知道每套房子的大小、位置等,你仍然可以做一些非常酷的事情。這就是無監督學習。
即使不想預測未知數字(比如價格),你仍然可以用機器學習做些有趣的事情。
這有點像是有人給你一張紙,紙上是數字列表,然后說:“我真的不知道這些數字有什么意思,但也許你能搞清楚是否有模式、分組或其他東西,祝你好運!”
那么用這些數據能做些什么呢?首先,你可以使用算法自動識別數據中的不同細分市場。也許你會發現,當地大學附近的購房者確實很喜歡有很多臥室的小房子,但是郊區的購房者更喜歡有很多平方英尺的三居室的房子。了解這些不同類型的客戶有助于指導你的營銷工作。
你能做的另一件很酷的事情是自動識別出任何與其他地方截然不同的住宅。也許那些離群的房子是豪宅,你可以把最好的銷售人員集中在那些地區,因為他們能給出更多的傭金。
監督學習是我們將在這篇文章的其余部分重點關注的內容,但這并不是因為無監督學習不那么有用或不太有趣。事實上,隨著算法的改進,無監督學習正在變得越來越重要,因為它可以在不需要給數據貼上正確答案標簽的情況下使用。
附注:還有很多其他類型的機器學習算法,但現在已經是一個很好的開端。
這很酷,但是能夠估算房價真的算作“學習”嗎?
作為一個人,你的大腦幾乎可以處理任何情況,并且是在沒有任何明確指示的情況下學習如何處理這種情況。如果你長時間賣房子,你會本能地“察覺”到房子的合適價格、出售房子的最佳方式、感興趣的客戶類型等。強人工智能研究的目標就是能夠用計算機復現這種能力。
然而目前的機器學習算法還不夠好,它們只在關注一個非常具體且有限的問題時才起作用。在這種情況下,“學習”的一個更好的定義可能是“根據一些實例數據,找出解決特定問題的方程式”。
不幸的是,“機器根據一些實例數據計算出方程來解決特定的問題”并不是一個很好的名字。所以我們最終仍以“機器學習”命名。
當然,如果你在未來 50 年后讀到這篇文章,并且我們已經找到了強人工智能的算法,那么這篇文章都會顯得有點古怪。
讓我們來寫一寫這個程序!
那么,如何編寫程序來估算上面的例子中房子的價格呢?在進一步閱讀之前,請考慮一下。
如果你對機器學習一無所知,你可能會試著寫出一些估算房屋價格的基本規則,就像這樣:
- def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
- price = 0
- # In my area, the average house costs $200 per sqft
- price_per_sqft = 200
- if neighborhood == "hipsterton":
- # but some areas cost a bit more
- price_per_sqft = 400
- elif neighborhood == "skid row":
- # and some areas cost less
- price_per_sqft = 100
- # start with a base price estimate based on how big the place is
- price = price_per_sqft*sqft
- # now adjust our estimate based on the number of bedrooms
- if num_of_bedrooms == 0:
- # Studio apartments are cheap
- priceprice = price — 20000
- else:
- # places with more bedrooms are usually
- # more valuable
- priceprice = price + (num_of_bedrooms * 1000)
- return price
如果你花幾個小時來研究,可能會得到一些有用的東西。但你的程序永遠不會完美,而且隨著價格的變化,它將很難維持。
如果計算機能幫你實現這個功能不是更好嗎?只要返回正確的數字,誰在乎函數究竟做了什么:
- def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
- price = <computer, plz do some math for me>
- return price
考慮這個問題的一種方式是,把價格看成是一道美味的燉菜,配料是臥室的數量、面積和社區。如果你能算出每種成分對最終價格的影響程度,也許就能算出每種成分在最終價格中所占的確切比例。
這會把你原來的函數(那些瘋狂if和else的函數)簡化成這樣:
- def estimate_house_sales_price(num_of_bedrooms, sqft,neighborhood):
- price = 0
- # a little pinch of this
- price += num_of_bedrooms * .841231951398213
- # and a big pinch of that
- price += sqft * 1231.1231231
- # maybe a handful of this
- price += neighborhood * 2.3242341421
- # and finally, just a little extra salt for good measure
- price += 201.23432095
- return price
注意這些魔法數字: .841231951398213、1231.1231231、2.3242341421 和 201.23432095。這些是我們的權重。如果能計算出適用于每套房子的完美權重,我們的函數就能預測房價!
計算最佳權重的一個愚蠢方法是這樣的:
第1步:
將每個初始權重設置為1.0:
- def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
- price = 0
- # a little pinch of this
- price += num_of_bedrooms * 1.0
- # and a big pinch of that
- price += sqft * 1.0
- # maybe a handful of this
- price += neighborhood * 1.0
- # and finally, just a little extra salt for good measure
- price += 1.0
- return price
第2步:
通過函數運行你所知道的每一棟房子,看看這個函數離預測到每一套房子的正確價格有多遠:
使用你的函數為每套房子預測價格
例如,如果第一套房子實際上賣了 25 萬美元,但你的函數預測它賣了 17.8 萬美元,那么這套房子的售價就少了 7.2 萬美元。
現在把你的數據集里每套房子的售價差額平方相加,假設你的數據集中有 500 套房子的銷售數據,你的函數計算的每套房子售價差額的平方的總和是 86,123,373 美元。這就是當前函數的“錯誤”程度。
現在,把總和除以 500,得到每套房子的平均差價。將這個平均錯誤量稱為函數的成本(cost)。
如果你能通過調整權值使這個成本為零,你的函數就完美了。這意味著,在每種情況下,你的函數都能夠根據輸入的數據完美地猜測房屋的價格。這就是我們的目標:通過嘗試不同的權重值使成本盡可能低。
第3步:
對每一個可能的權重組合重復第2步。最后選擇使成本最接近于零的權重組合。當你找到合適的權重時,問題就解決了!
頭腦風暴時間
很簡單,對吧?回想一下你剛才都做了什么。你取了一些數據,通過三個通用的、非常簡單的步驟輸入數據,最后得到一個可以預測你所在地區的任何房子的價格的函數。
但還有一些事實會讓你大吃一驚:
過去40年來,在許多領域(如語言學/翻譯)進行的研究表明,這些“攪拌數字燉湯”(我剛編好的詞)的通用學習算法可以實現真正的人為試圖得到的明確規則方法。機器學習的“愚蠢”方法最終擊敗了人類專家。
最后得到的函數是完全愚蠢的。它甚至不知道“平方英尺”或“臥室”是什么。它所知道的是,它需要加入一些數字來得到正確的答案。
你很可能不知道為什么一組特定的權重會起作用。所以你只是寫了一個你并不真正理解的函數,但是可以證明它是有效的。
想象一下,你的預測函數不是采用 “sqft” 和 “num-of-bedrooms” 這樣的參數,而是接受一組數字。
假設每個數字代表安裝在汽車頂部的攝像頭拍攝的圖像中一個像素的亮度。現在讓我們假設,該函數不是輸出一個名為“價格”的預測,而是輸出一個名為“度”的預測來轉動方向盤。那么你剛剛做了一個可以自動駕駛汽車的函數!
相當瘋狂,不是嗎?
第3步中,“嘗試每個權重數字”是什么意思?
當然不可能去嘗試所有可能的權重組合來找到最有效的組合。這真的需要花上很長時間,因為你永遠也不會用盡所有的數字。
為了避免這種情況的發生,數學家們想出了許多聰明的方法,可以快速地找到合適的權重值而無需太多嘗試。這里提供一種方法:
首先,寫一個簡單的方程來表示上面的第2步:
這是你的成本函數。
現在讓我們重寫一個完全相同的方程,但是使用一些機器學習的數學術語(你可以暫時忽略):
θ 表示當前權重,J(θ) 表示當前權重的成本。
這個方程表示我們的價格估計函數在我們目前設置的權重下的錯誤程度。
如果我們將 numberofbedroom 和 sqft 的成本函數的所有權重可能值繪制出來,我們會得到這樣一個圖形:
我們的成本函數圖看起來像一個碗。縱軸代表成本。
在這張圖中,藍色的最低點就我們成本最低的地方,即函數誤差值最小。最高點是我們錯誤值越大的地方。所以,如果我們能找到這個圖形最低點的權重,我們就得到答案了!
所以我們只需要調整權重,在這個圖上“下山”到最低點。如果我們不斷地對權重進行小的調整,使其始終向最低點移動,我們最終就會不需要嘗試太多權重的情況下到達最低點。
如果你還記得微積分的知識,你可能還記得如果對一個函數求導,會得到函數在任意點切線的斜率。換句話說,它告訴我們曲線上任意一點的下坡方向。我們可以用這些知識來走下坡。
因此,如果我們計算成本函數對每個權重的偏導數,我們就可以從每個權重中減去這個值。這將使我們離山腳更近一步。繼續這樣做,最終我們會到達山的底部,并為我們的權重找到最好的值。(如果不理解,別擔心,繼續讀下去)。
這是一種為函數尋找最佳權重方法的高級總結,稱為批量梯度下降(batch gradient descent)。當你使用機器學習庫來解決實際問題時,所有這些計算都會為你完成。但是對正在發生的事情有一個好的了解仍然是有用的。
還跳過了什么內容呢?
我所描述的三步算法叫做多元線性回歸(multivariate linear regression)。你正在估算一條貫穿你的所有家庭數據點的直線的方程。然后,根據房子在你的線上的位置,用這個方程來預測你以前從未見過的房子的銷售價格。這是一個非常有用的主意,你可以用它來解決“真正的”問題。
雖然我向你展示的方法適用于簡單的情況,但它并不適用于所有情況。其中一個原因是,房價并不總是簡單到可以遵循一條連續的線。
但幸運的是,有很多方法可以解決這個問題。有許多其他的機器學習算法可以處理非線性數據(如神經網絡(neural networks)或帶內核的支持向量機(support vector machine, SVM)。也有一些更巧妙地使用線性回歸的方法,允許更復雜的線被擬合。在所有情況下,找到最佳權重的基本思想仍然適用。
另外,我忽略了 過擬合(overfitting)的概念。一個簡單的例子,有一組權重,它總是能夠很好地預測原始數據集中房屋的價格,但實際上從未適用于任何不在原始數據集中的新房屋。但有一些方法可以解決這一問題(如正則化(regularization) 和使用交叉驗證數據集(cross-validation)。學會如何處理這個問題是學習如何成功應用機器學習的關鍵部分。
換句話說,雖然基本概念相當簡單,但是應用機器學習并獲得有用的結果需要一些技巧和經驗。但這是任何開發人員都可以學習的技能!
機器學習有魔法嗎?
一旦你開始發現機器學習技術很容易應用到看起來很難解決的問題上(比如手寫識別),你就會開始感覺到你可以用機器學習來解決任何問題,只要你有足夠的數據就可以得到答案。只需要輸入數據,然后看著電腦神奇地計算出與數據相符的方程!
但重要的是要記住,機器學習只有在問題確實可以用現有的數據解決的情況下才有效。
例如,如果你建立一個模型,根據每套房子里盆栽植物的類型來預測房價,那么這個模型永遠不會奏效。每套房子里的盆栽植物和房子的售價之間沒有任何關系。因此,無論如何努力,計算機永遠無法推斷出兩者之間的關系。
只能夠為實際存在關系的模型建模。所以記住,如果人類專家不能用這些數據來手動解決這個問題,那么計算機可能也不能。更應該關注的是那些人類可以解決的問題,如果計算機能夠更快地解決,就太棒了。
如何深入了解機器學習?
在我看來,目前機器學習最大的問題是它主要存在在學術界和商業研究團體的世界里。對于那些想要在不成為專家的情況下而能廣泛理解機器學習的人來說,并沒有很多容易理解的材料。但是這方面每天都在進步。
如果你想深入了解,吳恩達(Andrew Ng)在 Coursera 上開設的免費機器學習課程是非常棒的。我強烈推薦。它應該對任何擁有計算機科學學位并且只記得很少數學知識的人都是容易理解的。