深入探究递归神经网络:大牛级的训练和优化如何修成?
深入探究遞歸神經網絡:大牛級的訓練和優化如何修成?
摘要:不同于傳統FNN,RNN無需在層面之間構建,同時引入定向循環,能夠更好地處理高維度信息的整體邏輯順序。本文中,MIT的Nikhil Buduma將帶您深入探析RNN的原理、訓練和優化等各方面的內容,以及RNN已經獲取的一些成就。
在深度學習領域,傳統的前饋神經網絡(feed-forward neural net,簡稱FNN)具有出色的表現,取得了許多成功,它曾在許多不同的任務上——包括手寫數字識別和目標分類上創造了記錄。甚至到了今天,FNN在解決分類任務上始終都比其他方法要略勝一籌。
盡管如此,大多數專家還是會達成共識:FNN可以實現的功能仍然相當有限。究其原因,人類的大腦有著驚人的計算功能,而“分類”任務僅僅是其中很小的一個組成部分。我們不僅能夠識別個體案例,更能分析輸入信息之間的整體邏輯序列。這些信息序列富含有大量的內容,信息彼此間有著復雜的時間關聯性,并且信息長度各種各樣。例如視覺、開車、演講還有理解能力,這些都需要我們同時處理高維度的多種輸入信息,因為它們時時都在變化,而這是FNN在建模時就極為匱乏的。
現在的問題在于如何學習信息的邏輯順序,解決這一問題有一個相當靠譜的途徑,那就是遞歸神經網絡(Recurrent Neural Net,簡稱RNN)。
RNN是什么?
RNN建立在與FNN相同的計算單元上,兩者之間區別在于:組成這些神經元相互關聯的架構有所不同。FNN是建立在層面之上,其中信息從輸入單元向輸出單元單向流動,在這些連通模式中并不存在不定向的循環。盡管大腦的神經元確實在層面之間的連接上包含有不定向循環,我們還是加入了這些限制條件,以犧牲計算的功能性為代價來簡化這一訓練過程。因此,為了創建更為強大的計算系統,我們允許RNN打破這些人為設定強加性質的規定:RNN無需在層面之間構建,同時定向循環也會出現。事實上,神經元在實際中是允許彼此相連的。
RNN例圖,包含直接循環和內部連通
RNN包含輸入單元(input units)群,我們將其標記為u1,u2直到uK,而輸出單元(output units)群則被標記為y1,y2直到yL。RNN還包含隱藏單元(hidden units),我們將其標記為x1,x2直到xN,這些隱藏單元完成了最為有意思的工作。你會發現,在例圖中:有一條單向流動的信息流是從輸入單元到達隱藏單元的,與此同時另一條單向流動的信息流從隱藏單元到達輸出單元。在某些情況下,RNN會打破后者的限制,引導信息從輸出單元返回隱藏單元,這些被稱為“backprojections”,不讓RNN分析更加復雜。我們在這里討論的技術同樣適用于包含backprojections的RNN。
訓練RNN存在很多相當具有挑戰性的難題,而這仍是一個非常活躍的研究領域。了解概念之后,本文將帶您深入探析RNN的原理、訓練和優化等各方面的內容,以及RNN已經獲取的一些成就。
模擬RNN
現在我們了解到RNN的結構了,可以討論一下RNN模擬一系列事件的方式。舉個簡單的例子,下文中的這個RNN的運作方式類似一個計時器模塊,這是由Herbert Jaeger設計的一個經典案例(他的原稿請點擊這里查看)。
簡單案例:一個完美的RNN如何模擬計時器
在這個例子中,我們有兩個輸入單元,輸入單元u1相當于一個二進制開關,峰值時數值為1(在RNN開始計時的時候);輸入單元u2是一個離散變量,其取值范圍在0.1到1.0之間變化,指的是計時器如果在那一瞬間開啟,則輸出值相應開啟的長度。在RNN的規范中,要求它將輸出結果持續在1000 u2的區間里開啟。最終,訓練案例中的輸出結果會在0(關閉)與0.5(開啟)之間來回撥動。
但是,一個神經網絡究竟是如何完成這個計算的呢?首先,RNN的所有隱藏層行為會被初始化成為一些預設的狀態,然后在每個時間步長中(時間 t =1,2,……),所有的隱藏單元通過外部連接發送其當前的行為,再通過其他神經元(如果有自我連接則包括自身)的輸入和當前值的輸入,進行加權求和(logit)之后重新計算出新的行為,然后將其寫入神經元的特定功能中(簡單的復制操作,可調函數,soft-max等等)。因為之前的行為矢量被用在計算每個時間步長的行為矢量中,RNN可以保留之前的事件記憶并使用該記憶來做決定。
顯然一個神經網絡不大可能完全根據規范而構建,但是可以想象一下,在RNN的訓練進行過數百次或數千次之后,其輸出結果(橙色)會非常接近客觀數據(藍色)。下文中我們會對RNN訓練的方式進行更多討論。
經過良好的訓練后,RNN在實驗案例中接近輸出測試用例
此時此刻,你可能覺得這相當酷,但是有相當多的案例都很不自然。實踐中運用RNN的策略是什么呢?我們調查了真實的系統以及隨著時間流逝它們對于刺激物的回應行為。舉例來說,你可以教會一個RNN通過建立一個數據組將聲頻轉化為文字(在某種意義上,在訓練組中觀察人類的聽覺系統對于輸入內容的回應)。你還可以使用一個訓練過的神經網絡來模擬一個系統在異常刺激下的反映。
RNN在實踐中如何運用
但是如果你富有創意的話,可以通過更為驚人方式來使用RNN,比如一種專門的RNN——LSTM(Long Short-Term Memory),就已經被用來實現規模巨大的數據壓縮比率了,盡管目前基于RNN的壓縮方法還需要花費大量的時間。(后文將有詳細解釋。)
通過時間進行RNN-BP(BackPropagation)算法的訓練
我們一開始又是如何對RNN進行訓練,讓它來完成所有這些驚人的功能呢?尤其我們是如何確定每個連接的強度(或稱權值)呢?我們又是如何從所有隱藏單元中選擇初始行為的呢?我們的第一反應可能是直接使用BP算法,畢竟這種算法在FNN中使用過而且效果良好。
這里使用BP算法的問題在于我們有著周期性的依賴關系。在FNN中,我們在針對一個層面中的權值來計算誤差衍生時,可以根據上一層面中的誤差衍生對其進行完全表達。RNN中并沒有這種漂亮的分層,因為神經元并未組成有向非循環圖。在RNN中使用BP算法可能會迫使我們根據它自身來進行誤差衍生的表達,這樣會使分析復雜化。
因此,使用BP算法需要執行一個機智的轉化:將RNN轉化為一個新的架構,這個新架構在本質上來說就是一個FNN,我們將這個策略稱為通過時間“展開”RNN。下面圖表中有一個樣例(為了簡化起見,每個時間步長中只有一個輸入/輸出):
通過時間將RNN“展開”以使用BP算法
具體步驟非常簡單,但對我們分析神經網絡的能力有著深遠的影響。我們將RNN輸入、輸出、隱藏單元和復制分別看作時間步長。在我們的新FNN中,這些分別對應著不同的層面,然后我們將隱藏單元按照下面的方式連接起來,在原始的RNN中,w表示從神經元i到神經元j的連接強度(即權值),而在新的FNN中,我們畫出一個連接w的圖,分別連接每個tk層中的神經元i和每個tk+1層中的神經元j。
這樣一來,為了訓練RNN,我們取隨機的初始化權值,將其“展開”到FNN中,然后通過BP算法以確定最佳權值。為了確定時間0時隱藏狀態的賦初值,我們可以將初始行為視作注入FNN底層的參數,然后通過BP算法以確定其最佳值。
但是這里我們遇到了一個問題:在使用過每一批訓練案例之后,我們需要基于計算出的誤差衍生來修正權值。在FNN中,我們有一套連接關系,全部與原始的RNN中同樣的連接關系相對應。但是,根據權值計算出的誤差衍生卻無法保證是相同的,也就是說我們可能會用不同的數量來修正誤差。我們當然不想變成這樣!
對于這一問題,我們的解決辦法是:將同一組中所有連接的誤差衍生求平均值(或者求和)。也就是說每一批訓練之后,我們會用相同的數量來修正相應連接,因此如果它們的賦初值相同,則最終值也會相同,這很好地解決了我們的問題。
深層BP算法的問題
不同于傳統的FNN,由展開RNN而產生的FNN可能會有非常多層。這就產生了一個嚴重的現實問題:通過時間手段使用BP算法來進行訓練可能會變得非常困難。讓我們退回一步,研究一下原因。
我們試著訓練RNN做一個非常簡單的工作:先給RNN的一個隱藏單元賦予一個偏差值,然后把它與自身還有一個單一的輸出接口相連接。我們希望這個神經網絡在50步以后輸出一個固定目標值,這個值我們設定為0.7。這樣我們在將要在第50步的時候,使用輸出的均方誤差(squared error)作為誤差函數,就能通過權值和偏差值畫出一個曲面:
一個簡單的RNN的問題誤差曲面(圖片出自:Pascanu et al.)
現在,假定我們從紅色五角星處開始(使用一個隨機的權值賦初值),你會注意到:在使用梯度下降(gradient descent)的時候,圖線會越來越趨近于曲面的局部最小值。但是突然間,在稍微越過低谷并觸及峭壁的時候,在相反方向出現一個巨大的梯度,這就使得我們向反方向反彈并遠離局部最小值。一旦我們進入了虛空中,就會很快發現:梯度幾近消失,想要再次接近則需要近乎無窮的時間。這個問題被稱做“梯度的爆發與消失”(exploding and vanishing gradients),可以想象一下:我們可以通過改變梯度值,讓它永遠不要超過最大值來控制這個問題(請看撞到峭壁后點線的路徑),但是這個方法仍然不是非常有效,尤其是在更復雜的RNN中。(想要查看這個問題的數學處理方法,請查看這篇論文。)
長短時記憶
為了解決這些問題,研究人員提出了RNN的修正架構,以協助在強制的輸入、適當的回應與防止梯度爆發之間建立一個長期的時滯。這個架構強制其在特殊記憶單元中的內部狀態保持一個常數誤差流(constant error flow),這樣一來圖線既不會爆發也不會消失。這個長短時記憶(LSTM)架構利用了下面結構中顯示的單元:
基本的LSTM單元架構
LSTM單元包含一個嘗試將信息儲存較久的存儲單元。這個記憶單元的入口被一些特殊的門神經元(gate neurons)所保護,被保護的功能包括保存、寫入和讀取操作。這些門神經元都是logistic units,它們不會將自己的行為作為輸入值發送給其他神經元,而是負責在神經網絡的其它部分與記憶單元連接的邊緣處設定權值。這個記憶單元是一個線型的神經元,有自體內部連接。當保存門被打開時(如1中的行為),自體連接權值為1,記憶單元將內容寫入自身。當保存門輸出為0時,記憶單元會清除之前的內容。寫入門允許在輸出值為1的時候,神經網絡的其它部分將內容寫入記憶單元,而讀取門則允許在輸出值為1的時候,神經網絡的其它部分讀取記憶單元。
因此,這個操作究竟是如何保持一個時間的常數誤差流,從而在局部防止爆發與消失梯度的產生呢?為了更加形象化,我們將LSTM單元按照時間展開:
通過時間區域展開LSTM單元
首先,保存門被設定為0,寫入門被設定為1,并在記憶單元中存入4.2這個值。在隨后保存值為1的時候,4.2這個值一直被保存在記憶單元中,拒絕值為0時的讀取或寫入,最終這個單元在被讀取后清除。現在,讓我們試著從4.2這個值被載入記憶單元的那一刻起進行BP算法,直到從記憶單元中讀出4.2的那一刻并隨之將其清除為止。我們發現,根據記憶神經的線型本質,我們從讀取點到寫入點接收到的BP誤差派生的變化完全可以忽略,因為通過所有時間層連接記憶單元的連接權值加權后約等于1。因此,我們可以在幾百步中對這個誤差派生值進行局部保存,而無需擔心梯度的爆發或消失。
LSTM RNN非常有效,而且同樣適用于很多其他領域。我們早些時候討論過,LSTM RNN的深層架構被用于實現了相當驚人的數據壓縮率。(如果對LSTM RNN的特定應用有興趣,可以查看這篇論文做更深入的了解。)
結論
有效進行神經網絡訓練的相關方法仍舊是一個活躍的研究領域,并引出了大量置換手段,目前尚無哪一種表現出明顯的優勢。LSTM RNN架構就是這樣一個提高RNN訓練的方法。還有一個方法就是使用更好的最優化控制器來對付梯度的爆炸與消失。Hessian-free優化器嘗試通過小型梯度探測方向,甚至帶來了更小的曲度,這使得它比單純的梯度下降表現更佳。三分之一的方法涉及到權值謹慎的賦初值,期望借此避免頭一個梯度爆發和消失的問題(例如:反射狀態網絡,基于動量的方法)。
原文鏈接:A Deep Dive into Recurrent Neural Nets?(編譯/孫薇 校對/周建丁)
總結
以上是生活随笔為你收集整理的深入探究递归神经网络:大牛级的训练和优化如何修成?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入解析NoSQL数据库的分布式算法
- 下一篇: 你心动了吗?2014年iOS应用开发者收