有一次,我和Vito(個人合夥人)聊起了當下熱門的幾種技術趨勢。當談及它們在將來可能的發展前景的時候,Vito說了下面的一段話:html
人工智能是個信息革命到蒸汽機規模之間的機會,相比之下虛擬現實應該是移動互聯網級別的,而用戶個性化服務應該是伴生規模的。git
若是人工智能技術帶來的變革確實可以比擬工業革命的話,那麼它勢必會成就一代人,同時也淘汰掉一代人。並且,仔細想一想,其實人工智能離咱們並不遙遠,甚至能夠說已經開始深刻到咱們的平常生活中了。從iPhone裏的Siri,到各大網站的內容推薦系統,再到圖像識別和人臉識別技術的普遍應用,這些場景的背後都有這項技術在發揮做用。程序員
做爲程序員,以機器學習和深度學習爲表明的人工智能技術,與咱們的關係則更加緊密。如今凡有些規模的互聯網公司,基本都有專門研究算法的團隊。在數據挖掘、Antispam、推薦系統和廣告系統,以及其它一些領域,咱們都多多少少會涉及到一些機器學習的技術。即便咱們不親自負責開發和維護這些技術,在工做中也不免會與之產生交集。算法
說了這麼多,我其實想強調的一點是:任何人都應該瞭解一點跟人工智能有關的技術,由於這是沒法阻擋的大潮,是不可避免的將來趨勢。編程
而對於一名沒有涉及到任何這方面技術的工程師來講,這項技術自己的獨特性也絕對值得你花時間去了解。你一旦瞭解就會發現,這是一種全然不一樣的編程方式。markdown
本文就是這樣的一篇科普文章,目的是向全部沒有接觸過人工智能技術的程序員(甚至非技術人員),介紹人工智能領域最前沿的神經網絡和深度學習方面的知識。也許,你看完以後,會像我第一次接觸它們的時候同樣,驚奇地感嘆:這種編程方式簡直是造物主留下的一個後門!居然用如此簡單的算法就能實現出遠遠超越本來設計的智能!網絡
好了,蓄勢完畢,相信如今你對因而否願意花時間讀完剩下的內容,已經作出本身的決定了。實際上,這項科普的工做並不輕鬆,由於這項技術涉及到很多數學知識。爲了不閱讀障礙,我會嘗試在描述的過程當中儘可能不引入複雜的數學公式,同時讓講解儘可能有趣。數據結構
要想理解深度學習,咱們就必須先理解人工神經網絡,由於神經網絡是深度學習的基礎。而要理解神經網絡,咱們就必須先理解它的基本組成單元——神經元(neuron)。機器學習
感知器(perceptron)是一種早期的神經元結構,在上個世紀五六十年代就被提出來了[1]。如今它在神經網絡中已不多被使用,但理解它有助於理清其它類型神經元的基本結構和設計思路。異步
如上圖所示,一個感知器的定義元素包括:
直觀上理解,感知器至關於一個決策模型。輸入表示進行決策時須要考慮的外在因素或條件,權重表示你對某個外在因素的重視程度,而閾值則表示你對於這個決策事件自己的喜愛程度或接受程度。
舉一個例子:假設週末有一個同窗聚會,如今你正在決策要不要去參加。你考慮的因素以下:
如今假設閾值threshold=2。咱們根據前面的規則去計算output,這個計算過程就至關於決策過程。若是output算出來等於1,那麼你就去參加聚會,不然就不去。
決策結果無非是下面幾種:
對於一個給定的感知器來講,它的權重和閾值也是給定的,表明一種決策策略。所以,咱們能夠經過調整權重和閾值來改變這個策略。
關於閾值threshold,這裏須要指出的一點是,爲了表達更方便,通常用它的相反數來表達:b=-threshold,這裏的b被稱爲偏置(bias)。這樣,前面計算輸出的規則就修改成:若是w1x1 + w2x2 + w3x3 + ... + b > 0,則輸出output=1,不然輸出output=0。
再看一下下面這個感知器。權重w1=w2=-2,而b=3。
很明顯,只有當x1=x2=1的時候,output=0,由於(−2)*1+(−2)*1+3=−1,小於0。而其它輸入的狀況下,都是output=1。這實際上是一個「與非門」!
在計算機科學中,與非門是全部門部件中比較特殊的一個,它能夠經過組合的方式表達任何其它的門部件。這被稱爲與非門的普適性(Gate Universality)[2]。
既然感知器可以經過設置恰當的權重和偏置參數,來表達一個與非門,那麼理論上它也就能表達任意其它的門部件。所以,只要建立足夠多的感知器,那麼它們便可以經過彼此鏈接從而組成一個計算機系統。但這彷佛沒有什麼值得驚喜的,咱們已經有現成的計算機了,這只不過是讓事情複雜化了而已。
單個感知器能作的事情頗有限。要作複雜的決策,咱們可能須要將多個感知器鏈接起來。就像下面這個同樣:
這個由感知器組成的網絡,包含5個輸入,8個感知器。權重參數的數量,咱們能夠算一下:5*3+3*4+4*1=31。再加上8個偏置參數,這個網絡總共有39個參數。
這個圖有一點須要說明的是:左邊第一層的每一個感知器看起來彷佛有4個輸出,而不是1個。但這是個錯覺。實際狀況是每一個感知器的那惟一的一個輸出分別鏈接到了下一層的各個感知器的輸入上了。這種表示法是爲了方便。輸出端的多條連線只是表示鏈接關係,而不表示輸出的個數。
這個感知器網絡還算是一個簡單的網絡,就已經有多達39個參數了。而實際中的網絡可能會有上萬個,甚至數十萬個參數。若是手工一個一個地去配置這些參數,恐怕這項任務永遠也完成不了了。
而神經網絡最有特點的地方就在於這裏。咱們不是爲網絡指定全部參數,而是提供訓練數據,讓網絡本身在訓練中去學習,在學習過程當中爲全部參數找到最恰當的值。
如何訓練呢?大致思路是這樣:咱們告訴網絡當輸入是某個值的時候,咱們指望的輸出是什麼。這樣的每一份訓練數據,稱爲訓練樣本(training example)。這個過程至關於老師在教學生某個抽象的知識的時候,舉一個具體例子。通常來講,咱們舉的例子越多,就越能表達那個抽象的知識。這在神經網絡的訓練中一樣成立。咱們能夠向網絡灌入成千上萬個訓練樣本,而後網絡就自動從這些樣本中總結出那份隱藏在背後的抽象的知識。這份知識的體現,就在於網絡的全部權重和偏置參數的取值。
假設各個參數有一個初始值。當咱們輸入一個訓練樣本的時候,它會根據當前參數值計算出惟一的一個實際輸出值。這個值可能跟咱們指望的輸出值不同。想象一下,這時候,咱們能夠試着調整某些參數的值,讓實際輸出值和指望輸出值儘可能接近。當全部的訓練樣本輸入完畢以後,網絡參數也調整到了最佳值,這時每一次的實際輸出值和指望輸出值已經無限接近。這樣訓練過程就結束了。
假設在訓練過程當中,網絡已經對數萬個樣本可以給出正確(或接近正確)的反應了,那麼再給它輸入一個它沒見過的數據,它也應該有很大機率給出咱們預期的決策。這就是一個神經網絡工做的原理。
但這裏還有一個問題。在訓練過程當中,當實際輸出值和指望輸出值產生差別的時候,咱們如何去調整各個參數呢?固然,在思考怎麼作以前,咱們應該先弄清楚:經過調整參數的方式得到指望的輸出,這個方法可行嗎?
實際上,對於感知器網絡來講,這個方法基本不可行。好比在上圖有39個參數的感知器網絡中,若是維持輸入不變,咱們改變某個參數的值,那麼最終的輸出基本徹底不可預測。它或者從0變到1(或從1變到0),固然也可能維持不變。這個問題的關鍵在於:輸入和輸出都是二進制的,只能是0或者1。若是把整個網絡當作一個函數(有輸入,有輸出),那麼這個函數不是連續的。
所以,爲了讓訓練成爲可能,咱們須要一個輸入和輸出可以在實數上保持連續的神經網絡。因而,這就出現了sigmoid神經元。
sigmoid神經元(sigmoid neuron)是現代神經網絡常用的基本結構(固然不是惟一的結構)。它與感知器的結構相似,但有兩個重要的區別。
第一,它的輸入再也不限制爲0和1,而能夠是任意0~1之間的實數。
第二,它的輸出也再也不限制爲0和1,而是將各個輸入的加權求和再加上偏置參數,通過一個稱爲sigmoid函數的計算做爲輸出。
具體來講,假設z=w1x1+w2x2+w3x3+...+b,那麼輸出output=σ(z),其中:
σ(z) = 1/(1+e-z)
σ(z)的函數曲線以下:
可見,σ(z)是一個平滑、連續的函數。並且,它的輸出也是0~1之間的實數,這個輸出值能夠直接做爲下一層神經元的輸入,保持在0~1之間。
能夠想象,在採用sigmoid神經元組裝神經網絡以後,網絡的輸入和輸出都變爲連續的了。也就是說,當咱們對某個參數的值進行微小的改變的時候,它的輸出也只是產生微小的改變。這樣就使得逐步調整參數值的訓練成爲可能。這個思想以下圖所示:
爲了說明神經網絡如何具體應用。這裏咱們引入一個經典的案例。這個例子來自Michael Nielsen的書《Neural Networks and Deep Learning》[3],是利用神經網絡對於手寫體數字進行識別。固然,這個例子在歷史上,不少研究人員也都作過嘗試。
這裏順便說一句,Michael Nielsen 的這本書真的很贊,沒見過哪一份資料能把神經網絡和深度學習講解得這麼透徹。這本書簡直稱得上是神經網絡的科普聖經,感興趣的初學者必定要讀一讀。
這個問題就是對相似下面這樣的手寫體數字進行識別,區分出它們具體是0到9哪個數字:
這份手寫體數據其實來源於一個公開的數據集,稱爲MNIST[4]。其中每一個數字,是一張28像素×28像素的黑白圖片,每一個像素用一個灰度值表示。
Michael Nielsen採用的神經網絡結構以下:
左側第一列圓圈表示網絡的784個輸入(注意圖中沒有畫出所有),對應一張圖片的28×28=784個像素點。每一個像素的灰度值,在通過歸一化處理以後,能夠表達爲0~1之間的數值,做爲這裏的輸入。注意:這一列圓圈並非神經元(雖然看起來像),只是輸入而已。
中間一列稱爲隱藏層(hidden layer),圖中畫出的是15個神經元節點。隱藏層上的每個節點都與每一個輸入鏈接,也就是說輸入層和隱藏層之間是全鏈接。
這個神經網絡只有一層隱藏層,屬於淺層的神經網絡(shallow neural networks)。而真正的深度神經網絡(deep nerual networks),則會有多層隱藏層。
最右側一列是輸出層(output layer),有10個神經元節點,分別表明識別結果是0,1,2,...,9。固然,受sigmoid函數σ(z)的限制,每一個輸出也確定是0~1之間的數。那咱們獲得一組輸出值以後,咱們到底認爲識別結果是哪一個數字呢?咱們能夠根據哪一個輸出的值最大,咱們就認爲識別結果就取那個數字。而在訓練的時候,咱們指望的輸出形式是:正確的那個數字輸出爲1,其它輸出爲0。隱藏層和輸出層之間也是全鏈接。
咱們能夠算一下這個神經網絡共有多少個參數。權重參數有784*15+15*10=11910個,偏置參數有15+10=25個,總共參數個數爲:11910+25=11935個。
對於這個神經網絡的訓練過程,就是要肯定這11935個參數。訓練的目標能夠粗略歸納爲:對於每個訓練樣本,咱們指望的那個正確數字,對應的輸出無限接近於1,而其它輸出無限接近於0。
先不說具體的學習方法(下一節會介紹),咱們先說一下神經網絡這種編程方式在這一具體問題上取得的結果。根據Michael Nielsen給出的實驗結果,以上述網絡結構爲基礎,在未通過調優的狀況下,能夠輕鬆達到95%的正確識別率。而核心代碼只有74行!
在採用了深度學習的思路和卷積網絡(convolutional networks)以後,最終達到了99.67%的正確識別率。而針對MNIST數據集達到的歷史最佳成績是99.79%的識別率,是由Li Wan, Matthew Zeiler, Sixin Zhang, Yann LeCun, 和 Rob Fergus在2013年作出的。
考慮到這個數據集裏還有一些相似以下這樣難以辨認的數字,這個結果是至關驚人的!它已經超越了真正人眼的識別了。
在本文前面一節,咱們已經對神經網絡的訓練過程進行了描述,但其中關鍵的一步尚未介紹,就是如何在這個過程當中一步步調整權重和偏置參數的值呢?要講清楚這個問題,咱們就必須引入梯度降低算法(gradient descent)。
在訓練的過程當中,咱們的神經網絡須要有一個實際可行的學習算法,來逐步調整參數。要設計這樣一個學習算法,咱們首先要明確訓練的目標。
咱們訓練的最終目的,是讓網絡的實際輸出與指望輸出可以儘可能接近。咱們須要找到一個表達式來對這種接近程度進行表徵。這個表達式被稱爲代價函數(cost function)。
一個比較常見的cost function以下所示:
這是本文出現的最複雜的一個公式了。但不用恐懼,咱們對它分析一下,只要能理解它的主旨就好:
總結來講,C(w,b)表徵了網絡的實際輸出值和指望輸出值的接近程度。越接近,C(w,b)的值就越小。所以,學習的過程就是想辦法下降C(w,b)的過程。而無論C(w,b)的表達形式如何,它是w和b的函數,這就變成了一個求函數最小值的最優化問題。
因爲C(w,b)的形式比較複雜,參數也很是多,因此直接進行數學上的求解,很是困難。爲了利用計算機算法解決這一問題,計算機科學家們提出了梯度降低算法(gradient descent)。這個算法本質上是在多維空間中沿着各個維度的切線貢獻的方向,每次向下邁出微小的一步,從而最終抵達最小值。
因爲多維空間在視覺上沒法體現,因此人們一般會退到三維空間進行類比。當C(w,b)只有兩個參數的時候,它的函數圖像能夠在三維空間裏呈現。以下所示:
就好像一個小球在山谷的斜坡上向下不停地滾動,最終就有可能到達谷底。這個理解從新推廣到多維空間內也基本成立。
而因爲訓練樣本的數量很大(上萬,幾十萬,甚至更多),直接根據前面的C(w,b)進行計算,計算量會很大,致使學習過程很慢。因而就出現了隨機梯度降低(stochastic gradient descent)算法,是對於梯度降低的一個近似。在這個算法中,每次學習再也不針對全部的訓練集,而是從訓練集中隨機選擇一部分來計算C(w,b),下一次學習再從剩下的訓練集中隨機選擇一部分來計算,直到把整個訓練集用光。而後再不斷重複這一過程。
深度神經網絡(具備多個hidden layer)比淺層神經網絡有更多結構上的優點,它有能力從多個層次上進行抽象。
上圖表達了在一個基於深度學習的圖像識別過程當中,逐層抽象的過程:
從上個世紀八九十年代開始,研究人員們不斷嘗試將隨機梯度降低算法應用於深度神經網絡的訓練,但卻碰到了梯度消失(vanishing gradient)或梯度爆發(exploding gradient)的問題,致使學習過程異常緩慢,深度神經網絡基本不可用。
然而,從2006年開始,人們開始使用一些新的技術來訓練深度網絡,不斷取得了突破。這些技術包括但不限於:
限於篇幅緣由,咱們有機會下次再討論這些技術細節。
根據本文前面的介紹,深度學習的優勢顯而易見:這是一種全新的編程方式,它不須要咱們直接爲要解決的問題設計算法和編程,而是針對訓練過程編程。網絡在訓練過程當中就能本身學習到解決問題的正確方法,這使得咱們能夠用簡單的算法來解決複雜的問題,並且在不少領域賽過了傳統方法。而訓練數據在這個過程發揮了更重要的做用:簡單的算法加上覆雜的數據,可能遠勝於複雜的算法加上簡單的數據。
但這項技術的一些缺點咱們也不得不警戒:
記得前一段時間在朋友圈流傳甚廣BetaCat的故事,講的就是一我的工智能程序,經過自我學習,最終逐漸統治世界的故事。
那麼,如今的人工智能技術的發展,會致使這種狀況發生嗎?會致使強人工智能的出現嗎?
恐怕還不太可能。我的感受,大概有兩個重要因素:
可是,本着實用的角度,這仍然是一種很是吸引人,並且頗有前景的技術。
前段時間,朋友圈裏流傳着另一個故事:一個日本小夥(一位工程師)利用深度學習技術,嘗試爲他母親的農場設計了分選黃瓜的機器,大大減輕了他母親在農忙時節的工做量。
那麼,一樣做爲工程師的你,是否也想利用生平所學,爲媽媽作一點事呢?
(完)
注:本文圖片素材來源[3][5]。
其它精選文章: