你是否曾經(jīng)聽到過人們談?wù)摍C(jī)器學(xué)習(xí),而你卻對(duì)其含義只有一個(gè)模糊的概念呢?你是否已經(jīng)厭倦了在和同事對(duì)話時(shí)只能點(diǎn)頭呢?現(xiàn)在,讓我們一起來改變這個(gè)現(xiàn)狀吧!
這篇指南是為那些對(duì)機(jī)器學(xué)習(xí)感興趣,但又不知從哪里開始的人而寫的。我猜有很多人曾經(jīng)嘗試著閱讀機(jī)器學(xué)習(xí)的維基百科詞條,但是讀著讀著倍感挫折,然后直接放棄,希望能有人給出一個(gè)更直觀的解釋。本文就是你們想要的東西。
本文的寫作目標(biāo)是讓任何人都能看懂,這意味著文中有大量的概括。但是那又如何呢?只要能讓讀者對(duì)機(jī)器學(xué)習(xí)更感興趣,這篇文章的任務(wù)也就完成了。
什么是機(jī)器學(xué)習(xí)?
機(jī)器學(xué)習(xí)是一種概念:不需要寫任何與問題有關(guān)的特定代碼,泛型算法(Generic Algorithms)[1]就能告訴你一些關(guān)于你數(shù)據(jù)的有趣結(jié)論。不用編碼,你將數(shù)據(jù)輸入泛型算法當(dāng)中,它就會(huì)在數(shù)據(jù)的基礎(chǔ)上建立出它自己的邏輯。
比如說,有一種算法被稱為分類算法,它可以將數(shù)據(jù)分為不同的組。分類算法可以用來識(shí)別手寫數(shù)字;不用修改一行代碼,它也可以用來區(qū)分垃圾郵件和非垃圾郵件。如果給同樣的算法輸入不同的訓(xùn)練數(shù)據(jù),它就能得出不同的分類邏輯。

「機(jī)器學(xué)習(xí)」是一個(gè)涵蓋性術(shù)語,它覆蓋了大量類似的泛型算法。
兩類機(jī)器學(xué)習(xí)算法
你可以把機(jī)器學(xué)習(xí)算法分為兩大類:監(jiān)督式學(xué)習(xí)(supervised Learning)和非監(jiān)督式學(xué)習(xí)(unsupervised Learning)。要區(qū)分兩者很簡(jiǎn)單,但也非常重要。
監(jiān)督式學(xué)習(xí)
假設(shè)你是一名房地產(chǎn)經(jīng)紀(jì)人,你的生意蒸蒸日上,因此你雇了一批新員工來幫忙。但是問題來了——雖然你可以一眼估算出房子的價(jià)格,但新員工卻不像你這樣經(jīng)驗(yàn)豐富,他們不知道如何給房子估價(jià)。
為了幫助你的新員工(也許就是為了給自己放個(gè)假嘻嘻),你決定寫一個(gè)可以根據(jù)房屋大小、地段以及同類房屋成交價(jià)等因素來評(píng)估一間房屋的價(jià)格的小軟件。
近三個(gè)月來,每當(dāng)你的城市里有人賣了房子,你都記錄了下面的細(xì)節(jié)——臥室數(shù)量、房屋大小、地段等等。但最重要的是,你寫下了最終的成交價(jià):

使用這些訓(xùn)練數(shù)據(jù),我們要來編寫一個(gè)能夠估算該地區(qū)其他房屋價(jià)值的程序:

這就是監(jiān)督式學(xué)習(xí)。你已經(jīng)知道了每一棟房屋的售價(jià),換句話說,你已經(jīng)知道了問題的答案,并且可以反向找出解題的邏輯。
為了編寫你的軟件,你將包含每一套房產(chǎn)的訓(xùn)練數(shù)據(jù)輸入到你的機(jī)器學(xué)習(xí)算法當(dāng)中去。算法會(huì)嘗試找出需要做哪些數(shù)學(xué)運(yùn)算來得出價(jià)格。
這就好像是你已經(jīng)知道了數(shù)學(xué)測(cè)試題的答案,但是算式中的運(yùn)算符號(hào)都被擦去了:

你能從這張圖里看出來測(cè)驗(yàn)中的數(shù)學(xué)題是怎樣的嗎?你知道自己應(yīng)該對(duì)左邊的數(shù)字「做些什么」,才能得到右邊的答案。
在監(jiān)督式學(xué)習(xí)中,你讓計(jì)算機(jī)為你算出這種關(guān)系。而一旦你知道了解決這類特定問題所需要的數(shù)學(xué)方法后,你就可以解答其它同類問題了!
非監(jiān)督式學(xué)習(xí)
讓我們回到房地產(chǎn)經(jīng)紀(jì)人的例子。如果你不知道每棟房子的售價(jià)怎么辦?即使你所知道的僅僅是每棟房屋的大小、位置等信息,你也可以搞出一些很酷炫的花樣來。這就是我們所說的非監(jiān)督式學(xué)習(xí)。

這就有點(diǎn)像有人給你一張紙,上面寫了一列數(shù)字,然后說:「我不太清楚這些數(shù)字有什么意義,但也許你能找出些規(guī)律或是把它們分類什么的——祝你好運(yùn)!」
所以該怎么處理這些數(shù)據(jù)呢?首先,你可以用個(gè)算法自動(dòng)從數(shù)據(jù)中劃分出不同的細(xì)分市場(chǎng)。也許你會(huì)發(fā)現(xiàn),當(dāng)?shù)卮髮W(xué)附近的購(gòu)房者特喜歡戶型小、臥室多的房子,而郊區(qū)的購(gòu)房者偏好三臥室的大戶型。了解這些不同消費(fèi)者的喜好可以直接幫助你的營(yíng)銷。
你還可以做件很酷炫的事,就是自動(dòng)找出非同尋常的房屋。這些與眾不同的房產(chǎn)也許是奢華的豪宅,而你可以將最優(yōu)秀的銷售人員集中在這些地區(qū),因?yàn)樗麄兊膫蚪鸶摺?/p>
在接下來的內(nèi)容中我們主要討論監(jiān)督式學(xué)習(xí),但這并不是因?yàn)榉潜O(jiān)督式學(xué)習(xí)比較沒用或是無趣。實(shí)際上,隨著算法的改良,非監(jiān)督式學(xué)習(xí)正變得越來越重要,因?yàn)榧词共粚?shù)據(jù)和正確答案聯(lián)系在一起,它也可以被使用。
太酷炫了,但是估算房?jī)r(jià)真能被看作「學(xué)習(xí)」嗎?
作為人類的一員,你的大腦可以應(yīng)付絕大多數(shù)情況,并且在沒有任何明確指令時(shí)也能夠?qū)W習(xí)如何處理這些情況。如果你做房地產(chǎn)經(jīng)紀(jì)人時(shí)間足夠長(zhǎng),你對(duì)于房產(chǎn)的合適定價(jià)、房屋的最佳營(yíng)銷方式以及客戶會(huì)感興趣類型等等都會(huì)有一種本能般的「感覺」。強(qiáng)人工智能研究的目標(biāo)就是要計(jì)算機(jī)復(fù)制這種能力。
但是目前的機(jī)器學(xué)習(xí)算法還沒有那么強(qiáng)大——它們只能在非常特定的、有限的問題上有效。也許在這種情況下,「學(xué)習(xí)」更貼切的定義是「在少量樣本數(shù)據(jù)的基礎(chǔ)上找出一個(gè)公式來解決特定的問題」。
但是「機(jī)器在少量樣本數(shù)據(jù)的基礎(chǔ)上找出一個(gè)公式來解決特定的問題」不是個(gè)好名字。所以最后我們用「機(jī)器學(xué)習(xí)」取而代之。
當(dāng)然了,如果你是在 50 年后的未來讀的這篇文章,而我們?nèi)祟愐惨呀?jīng)得出了強(qiáng)人工智能的算法的話,那這篇文章看起來就像個(gè)老古董了。那樣的話,就別讀了,去讓你的機(jī)器傭人給你做份三明治吧,未來的人類。
讓我們愉快地寫代碼吧!
所以,你打算怎么寫上面例子中評(píng)估房?jī)r(jià)的程序呢?在往下看之前先思考一下吧。
如果對(duì)機(jī)器學(xué)習(xí)一無所知,你很有可能會(huì)嘗試寫出一些基本規(guī)則來評(píng)估房?jī)r(jià),如下:
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
#在我這地方,每平方英尺房屋均價(jià)是 200 美元
price_per_sqft = 200
if neighborhood == "hipsterton":
#但是有些地段房?jī)r(jià)會(huì)貴一點(diǎn)
price_per_sqft = 400
elif neighborhood == "skid row":
# 有些地段房?jī)r(jià)便宜點(diǎn)
price_per_sqft = 100
# 們先按面積大小估計(jì)房屋價(jià)格基準(zhǔn)
price = price_per_sqft * sqft
# 現(xiàn)在根據(jù)臥室數(shù)量微調(diào)價(jià)格
if num_of_bedrooms == 0:
# 工作室類型的公寓比較便宜
price = price — 20000
else:
# 臥室數(shù)量越多,通常房?jī)r(jià)越貴
price = price + (num_of_bedrooms * 1000)
return price
假如你像這樣瞎忙幾個(gè)小時(shí),最后也許會(huì)得到一些像模像樣的東西。但是你的程序永不會(huì)完美,而且當(dāng)價(jià)格變化時(shí)很難維護(hù)。
如果能讓計(jì)算機(jī)找出實(shí)現(xiàn)上述函數(shù)功能的辦法,豈不更好?只要返回的房?jī)r(jià)數(shù)字正確,誰會(huì)在乎函數(shù)具體干了些什么呢?
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = <computer, plz do some math for me>
return price
考慮這個(gè)問題的一種角度是將價(jià)格看作一碗美味的湯,而湯的原材料就是臥室數(shù)量、面積和地段。如果你能算出每種原材料對(duì)最終的價(jià)格有多大影響,也許就能得到各種原材料混合形成最終價(jià)格的具體比例。
這樣可以將你最初的程序(全是令人抓狂的 if else 語句)簡(jiǎn)化成類似如下的樣子:
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
# 一小撮這個(gè)
price += num_of_bedrooms * .841231951398213
# 一大撮那個(gè)
price += sqft * 1231.1231231
# 或許再加一把這個(gè)
price += neighborhood * 2.3242341421
# 最后,再多加一點(diǎn)點(diǎn)鹽
price += 201.23432095
return price
注意那些用粗體標(biāo)注的神奇數(shù)字——.841231951398213, 1231.1231231, 2.3242341421, 和201.23432095。它們稱為權(quán)重(weight)。如果我們能找出對(duì)每棟房子都適用的完美權(quán)重,我們的函數(shù)就能預(yù)測(cè)所有的房?jī)r(jià)![3]
一種找出最佳權(quán)重的笨辦法如下所示:
第一步:
首先,將每個(gè)權(quán)重都設(shè)為 1.0:
def estimate_house_sales_price(num_of_bedrooms, sqft, neighborhood):
price = 0
# 一小撮這個(gè)
price += num_of_bedrooms * 1.0
# 一大撮那個(gè)
price += sqft * 1.0
# 或許再加一把這個(gè)
price += neighborhood * 1.0
# 最后,再多加一點(diǎn)點(diǎn)鹽
price += 1.0
return price
第二步:
將你知道的每棟房產(chǎn)的數(shù)據(jù)代入函數(shù)進(jìn)行運(yùn)算,檢驗(yàn)估算值與正確價(jià)格的偏離程度:

比如說,如果第一套房產(chǎn)實(shí)際成交價(jià)為 25 萬美元,你的函數(shù)估價(jià)為 17.8 萬美元,這一套房產(chǎn)你就差了 7.2 萬。
現(xiàn)在,將你的數(shù)據(jù)集中的每套房產(chǎn)估價(jià)偏離值平方后求和。假設(shè)你的數(shù)據(jù)集中交易了 500 套房產(chǎn),估價(jià)偏離值平方求和總計(jì)為 86,123,373 美元。這個(gè)數(shù)字就是你的函數(shù)現(xiàn)在的「錯(cuò)誤」程度。
現(xiàn)在,將總和除以 500,得到每套房產(chǎn)的估價(jià)偏差的平均值。將這個(gè)平均誤差值稱為你函數(shù)的代價(jià)(cost)。
如果你能通過調(diào)整權(quán)重,使得這個(gè)代價(jià)變?yōu)?0,你的函數(shù)就完美了。它意味著,根據(jù)輸入的數(shù)據(jù),你的程序?qū)γ恳还P房產(chǎn)交易的估價(jià)都是分毫不差。所以這就是我們的目標(biāo)——通過嘗試不同的權(quán)重值,使代價(jià)盡可能的低。
第三步:
通過嘗試所有可能的權(quán)重值組合,不斷重復(fù)第二步。哪一個(gè)權(quán)重組合的代價(jià)最接近于 0,你就使用哪個(gè)。當(dāng)你找到了合適的權(quán)重值,你就解決了問題!
興奮的時(shí)刻到了!
挺簡(jiǎn)單的,對(duì)吧?想一想剛才你做了些什么。你拿到了一些數(shù)據(jù),將它們輸入至三個(gè)泛型的、簡(jiǎn)單的步驟中,最后你得到了一個(gè)可以對(duì)你所在區(qū)域任何房屋進(jìn)行估價(jià)的函數(shù)。房?jī)r(jià)網(wǎng)站們,你們要小心了!
但是下面的一些事實(shí)可能會(huì)讓你更興奮:
過去 40 年來,很多領(lǐng)域(如語言學(xué)、翻譯學(xué))的研究表明,這種「攪拌數(shù)字湯」(我編的詞)的泛型學(xué)習(xí)算法已經(jīng)超過了那些真人嘗試明確規(guī)則的方法。機(jī)器學(xué)習(xí)的「笨」辦法終于打敗了人類專家。
你最后寫出的程序是很笨的,它甚至不知道什么是「面積」和「臥室數(shù)量」。它知道的只是攪拌,改變數(shù)字來得到正確的答案。
你可能會(huì)對(duì)「為何一組特殊的權(quán)重值會(huì)有效」一無所知。你只是寫出了一個(gè)你實(shí)際上并不理解卻能證明有效的函數(shù)。
試想,如果你的預(yù)測(cè)函數(shù)輸入的參數(shù)不是「面積」和「臥室數(shù)量」,而是一列數(shù)字,每個(gè)數(shù)字代表了你車頂安裝的攝像頭捕捉的畫面中的一個(gè)像素。然后,假設(shè)預(yù)測(cè)的輸出不是「價(jià)格」而是「方向盤轉(zhuǎn)動(dòng)角度」,這樣你就得到了一個(gè)程序可以自動(dòng)操縱你的汽車了!
太瘋狂了,對(duì)吧?
第三步里「嘗試每個(gè)數(shù)字」是怎么一回事?
好吧,當(dāng)然你不可能試遍所有權(quán)重組合來找到效果最好的組合。直到世界毀滅你也算不完,因?yàn)檫@數(shù)字和組合無窮無盡。
為了避免這種情況,數(shù)學(xué)家們找到了很多種聰明的辦法來快速找到優(yōu)秀的權(quán)重值。下面是一種:
首先,寫出一個(gè)簡(jiǎn)單的等式表示上面的第二步:

現(xiàn)在讓我們,使用機(jī)器學(xué)習(xí)數(shù)學(xué)術(shù)語(現(xiàn)在暫時(shí)你可以忽略它們),重新改寫同樣的這一等式:

這個(gè)等式表示,在當(dāng)前權(quán)重值下,我們估價(jià)程序的偏離程度。
如果我們?yōu)檫@個(gè)等式中所有臥室數(shù)和面積的可能權(quán)重值作圖的話,我們會(huì)得到類似下圖的圖表:

圖中,藍(lán)色的最低點(diǎn)就是代價(jià)最低的地方——在這里我們的程序偏離最小。最高點(diǎn)們意味著偏離最大。所以,如果我們能找到一組權(quán)重值讓我們到達(dá)圖中的最低點(diǎn),我們就得到了答案!

因此,我們需要做的只是調(diào)整我們的權(quán)重,使得我們?cè)趫D上朝著最低點(diǎn)「走下坡路」。如果我們不斷微調(diào)權(quán)重,一直向最低點(diǎn)移動(dòng),那么我們最終不用嘗試太多權(quán)重就可以到達(dá)那里。
如果你還記得一點(diǎn)微積分的話,你也許記得如果你對(duì)一個(gè)函數(shù)求導(dǎo),它會(huì)告訴你函數(shù)任意一點(diǎn)切線的斜率。換句話說,對(duì)于圖上任意給定的一點(diǎn),求導(dǎo)能告訴我們哪條是下坡路。我們可以利用這個(gè)知識(shí)不斷走向最低點(diǎn)。[5]
所以,如果我們對(duì)代價(jià)函數(shù)關(guān)于每一個(gè)權(quán)重求偏導(dǎo),那么我們就可以從每一個(gè)權(quán)重中減去該值。這樣可以讓我們更加接近山底。一直這樣做,最終我們將到達(dá)底部,得到權(quán)重的最優(yōu)值。(讀不懂?不用擔(dān)心,繼續(xù)往下讀)。
這種為函數(shù)找出最佳權(quán)重的方法叫做批量梯度下降(Batch Gradient Descent)。如果你對(duì)細(xì)節(jié)感興趣,不要害怕,可以看看這個(gè)詳細(xì)說明。
當(dāng)你使用一個(gè)機(jī)器學(xué)習(xí)算法庫來解決實(shí)際問題時(shí),這些都已經(jīng)為你準(zhǔn)備好了。但清楚背后的原理依然是有用的。
還有什么是本篇文章略過的內(nèi)容?
上面我描述的三步算法被稱為多元線性回歸(multivariate linear regression)。你在估算一個(gè)能夠擬合所有房?jī)r(jià)數(shù)據(jù)點(diǎn)的直線表達(dá)式。然后,你再根據(jù)房子可能在你的直線上出現(xiàn)的位置,利用這個(gè)等式來估算你從未見過的房屋的價(jià)格。這是一個(gè)十分強(qiáng)大的想法,你可以用它來解決「實(shí)際」問題。
但是,盡管我展示給你的這種方法可能在簡(jiǎn)單的情況下有效,它卻不能應(yīng)用于所有情況。原因之一,就是因?yàn)榉績(jī)r(jià)不會(huì)是簡(jiǎn)簡(jiǎn)單單一條連續(xù)的直線。
不過幸運(yùn)的是,有很多辦法來處理這種情況。有許多機(jī)器學(xué)習(xí)算法可以處理非線性數(shù)據(jù)(如神經(jīng)網(wǎng)絡(luò)或帶核函數(shù)的支持向量機(jī))。除此之外,靈活使用線性回歸也能擬合更復(fù)雜的線條。在所有的情況下,尋找最優(yōu)權(quán)重這一基本思路依然適用。
另外,我忽略了過擬合(overfitting)的概念。得到一組能完美預(yù)測(cè)原始數(shù)據(jù)集中房?jī)r(jià)的權(quán)重組很簡(jiǎn)單,但用這組權(quán)重組來預(yù)測(cè)原始數(shù)據(jù)集之外的任何新房屋其實(shí)都不怎么準(zhǔn)確。這也是有許多解決辦法的(如正則化以及使用交叉驗(yàn)證的數(shù)據(jù)集)。學(xué)習(xí)如何應(yīng)對(duì)這一問題,是學(xué)習(xí)如何成功應(yīng)用機(jī)器學(xué)習(xí)技術(shù)的重點(diǎn)之一。
換言之,盡管基本概念非常簡(jiǎn)單,要通過機(jī)器學(xué)習(xí)得到有用的結(jié)果還是需要一些技巧和經(jīng)驗(yàn)的。但是,這是每個(gè)開發(fā)者都能學(xué)會(huì)的技巧。
機(jī)器學(xué)習(xí)是黑魔法嗎?
一旦你開始明白,用機(jī)器學(xué)習(xí)技術(shù)解決那些看似困難問題(如字跡識(shí)別)有多便利時(shí),你就會(huì)有一種,只要有足夠的數(shù)據(jù),你就能夠用機(jī)器學(xué)習(xí)解決任何問題的感覺。只需要輸入數(shù)據(jù),計(jì)算機(jī)就能神奇地找出擬合數(shù)據(jù)的等式!
但是有一點(diǎn)很重要,你要記住,只有在你擁有的數(shù)據(jù)對(duì)于解決實(shí)際問題有效的時(shí)候,機(jī)器學(xué)習(xí)才能適用。
例如,如果你建立了一個(gè)根據(jù)每套房屋內(nèi)盆栽種類的數(shù)量來預(yù)測(cè)房?jī)r(jià)的模型,那它永遠(yuǎn)都不會(huì)有效果。因?yàn)榕柙苑N類的數(shù)量和房?jī)r(jià)之間沒有任何的關(guān)系。所以,無論你多賣力地嘗試,計(jì)算機(jī)永遠(yuǎn)也推導(dǎo)不出兩者之間的關(guān)系。

所以請(qǐng)記住,如果一個(gè)問題人類專家不能手動(dòng)用數(shù)據(jù)解決,計(jì)算機(jī)可能也不能解決。然而,對(duì)于那些人類能夠解決的問題,如果計(jì)算機(jī)能夠更快地解決,那豈不美哉?
怎樣學(xué)到更多機(jī)器學(xué)習(xí)的知識(shí)
我認(rèn)為,目前機(jī)器學(xué)習(xí)的最大問題是它主要活躍于學(xué)術(shù)界和商業(yè)研究組織中。對(duì)于只想大體了解一下,而不打算成為專家的人們來說,簡(jiǎn)單易懂的資料不多。但是這種情況每天正在改善。
吳恩達(dá)教授(Andrew Ng)在 Coursera 上的免費(fèi)機(jī)器學(xué)習(xí)課程非常棒。我強(qiáng)烈建議從此入手。對(duì)于任何擁有計(jì)算機(jī)或科學(xué)學(xué)位的人,或是還能記住一點(diǎn)點(diǎn)數(shù)學(xué)的人來說,都應(yīng)該非常容易入門。
另外,你還可以通過下載安裝 SciKit-Learn,用它來試驗(yàn)無數(shù)個(gè)機(jī)器學(xué)習(xí)算法。它是一個(gè) Python 框架,包含了所有常見機(jī)器學(xué)習(xí)算法的「黑盒」版本。