深度學習入門系列,用白話文的方式讓你看得懂學的快(第七章、第八章)

前接第五章、第六章:深度學習入門系列,用白話文的方式讓你看得懂學的快(第五章、第六章)

山重水複疑無路,最快下降問梯度(深度學習入門系列之七)

原文再續,書接上回。

一年多前,吳軍博士寫了一本暢銷書《智能時代》[1]。書里提到,在人工智慧領域,有一個流派叫「鳥飛派」,亦稱之為「模仿派」。說的是,當人們要學習飛翔的時候,最先想到的是模仿鳥一樣去飛翔。

很多年前,印度詩人泰戈爾出了本《飛鳥集》,裡面有個名句:「天空沒有留下翅膀的痕迹,但我已經飛過」。有人對此解讀為,「人世間,很多事情雖然做過了,卻不為人所知,但那又如何?重要的是,我已做過,並從中獲得了許多。」

兩千多年前,司馬遷在《史記?滑稽列傳》寫到:「此鳥不飛則已,一飛衝天;不鳴則已,一鳴驚人。」說的是當年楚莊王在「勢不眷我」時,選擇了「蟄伏」。蟄伏,只是一個儲勢過程,遲早有一天,蓄勢待發,「發」則達天。

這三者的情感交集,讓我聯想到出了本章的主人公傑弗里?辛頓(Geoffrey Hinton)教授,在學術界里,他就是這樣的一個「勵志」人物!

1986年,辛頓教授和他的小夥伴們重新設計了BP演算法,以「人工神經網路」模仿大腦工作機理,「吻」醒了沉睡多年的「人工智慧」公主,一時風光無限。

但「好花不常開,好景不常在」。當風光不再時,辛頓和他的研究方向,逐漸被世人所淡忘。

這被「淡忘」的冷板凳一坐,就是30年。

但在這30年里,辛頓又如「飛鳥」一般,即使「飛過無痕」,也從不放棄。從哪裡跌倒,就從哪裡爬起。實在不行,即使換個馬甲,也要重過一生。

玉汝於成,功不唐捐。

終於,在2006年,辛頓等人提出了「深度信念網(Deep Belief Nets,DBN)」(這實際上就是多層神經網路的馬甲)[2]。這個「深度信念網」後期被稱為「深度學習」。終於,辛頓再次閃耀於人工智慧世界,隨後被封為「深度學習教父」。

但細心的讀者可發現,即使辛頓等人提出了「深度信念網」,在隨後的小10年里,這個概念亦是不溫不火地發展著(如圖1所示)。直到後期(2012年以後),隨著大數據和大計算(GPU、雲計算等)的興起,深度學習才開始大行其道,一時間甚囂塵上。

(圖7-1 深度學習的谷歌趨勢圖)

回顧起傑弗里?辛頓過往40多年的學術生涯,可謂是顧跌宕起伏,但最終修得正果。倘若細細說起,這「牛逼」,還得從1986年吹起。

7.1 1986年的那篇神作

1986年10月,傑弗里?辛頓還在卡內基梅隆大學任職。他和在加州大學聖迭戈分校的認知心理學家大衛·魯梅爾哈特(David Rumelhart)等人,在著名學術期刊《自然》上聯合發表題為:「通過反向傳播演算法的學習表徵(Learning Representations by Back-propagating errors)」的論文[3]。該文首次系統簡潔地闡述反向傳播演算法(BP)在神經網路模型上的應用,該演算法把網路權值糾錯的運算量,從原來的與神經元數目的平方成正比,下降到只和神經元數目本身成正比。

與此同時,當時的大背景是,在八十年代末,Intel x86系列的微處理器和內存技術的發展,讓計算機的運行速度和數據訪存速度也比二十年前高了幾個數量級。這一下(運算量下降)一上(計算速度上升),加之多層神經網路可通過設置隱含層 (hidden layer),極大增強了數據特徵的表徵能力,從而輕易解決感知機無法實現的異或門 (XOR gate)難題,這些「天時地利人和」的大好環境,極大緩解了當年明斯基對神經網路的責難。

於是,人工神經網路的研究,漸漸得以復甦。

(圖7-2 1986年傑弗里?辛頓的那篇神作)

值得一提的是,在文獻[3]中,傑弗里?辛頓並不是第一作者,魯梅爾哈特才是,而辛頓僅僅「屈居」第二(如圖7-2所示)。但為什麼我們提起BP演算法時,總是說起辛頓呢?其實原因也很簡單,主要有二:第一、魯梅爾哈特畢竟並非計算機科學領域之內的人士,我們計算機科學家,總不能找一個腦科學家去「拜碼頭」吧;第二、辛頓是這篇論文的通信作者,通常而言,通信作者才是論文思路的核心提供者,這樣一來,即使作者排名第二,也沒有埋沒掉辛頓教授的貢獻。

同在1986年,魯梅爾哈特也和自己的小夥伴們合作發表了一篇題為「並行分散式處理:來自認知微結構的探索」的論文[4]。僅僅從論文題目的前半部分來看,我們很可能誤解這是一個有關「高性能計算」的文章,但從標題的後半部分可以得知,這是魯梅爾哈特等人對人類大腦研究的最新認知。魯梅爾哈特對大腦工作機理的深入觀察,極大地啟發了辛頓。辛頓靈光一現,覺得可以把這個想法遷移到「人工神經網路」當中。於是,就有了他們神來一筆的合作。

我們知道,1986年,辛頓和魯梅爾哈特能在大名鼎鼎的《自然》期刊上發表論文,自然不是泛泛而談,它一定是解決了什麼大問題。下面我們就聊聊這個話題。

7.2 多層感知機網路遇到的大問題

由於歷史的慣性,在第六講中提到的多層前饋網路,有時也被稱為多層感知機(Multilayer Perceptron,MLP)。但這個提法導致概念多少有些混淆。這是因為,在多層前饋網路中,神經元的內部構造已悄然發生變化,即激活函數從簡單粗暴的「階躍函數」變成了比較平滑的擠壓函數Sigmoid(如圖7-3所示)。

激活函數為什麼要換成Sigmoid呢?其實原因並不複雜,這是因為感知機的激活函數是階躍函數,不利於函數求導,進而求損失函數的極小值。我們知道,當分類對象是線性可分,且學習率(learning rate)η足夠小時,由感知機還不堪勝任,由其構建的網路,還可以訓練達到收斂。但分類對象不是線性可分時,感知機就有點「黔驢技窮」了。因此,通常感知機並不能推廣到一般前饋網路中。

(圖 7-3 變更激活函數的前饋多層神經網路)

按照我們前面章節的說法,所謂的機器學習,簡單來說,就是找到一個好用的函數(function),從而較好地實現某個特定的功能(function)。一言蔽之,函數就是功能。而對於某個特定的前饋神經網路,給定網路參數(連接權值與閾值),其實就是定義了一個具備數據採集(輸入層)、加工處理(隱含層),然後輸出結果(輸出層)的函數。

如果僅僅給定一個網路結構,其實它定義的是一個函數集合。因為不同的網路參數(連接權值與閾值),實現的功能「大相徑庭」。功能不同,自然函數也是不同的!

針對前饋神經網路,我們需要實現的目的很簡單,就是想讓損失函數達到最小值,因為只有這樣,實際輸出和預期輸出的差值才最小。那麼,如何從眾多網路參數(神經元之間的鏈接權值和閾值)中選擇最佳的參數呢?

最簡單粗暴的方法,當然就是枚舉所有可能值了!

(圖7-4 暴力調參不可取)

但這中暴力策略,對稍微複雜一點的網路就不可取了!例如,用於語音識別的神經網路,假設網路結構有7層,每一層有1000個神經元,那麼僅一層之間的全連接權值,就達到1000×1000=106個,一旦層次多了,那權值數量就海了去了!(如圖7-4所示)。故此,這種暴力調參找最優參數,既不優雅,也不高效,故實不可取!

7.3到底什麼是梯度?

為了克服多層感知機存在的問題,人們設計了一種名為delta(Δ)法則(delta rule)的啟發式方法,該方法可以讓目標收斂到最佳解的近似值[5]。

delta法則的核心思想在於,使用梯度下降(gradient descent)的方法找極值。具體說來,就是在假設空間中搜索可能的權值向量,並以「最佳」的姿態,來擬合訓練集合中的樣本。那麼,何謂最佳擬合呢?當然就是讓前文提到的損失函數達到最小值!

我們知道,求某個函數的極值,難免就要用到「導數」等概念。既然我們把這個系列文章定位為入門層次,那不妨就再講細緻一點。什麼是導數呢?所謂導數,就是用來分析函數「變化率」的一種度量。針對函數中的某個特定點x0,該點的導數就是x0點的「瞬間斜率」,也即切線斜率,見公式(7.1)。

如果這個斜率越大,就表明其上升趨勢越強勁。當這個斜率為0時,就達到了這個函數的「強弩之末」,即達到了極值點。而前文提到的損失函數,如果要達到損失最小,就難免用到導數「反向指導」如何快速抵達極小值。

在單變數的實值函數中,梯度就可以簡單地理解為只是導數,或者說對於一個線性函數而言,梯度就是線的斜率。但對於多維變數的函數,它的梯度概念就不那麼容易理解了。下面我們來談談這個概念。

在向量微積分中,標量場的梯度其實是一個向量場(vector filled)。對於特定函數的某個特定點,它的梯度就表示從該點出發,該函數值增長最為迅猛的方向(direction of greatest increase of a function)[6]。假設一個標量函數f的梯度記為:f或gradf,這裡的表示向量微分運算元。那麼,在一個三維直角坐標系,該函數的梯度就可以表示為公式(7.2):

求這個梯度值,難免要用到「偏導」的概念。說到「偏導」,這裡順便「輕拍」一下國內的翻譯。「偏導」的英文本意是「partial derivatives(局部導數)」,書本上常翻譯為「偏導」,可能會把讀者的思路引導「偏」了。

那什麼是「局部導數」呢?對於多維變數函數而言,當求某個變數的導數(相比於全部變數,這裡只求一個變數,即為「局部」),就是把其它變數視為常量,然後整個函數求其導數。之後,這個過程對每個變數都「臨幸」一遍,放在向量場中,就得到了這個函數的梯度了。舉例來說,對於3變數函數f=x2+3xy+y2+z3,它的梯度可以這樣求得:

(1) 把y,z視為常量,得x的「局部導數」:

(2) 然後把xx,z視為常量,得y的「局部導數」:

(3) 最後把xx,y視為常量,得z的「局部導數」:

於是,函數f的梯度可表示為:

針對某個特定點,如點A(1, 2, 3),帶入對應的值即可得到該點的梯度:

這時,梯度可理解為,站在向量點A(1, 2, 3),如果想讓函數f的值增長得最快,那麼它的下一個前進的方向,就是朝著向量點B(8,7,27)方向進發(如圖7-3所示)。很顯然,梯度最明顯的應用,就是快速找到多維變數函數的極(大/小)值。

(圖7-5 梯度概念的示意圖)

在這裡需要說明的是,我們用「局部導數」的翻譯,僅僅是用來加深大家對「偏導」的理解,並不是想糾正大家已經約定俗成的叫法。所以為了簡單起見,在後文我們還是將「局部導數」稱呼為「偏導」。

7.4 到底什麼是梯度下降?

上面我們提到了梯度的概念,下面我們說說在求損失函數極小值過程中,常常提到的「梯度遞減」的概念。

我們先給出一個形象的案例。爬過山的人,可能會有這樣的體會,爬坡愈平緩(相當於斜率較小),抵達山峰(函數峰值)的過程就越緩慢,而如果不考慮爬山的重力阻力(對於計算機而言不存在這樣的阻力),山坡越陡峭(相當於斜率越大),順著這樣的山坡爬山,就越能快速抵達山峰(對於函數而言,就是愈加快速收斂到極值點)。

(圖7-6 梯度遞減求極小值)

如果我們把山峰「乾坤大挪移」,把爬山峰變成找谷底(即求極小值),這時找斜率最陡峭的坡而攀爬山峰的方法,並沒有本質變化,不過是方向相反而已。如果把登山過程中求某點的斜率稱為「梯度(gradient)」,而找谷底的方法,就可以把它稱之為「梯度遞減(gradient descent)」,示意圖如圖7-6所示。

依據「梯度遞減」作為指導,走一步,算一步,一直遵循「最陡峭」的方向,探索著前進,這個過程,是不是有點像鄧公的名句「摸著石頭過河」?

這個「梯度遞減」體現出來的指導意義,就是「機器學習」中的「學習」內涵,即使在大名鼎鼎的「AlphaGo」中,「學習」這是這麼玩的!你是不是有點失望?這機器學習也太不高大上了!

但別忘了,在第一講中,我們就已經講到「學習」的本質,在於性能的提升。利用「梯度遞減」的方法,的確在很大程度上,提升了機器的性能,所以,它就是「學習」!

當然,從圖7-3中,我們也很容易看到「梯度遞減」的問題所在,那就是它很容易收斂到局部最小值。正如攀登高峰,我們會感嘆「一山還比一山高」,探尋谷底時,我們也可能發現,「一谷還比一谷低」。但是「只緣身在此山中」,當前的眼界讓我們像「螞蟻尋路」一樣,很難讓我們有全局觀,因為我們都沒有「上帝視角」。

7.5 重溫神經網路的損失函數

針對前饋神經網路的設計,輸入和輸出層設計比較直觀。比如說,假如我們嘗試判斷一張手寫數字圖片上面是否寫著數字「2」。很自然地,我們可以把圖片像素的灰度值作為網路的輸入。如果圖片的維度是16×16,那麼我們輸入層神經元就可以設計為256個(也就是說,輸入層是一個包括256個灰度值向量),每個神經元接受的輸入值,就是規格化的灰度值。

而輸出層的設計也很簡單,就是需要包含10神經元,輸出是數字「0~9」的分類概率(也就是說,輸出層是一個包括10個概率值的向量)。擇其大者而判之,如圖7-7所示,如果判定為「2」的概率(比如說80%)遠遠大於其他數字,那麼整個神經網路的最終判定,就是手寫圖片中的數字是「2」,而非其它數字。

相比於神經網路輸入、輸出層設計的簡單直觀,它的隱含層設計,可就沒有那麼簡單了。說好聽點,它是一門藝術,依賴於「工匠」的打磨。說不好聽點,它就是一個體力活,需要不斷地「試錯」。

但通過不斷地「折騰」,研究人員還真是掌握了一些針對隱層的啟發式設計規則(如下文即將提到的BP演算法),以此降低訓練網路所花的開銷,並盡量提升網路的性能。

那麼,怎樣才算是提升神經網路性能呢?這就需要用到前面我們前面提到的損失函數了。在第六章我們提到,所謂「損失函數」,就是一個刻畫實際輸出值和期望輸出值之間「落差」的函數。

為了達到理想狀態,我們當然希望這種「落差」最小,也就是說,我們希望快速配置好網路參數,從而讓這個損失函數達到極小值。這時,神經網路的性能也就接近最優!

關於求損失函數極小值,台灣大學李弘毅博士給出了一個通俗易懂的例子,下面我們來說說。對於識別手寫數字的神經網路,訓練數據都是一些「0,1 2, …, 9」等數字圖像,如圖7-8所示。

(圖7-8 識別手寫數字的神經網路)

由於人們手寫數字的風格不同,圖像的殘缺程度不同,輸出的結果有時並不能「十全十美」,於是我們就用損失函數來衡量二者的誤差。前面我們提到,常用的損失函數是:

機器學習的任務,在很大程度上,找一個模型,擬合(fitting)或者說「適配」給定的訓練數據,然後再用這個模型預測新數據。這個模型的表現形式,具體說來,就是設計一個好用的函數,用以揭示這些訓練樣本隨自變數的變化關係。揭示擬合好壞的程度,就要用到損失函數。「損失」越小,說明擬合的效果就越好。

(圖7-9 用梯度遞減,更新網路權值)

在我們訓練神經網路時,損失函數說白了,就是有關「權值參數」的函數。為了求損失函數的極小值,就不可避免地需要計算損失函數中每一個權值參數的偏導數,這時前文中提到的「梯度遞減」方法就派上用場了。訓練線性單元的梯度遞減演算法示意圖如圖7-9所示,圖中的參數η就是「學習率」,它決定了梯度遞減搜索的步長,這個步長「過猶不及」。如果值太小,則收斂慢,如果值太大,則容易越過極值,導致網路震蕩,難以收斂。

圖7-9僅僅給出一個權值變數wiwi的梯度示意圖,而實際上,神經網路中的參數是非常多的,因此針對損失函數LL的權值向量的梯度w? w→可以記作:

在這裡,?L(w? )本身就是一個向量,它的多個維度分別由損失函數LL對多個權值參數wi求偏導所得。當梯度被解釋為權值空間的一個向量時,它就確定了L對陡峭上升的方向。

如果需要根據圖7-9所示的公式來更新權值,我們需要一個更加實用的辦法,在每一步重複計算。幸運的是,這個過程並不複雜,通過簡易的數學推導,我們可以得到每個權值分量wi更加簡明的計算公式:

其中,xid表示訓練集合第dd個樣例的輸入分量xixi,ydyd表示第dd樣例的期望輸出值,y′d表示第d樣例的實際輸出值,這二者的差值就是「損失(loss)」,也稱之為誤差(error)。有了公式(7.5)做支撐,圖7-9所示的演算法就可行之有「章法」了。

有了前面的知識鋪墊,我們終於可以在下一章談談誤差反向傳播(Back Propagation,BP)演算法了。

7.6 小結

在本章中,我們主要講解了梯度的概念。所謂梯度,就是該函數值增長最為迅猛的方向,然後我們介紹了梯度下降法則。

在下一章中,我們將用最為通俗易懂的圖文並茂的方式,給你詳細解釋誤差反向傳播(BP)演算法。BP演算法不僅僅是作為經典留在我們的記憶里,而且,它還「歷久彌新」活在當下。要知道,深度信念網(也就是深度學習)之所以性能奇佳,不僅僅是因為它有一個「無監督」的逐層預訓練(unsupervised layer-wise training),除此之外,預訓練之後的「微調(fine-tuning)」,還是需要「有監督」的BP演算法作為支撐。

由此可見,BP演算法影響之深,以至於「深度學習」都離不開它!

「世上沒有白走的路,每一步都算數」。希望你能持續關注。

7.7 請你思考

通過本章的學習,請你思考如下問題:

(1)在前饋神經網路中,隱含層設計多少層、每一層有多少神經元比較合適呢?我們可以設定一種自動確定網路結構的方法嗎?

(2)神經網路具有強大的特徵表徵能力,但「成也蕭何,敗也蕭何」,BP演算法常常遭遇「過擬合(overfitting)」,它可能會把噪音當做有效信號,你知道有什麼策略來避免過擬合嗎?

【參考文獻】

[1] 吳軍. 智能時代. 中信出版集團. 2016.8

[2] Hinton G E, Osindero S, Teh Y W. A fast learning algorithm for deep belief nets[J]. Neural computation, 2006, 18(7): 1527-1554.

[3] Williams D, Hinton G. Learning representations by back-propagating errors[J]. Nature, 1986, 323(6088): 533-538.

[4] Rumelhart D E, McClelland J L, PDP Research Group. Parallel Distributed Processing, Volume 1 Explorations in the Microstructure of Cognition: Foundations[J]. 1986.

[5] Tom Mitchell著.曾華軍等譯. 機器學習. 機器工業出版社. 2007.4

[6] Better Explained. Vector Calculus: Understanding the Gradient

文章作者:張玉宏,著有《品味大數據》一書。審校:我是主題曲哥哥。

---------------------華麗的分割線---------------------

BP演算法雙向傳,鏈式求導最纏綿(深度學習入門系列之八)

8.1 BP神經網路極簡史

在神經網路(甚至深度學習)參數訓練中,BP(Back Propagation)演算法非常重要,它都佔據舉足輕重的地位。在提及BP演算法時,我們常將它與傑弗里?辛頓(Geoffrey Hinton)的名字聯繫在一起。但實際上,辛頓還真不是第一個提出BP演算法的人,就像愛迪生不是第一個發明電燈的人一樣。但人們記住的,永遠都是那個讓電燈「飛入平常百姓家」的功勛人物愛迪生,而不是它的第一發明人美國人亨利·戈培爾(Henry Goebel)。

如果說辛頓就是BP演算法的「愛迪生」,那誰是BP演算法的「戈培爾」呢?他就是保羅·沃伯斯(Paul Werbos)。1974年,沃伯斯在哈佛大學博士畢業。在他的博士論文里,首次提出了通過誤差的反向傳播來訓練人工神經網路[1]。事實上,這位沃伯斯不光是BP演算法的開創者,他還是循環神經網路(Recurrent Neural Network,RNN)的早期開拓者之一。在後期的系列入門文章中,我們還會詳細介紹RNN,這裡暫且不表。

說到BP演算法,我們通常強調的是反向傳播,但其實呢,它是一個典型的雙向演算法。更確切來說,它的工作流程是分兩大步走:(1)正向傳播輸入信號,輸出分類信息(對於有監督學習而言,基本上都可歸屬於分類演算法);(2)反向傳播誤差信息,調整全網權值(通過微調網路參數,讓下一輪的輸出更加準確)。

下面我們分別舉例,說明這兩個流程。為了簡化問題描述,我們使用如圖8-1所示的最樸素三層神經網路。在這個網路中,假設輸入層的信號向量是[-1, 1],輸出層的目標向量為[1, 0],「學習率」η為0.1,權值是隨機給的,這裡為了演示方便,分別給予或「1」或「-1」的值。下面我們就詳細看看BP演算法是如何運作的?

(圖8-1 簡易的三層神經網路)

8.2.1正向傳播信息

正向傳播信息,簡單說來,就是把信號通過激活函數的加工,一層一層的向前「蔓延」,直到抵達輸出層。在這裡,假設神經元內部的激活函數為Sigmod(

)。之所以選用這個激活函數,主要因為它的求導形式非常簡潔而優美:

事實上,類似於感知機,每一個神經元的功能都可細分兩大部分:(1)彙集各路鏈接帶來的加權信息;(2)加權信息在激活函數的「加工」下,神經元給出相應的輸出,如圖8-2所示。

(圖8-2 單個神經元的兩部分功能)

於是,在正向傳播過程中,對於f1(e)f1(e)神經元的更新如圖8-3所示,其計算過程如下所示:

(圖8-3 神經元信息前向更新神經元1的f1(e))

接著,在同一層更新f2(e)f2(e)的值,過程和計算步驟類似於f1(e)f1(e),如圖8-4所示:

(圖8-4 神經元信息前向更新神經元2的f2(e))

接下來,信息正向傳播到下一層(即輸出層),更新神經元3的f3(e)f3(e)(即輸出y1y1的值),如圖8-5所示。

(圖8-5 神經元信息前向更新神經元3的f3(e))

然後,類似地,計算同在輸出層求神經元f4(e)(即輸出y2)的值,如圖8-6所示。

(圖8-6神經元信息前向更新f4(e))

到此,在第一輪信號前向傳播中,實際輸出向量已計算得到y′=[0.65,0.59]T,但我們預期輸出的向量(即教師信號)是y=[1,0]T,這二者之間是存在「誤差」的。於是,重點來了,下面我們就用「誤差」信息反向傳播,來逐層調整網路參數。為了提高權值更新效率,這裡就要用到下文即將提到的「反向模式微分法則(chain rule)」。

8.2.2 求導中的鏈式法則

(砰!砰!砰!敲黑板!請注意:如下部分是BP演算法最為精妙之處,值得細細品味!)

在前面信號正向傳播的示例中,為了方便讀者理解,我們把所有的權值都暫時給予了確定之值。而實際上,這些值都是可以調整的,也就是說其實它們都是變數,除掉圖8-1中的所有確定的權值,把其視為變數,得就到更為一般化的神經網路示意圖8-7。

(圖8-7 帶權重變數的神經網路)

這裡為了簡化理解,我們暫時假設神經元沒有激活函數(或稱激活函數為y=x),於是對於隱含層神經元,它的輸出可分別表示為:

然後,對於輸出層神經元有:

於是,損失函數L可表示為公式(8.2):

這裡YY為預期輸出值向量(由y1,y2,...,yi,...等元素構成),實際輸出向量為fi(w11,w12,...,wij,...,wmn)。對於有監督學習而言,在特定訓練集合下,輸入元素xi和預期輸出yiyi都可視為常量。由此可以看到,損失函數LL,在本質上,就是一個單純與權值wij相關的函數(即使把原本的激活函數作用加上去,除了使得損失函數的形式表現得更加複雜外,並不影響這個結論)。

於是,損失函數L梯度向量可表示為公式(8.3):

其中,這裡的eij是正交單位向量。為了求出這個梯度,需要求出損失函數LL對每一個權值wij的偏導數。

BP演算法之所以經典,部分原因在於,它是求解這類「層層累進」的複合函數偏導數的利器。為啥這麼說呢?下面,我們就列舉一個更為簡化但不失一般性的例子來說明這個觀點(以下案例參考了Chris Olah的博客文章[3])。

假設有如下一個三層但僅僅包括a、b、c、d和e等5個神經元的網路,在傳遞過程中,c、d和e神經元對輸入信號做了簡單的加工,如圖8-8所示。

(圖8-8 簡易的神經網路)

假設變數aa影響cc,此時我們想弄清楚a是如何影響c的。於是我們考慮這麼一個問題,如果a變化一點點,那麼c是如何變化的呢?我們把這種影響關係定義為變數c相對於變數a的偏導數,記做?c/?a。

利用高等數學的知識,我們很容易求得,對於直接相連的神經元(如a對c,或b對d),可利用「加法規則」或「乘法規則」直接求出。例如,利用加法規則,?c/?a可表示為:

而對於表達式為乘法的求偏導規則為:

那麼,對於間接相連的神經元,比如aa=對e,如果我們也想知道a變化一點點時e變化多少,怎麼辦呢?也就是說,偏導數?e/?a該如何求呢?這時,我們就需要用到鏈式法則了。

這裡假設a=2,b=1。如果aa的變化速率是1,那麼c的變化速率也是1(因為?c/?a=1)。類似地,如果c的變化速率為1,那麼e的變化速率為2(因為?e/?c=d=2)。所以相對於a變化1,e的變化為1×2=2。這個過程就是我們常說的「鏈式法則」,其更為形式化的表達為(如圖8-9所示):

(圖8-9 鏈式法則示意圖)

a對e的「影響」屬於單路徑的影響,還比較容易求得,但這並不是我們關注的重點。因為在神經網路中,神經元對神經元的連接,阡陌縱橫,其影響也是通過多條路徑「交織」在一起的。在圖8-9中,我們研究一下b對e的影響,就能比較好理解這一工作機理。顯然,b對e的影響,也可表達為一個偏導關係:

從圖8-9可以看出,b對e影響,其實是「兵分兩路」:(1)b通過影響c,然後通過c影響e;(2)b通過影響d,然後通過d影響e。這就是多維變數(這裡「多」僅為2)鏈式法則的「路徑加和」原則。

這個原則,看起來簡單明了,但其實蘊藏著巨大代價。因為當網路結構龐大時,這樣的「路徑加和」原則,很容易產生組合爆炸問題。例如,在如圖8-10所示的有向圖中,如果X到Y有三條路徑(即X分別以α、β和χ的比率影響Y),Y到Z也有三條路徑(Y分別以δ、ε和ξ的比率影響Z)。

(圖8-10 路徑加和規則演示)

於是,很容易根據路徑加和原則得到X對Z的偏導數:

上面用到的求偏導數方法,可稱之為「前向模式微分(forward-mode differentiation)」,如圖8-11-(a)所示。當網路結構簡單時,即使X到Z的每一個路徑都被「臨幸(遍歷)」一遍,總共才有 3×3=9條路徑,但一旦網路結構的複雜度上去了,這種「前向模式微分」,就會讓求偏導數的次數和神經元個數的平方成正比。這個計算量,就很可能是成為機器「難以承受的計算之重」。

有道是「東方不亮西方亮」。為了避免這種海量求導模式,數學家們另闢蹊徑,提出了一種稱之為「反向模式微分(reverse-mode differentiation)」。取代公式(8.4)的那種簡易的表達方式,我們用公式(8.5)的表達方式來求X對Z的偏導:

或許你會不屑一顧,這又是在搞什麼鬼?把公式(8.4)恆等變換為公式(8.5)又有什麼用呢?

(圖8-11 前向與反向微分方法對比)

你可別急,這背後大有玄機,且聽我慢慢道來。

前文提到的前向模式微分方法,其實就是我們在高數課堂上學習的求導方式。在這種求導模式中,強調的是某一個輸入(比如X)對某一個節點(如神經元)的影響。因此,在求導過程中,偏導數的分子部分,總是根據不同的節點總是不斷變化,而分母則鎖定為偏導變數「?X」,保持定不變(見圖8-11-(a))。

相比而言,反向模式微分方法則有很大不同。首先在求導方向上,它是從輸出端(output)到輸入端進行逐層求導。其次,在求導方法上,它不再是對每一條「路徑」加權相乘然後求和,而是針對節點採納「合併同類路徑」和「分階段求解」的策略。

拿8-11-(b)的例子來說,先求Y節點對Z節點的"總影響"(反向第一層):

然後,再求節點X對節點Z的總影響(反向第二層):

特別需要注意的是,?Z/?Y?已經在第一層求導得到。在第二層僅僅需要求得?Y/?X,而?Y/?X? 容易求得(α+β+χ),然後二者相乘即可得到所求。這樣一來,就大大減輕了第二層的求導負擔。在求導形式上,偏導數的分子部分(節點)不變,而分母部分總是隨著節點不同而變化,即[?Z/?]。

這樣說來說去,好像還是不太明白!下面我們還是用圖8-9所示的原始例子,對比二者的求導過程,一遍走下來,有了感性認識,你就能明白其中的差異。為了進一步方便讀者理解,我們將圖8-9重新繪製為圖8-12的樣子。

(圖8-12 前向模式微分方法)

以求變數b偏導數的流程為例,我們先用前向模式微分法,來說明這種方法的求導過程。根據加法規則,對於求偏導值?e/?b的步驟可以分兩步走:(1)求得所有輸入(包括a和b)到終點e的每條路徑上的偏導值乘積;(2)對所有條路徑的導數值進行加和操作。

從8-12所示的圖中,對於兩個輸入a和b,它們共有3條路徑抵達終點e(分別計為①、②和③)。

對於第①條路徑而言,輸入a對e的影響為:

對於第②條路徑而言,輸入b對e的影響為:

對於第③條路徑而言,輸入b對e的影響為:

所以在整體上,輸入a和b從三條路徑上對e施加的「總影響」為:0+2+3=5.

或許讀者已經注意到了,有些路徑已經被冗餘遍歷了,比如在圖8-12所示中,a→c→e(第①條路)和b→c→e(第②條路)就都走了路徑c→e。

這些局部性的冗餘也就罷了,更為「惡劣」的是,對於求?e/?a,上述三條路徑,它們同樣還得「一個都不能少」地跑一遍,如果求得的變數多了,這到底得有多少冗餘啊!

可能你會疑問,對於?e/?b(?e/?a),第①(③)條路徑明明可以不走的嘛?這種明智,是對人的觀察而言的,而且是對於簡單網路而言的。因為,如果網路及其複雜,人們可能就沒有這麼「慧眼識珠」,識別其中的路徑冗餘。

此外,對於計算機而言,有些時候,局部操作的「優化」,相對於整體操作的「規範化」,頂多算得上「奇淫巧技」,其優勢可謂是「蕩然無存」。有過大規模並行編程經驗的讀者,可能對這個觀點會有更深的認知。

然而,同樣是利用鏈式法則,反向模式微分方法就能非常機智地避開了這種冗餘(下面即將講到的BP演算法,正是由於這麼干,才有其優勢的)。在這種方法中,它能做到對每一條路徑只「臨幸」一次,這是何等的節儉!下面我們來看看它是如何工作的。

(圖8-13反向模式微分方法)

相比於「前向模式微分法」是以輸入(如圖8-13-(a)所示的a和b)為錨點,正向遍歷每一條可能的路徑。反向模式微分法是以節點(或說神經元,如圖8-13-(a)所示的e、c和d)為錨點,逐層分階段求導,然後彙集每一個節點的外部路徑(合併同類路徑)。

如圖8-13-(b)所示,在反向求導的第1層,對於節點c有:

類似的,對於節點d有:

在階段性的求解完畢第一層的導數之後,下面開始求解第二層神經元變數的偏導。如圖8-13-(c)所示,在反向第2層,對於節點a有如圖8-14-(Ⅰ)所示的求導模式。

(圖8-14反向模式微分方法的推演)

特別需要注意的是,8-14-(Ⅰ)所示的表達式「?e/?c×?c/?a」中左部「?e/?c」,已經在第1層求解過了,並「存儲」在神經元cc中。此時,採用「拿來主義」,拿來就能用!這就是反向模式微分的精華所在!

類似地,在反向求導第2層,對於節點bb,由於它彙集「兩路兵馬」的影響,所以需要合併同類路徑,有如圖8-14-(Ⅱ)所示結果。

這樣一來,如圖8-13反向模式微分方法,每個路徑僅僅遍歷一次,就可以求得所有輸出(如e節點)對輸入(如a或b節點)的偏導,乾淨利落,沒有任何冗餘!

在第七章中,我們曾提到,「BP演算法把網路權值糾錯的運算量,從原來的與神經元數目的平方成正比,下降到只和神經元數目本身成正比。」其功勞,正是得益於這個反向模式微分方法節省的計算冗餘

8.2.3 誤差反向傳播

有了前面「鏈式求導」的知識鋪墊,下面我們就來細細講解誤差反向傳播的過程。鑒於我們的系列文章是寫給初學者(實踐者)看的,下面我們盡量省略了其中較為複雜的推導公式,對該部分感興趣的讀者可參閱卡內基梅隆大學Tom Mitchell教授的經典著作《機器學習》[3](對公式不感冒的讀者,第一遍閱讀可以直接跳過公式,直達圖文解釋部分)。

誤差反向傳播通過梯度下降演算法,迭代處理訓練集合中的樣例,一次處理一個樣例。對於樣例d,如果它的預期輸出(即教師信號)和實際輸出有「誤差」,BP演算法抓住這個誤差信號Ld,以「梯度遞減」的模式修改權值。也就是說,對於每個訓練樣例d,權值wji的校正幅度為Δwji(需要說明的是,wji和wij其實都是同一個權值,wji表示的是神經元j的第i個輸入相關的權值,這裡之所以把下標「j」置於「i」之前,僅僅表示這是一個反向更新過程而已):

在這裡,Ld表示的是訓練集合中樣例d的誤差,分解到輸出層的所有輸出向量,Ld可表示為:

其中:

yj表示的是第j個神經單元的預期輸出值。

y′j表示的j個神經單元的實際輸出值。

outputsoutputs的範圍是網路最後一層的神經元集合。

下面我們推導出?Ld/?wji的一個表達式,以便在公式(8.7)中使用梯度下降規則。首先,我們注意到,權值wji僅僅能通過netj影響其他相連的神經元。因此利用鏈式法則有:

在這裡,netj=∑iwjixji,也就是神經元jj輸入的加權和。xji表示的神經j的第i個輸入。需要注意的是,這裡的xji是個統稱,實際上,在反向傳播過程中,在經歷輸出層、隱含層和輸入層時,它的標記可能有所不同。

由於在輸出層和隱含層的神經元對「糾偏」工作,承擔的「責任」是不同的,至少是形式不同,所以需要我們分別給出推導。

(1)在輸出層,對第i個神經元而言,省略部分推導過程,公式(8.8)的左側第一項為:

為了方便表達,我們用該神經元的糾偏「責任(responsibility)」δ(1)描述這個偏導,即:

(2)對隱含層神經元j的梯度法則(省略了部分推導過程),有:

其中:

fj表示神經單元j的計算輸出。

netj表示的是神經單元j的加權之和。

Downstream(j)表示的是在網路中神經單元jj的直接下游單元集合。

隱含層神經元的糾差職責,是通過計算前一步輸出神經元的「責任」來實現的。

這裡說的每層神經元「責任」,或者更為確切來說是「糾偏責任」,其實就是在8.2.2節講到的「分階段求解」策略。

在明確了各個神經元「糾偏」的職責之後,下面就可以依據類似於感知機學習,通過如下加法法則更新權值:

對於輸出層神經元有:

對於隱含層神經元有:

在這裡,η∈(0,1)表示學習率。在實際操作過程中,為了防止錯過極值,η通常取小於0.1的值。hj為神經元j的輸出。xjk表示的是神經單元j的第k個輸入。

上面的公式依然比較抽象,難以理解。下面我們還是以前面的神經網路拓撲結構為例,用實際運算過程給予詳細說明,以期望給與讀者感性認識。

在這裡,我們把每個神經元根據誤差調參的「責任」記為δ,那麼,根據公式(8.9)和(8.10),神經元3的「責任」可表示為:

(圖8-15 誤差反向傳播計算神經元3的「責任」)

(圖8-16 誤差反向傳播計算神經元4的責任)

在反向更新完畢輸出層的權值後,下面。我們開始反向更新隱含層的網路權值,示意圖如圖8-17所示。

(圖8-17 誤差反向傳播計算神經元1的責任)

如果我們把反向傳播誤差的「職責(即δj)」,也看做一種特殊信息的話,那麼在隱藏層的每個神經元都會有一個加權和影響,記為Δj,實際上,這裡的Δj,就是公式(8.11)的加權求和Downstream(j)(其實也就是8.2.2所提及的「合併同類路徑」)。

對於隱含層神經1,則有:

在計算出計算神經元1承擔的「責任」之後,我們就可以更新與神經元1相連的兩個輸入變數權值:

類似的流程(示意圖如圖8-18所示),可以求得神經元2的累計加權影響有:

(圖8-18誤差反向傳播計算神經元2的責任)

同樣,計算出計算神經元2承擔的「責任」之後,我們就可以更新與神經元2相連的兩個輸入變數權值:

從上面的推導過程,我們可以看到,經過一輪的誤差逆傳播,神經網路的權值前後確有不同。但由於學習率(即步長)較小(為0.1),所以前後的權值變化並不大(括弧內的數值為原始權值),如圖8-19所示。

(圖8-19 一輪BP演算法之後前後的權值對比)

如此一來,整個網路的權值就全部得以更新。接下來,網路就可接受下一個訓練樣例,接著往下訓練了,直到輸出層的誤差小於預設的容忍度。

BP演算法,在很多場所的確非常有用。例如,1989年,Yann Lecun(又一位當下的深度學習大牛)等人就用BP演算法,在手寫郵政編碼識別上有著非常成功的應用[5],訓練好的系統,手寫數字錯誤率只有5%。Lecun藉此還申請了美國專利,開了公司,發了一筆小財。

在發表BP演算法之後的30年,2006年,辛頓等人在發表的有關「深度信念網」的經典論文中指出[8],深度信念網(DBN)的組成元件就是受限玻爾茲曼機 (Restricted Boltzmann Machines, RBM)。而DBN的構建其實分兩步走的:(1)單獨「無監督」地訓練每一層RBM網路,以確保特徵向量在映射到不同特徵空間時,能夠儘可能多地保留特徵信息;(2)在DBN的最後一層,設置BP網路,用以接收RBM的輸出特徵向量作為它的輸入特徵向量,然後「有監督」地訓練實體關係分類器,對網路權值實施微調(Fine-Tune)。

現在你看到了,BP演算法的影響力,一直滲透到「深度學習」骨子裡!這就是為什麼在講深度學習時,我們繞不過BP演算法的原因。

8.4 小結

在本章中,我們詳細解釋了反向傳播(BP)演算法,通過學習我們知道,BP演算法其實並不僅僅是個反向演算法,而是一個雙向演算法。也就是說,它其實是分兩大步走:(1)正向傳播信號,輸出分類信息;(2)反向傳播誤差,調整網路權值。如果沒有達到預期目的,重走回頭路(1)和(2)。

BP演算法很成功。但我們也要看到BP演算法的不足,比如說會存在「梯度擴散(Gradient Diffusion)」現象,其根源在於對於非凸函數,梯度一旦消失,就沒有指導意義,導致它可能限於局部最優。而且「梯度擴散」現象會隨著網路層數增加而愈發嚴重,也就是說,隨著梯度的逐層消減,導致它對調整網路權值的調整效益,作用越來越小,故此BP演算法多用於淺層網路結構(通常小於等於3),這就限制了BP演算法的數據表徵能力,從而也就限制了BP的性能上限。

再比如說,雖然相比於原生態的BP演算法,雖然它降低了網路參數的訓練量,但其網路參數的訓練代價還是不小,耗時非常「可觀」。就拿LeCun的識別手寫郵編的案例說事,其訓練耗時就達3天之久。

再後來,與LeCun同在一個貝爾實驗室的同事Vladimir Vapnik(弗拉基米爾·萬普尼克),提出並發揚光大了支持向量機 (Support Vector Machine) 演算法。

SVM作為一種分類演算法,對於線性分類,自然不在話下。在數據樣本線性不可分時,它使用了所謂「核機制(kernel trick)」,將線性不可分的樣本,映射到高維特徵空間 (high-dimensional feature space),從而使其線性可分。自上世紀九十年代初開始,SVM逐漸大顯神威,在圖像和語音識別等領域,獲得了廣泛而成功的應用。

在手寫郵政編碼的識別問題上,LeCun利用BP演算法,把錯誤率整到5%左右,而SVM在1998年就把錯誤率降到低至0.8%。這遠超越同期的傳統神經網路演算法。

就這樣,萬普尼克又把神經網路研究送到了一個新的低潮!

在下一章中,我們將來聊聊「卷積神經網路」,這可是深度學習發展過程中的一個重要里程碑,希望你能關注。

8.5 請你思考

通過本章的學習,請你思考如下問題:

(1)正是由於神經網路具有強大的表示能力,「成也蕭何,敗也蕭何」,BP演算法常常遭遇「過擬合(overfitting)」,它可能會把噪音當做有效信號,你知道有什麼策略來避免過擬合嗎?

(2)利用梯度遞減策略,BP演算法常停止於局部最優解,而非全局最優解,這好比「只因身在此山中」,卻不知「人外有人,山外有山」,你知道有什麼方法可以改善這一狀況嗎?

(3)在BP演算法流程中,我們看到的是反反覆復的權值調整,而傑弗里?辛頓在文獻[4]中提到的特徵表示(representation),體現在什麼地方?

【參考文獻】

[1] Paul J. Werbos. Beyond Regression: New Tools for Prediction and Analysis in the Behavioral Sciences. PhD thesis, Harvard University, 1974

[2] Christopher Olah. Calculus on Computational Graphs: Backpropagation

[3]Tom Mitchell著.曾華軍等譯. 機器學習. 機器工業出版社. 2007.4

[4] Williams D, Hinton G. Learning representations by back-propagating errors[J]. Nature, 1986, 323(6088): 533-538.

[5] LeCun Y, Boser B, Denker J S, et al. Backpropagation applied to handwritten zip code recognition[J]. Neural computation, 1989, 1(4): 541-551.

[6]周志華. 機器學習. 清華大學出版社. 2016.1

[7] Mirosav Kubat著. 王勇等譯. 機器學習導論. 機械工業出版社. 2016.11

[8] Hinton G E, Osindero S, Teh Y W. A fast learning algorithm for deep belief nets[J]. Neural computation, 2006, 18(7): 1527-1554.

文章作者:張玉宏,著有《品味大數據》一書。審校:我是主題曲哥哥。

(未完待續)

本系列內容未完待續,若期望持續學習還請關注阿里云云棲社區知乎機構號:阿里云云棲社區 - 知乎

推薦閱讀:

機器學習系列:遞歸神經網路
基於TensorFlow一次簡單的RNN實現
勘誤與科普:如何在飛鳥的背後,捕捉到飛行|張崢談人工智慧
數據學習之路---每周好文分享(第一期)
面向數據科學家的兩門課:Data8 和 DS100

TAG:机器学习 | 人工智能 | 深度学习DeepLearning |