从前馈到反馈:解析循环神经网络(RNN)及其tricks
好像已經有兩周沒有更新啦。最后這幾天都不敢打開訂閱號后臺了,怕一打開發現掉了幾百個粉絲的話就難過死了T_T。然而小夕發現你們并沒有離開,感動的差點哭出來,都感覺再不認真寫一篇文章就太對不起大家的等待啦。
而這兩周,經歷的事情蠻多的。為了湊下一季的房租,接了個私活,要死要活的做完了QAQ。而且還發現了一個特別好的學習平臺,閉關修煉了一周,改天跟你們分享一下~下面開始正文啦,不要太激動哦。
為什么需要反饋?
?
在上一篇《前饋網絡與卷積網絡》中,小夕講解了前饋網絡中的戰斗機——卷積神經網絡(CNN)更關注局部特征的提取,比如在句子級情感分類的任務中,往往找出句子中可以表現情感的情感詞就能完成這個句子的情感極性分類,而情感詞之前的詞并不會對決策結果起到多大的影響。還是習慣性的舉出栗子????:
?
比如?“夕小瑤 今天 不開心 了。”?
為了判斷這個句子的情感極性,只需要讓分類器能識別出“不開心”是個負極性的詞,其他詞是偏中性詞就可以了。而“不開心”前面的中性詞是“今天”還是“有時”,對“不開心”的情感極性并不會有多大的影響,也不會對整個句子的情感極性有多大影響。因此,當我們把該句子中的各個詞條依次輸入給模型去分類時,并不需要去“瞻前顧后”,因此使用一個關注局部的前饋神經網絡往往表現更佳。而從最近三四年的論文來看,在句子級情感分類問題上,也確實是卷積網絡比遞歸網絡和循環網絡更容易引領state-of-arts。
?
然而,還有一些任務的labels之間會有很強的相關性,比如命名實體識別(NER)任務,我們想要識別出文本中的地址時:
?
“據報道,在 2016年,有 一只 可愛的 小狗狗 在 北京市 海淀區 番茄貓咪 小區 失蹤。”(什么鬼栗子)
?
這句話中的地址是“北京市 海淀區 番茄 貓咪 小區”,因此我們的目標是給這幾個詞條貼上“這是地址”的標簽,給其他詞條貼上“這不是地址”的標簽。
?
顯然,如果用CNN去做的話,很容易把“番茄”識別成非地址詞,畢竟想要識別出來它的話,就要同時考慮“海淀區”“貓咪”“小區”這三個相鄰的上下文詞條,也就是說CNN的卷積濾波器的長度要最少達到4才有較大的可能性正確標注這個句子的labels。而對更長的地址,那代價就更大了,總不能無限增長濾波器的長度吶。所以一個更靠譜的辦法是讓模型在當前位置的輸出再反饋給模型,來幫助模型做下一位置的決策!
這樣的有反饋單元的模型在做當前位置的決策的時候,會同時考慮前面所有位置/時間點的情況(直接考慮上一時間點,又由于上一時間點也考慮了上上時間點,因此間接考慮了上一時間點前面所有的時間點),因此有反饋單元的模型在判斷“番茄”是不是地址時,它通過前面積累的 “據報道,在2016年,有 一只 可愛的 小狗狗 在 北京市 海淀區” 發現下一個詞 “番茄” 是非地址詞的概率并不大(因為訓練集中很少會出現主語+“在”+地址1+地址2+非地址名詞+...的情況,倒是經常出現主語+“在”+地址1+地址2+地址3+...的情況),從而可以完成正確決策。
?
相比之下,在卷積網絡中,由于它視野有限,不瞻前顧后,所以它更可能覺得“地址+非地址名詞”非常正常,因為比如“北京糖葫蘆”,“美國 貓”也很常見嘛~進而導致了錯誤決策。這也是為什么在該任務中,有反饋單元的神經網絡比前饋網絡更容易成為state-of-art。
?
數學上如何描述反饋?
?
顯然這樣模型就不再是前饋的了,而是將模型的輸出也作為輸入來丟進模型。回顧一下,前饋網絡的時候簡單的前饋公式是這樣的:
?
O=f( X * W+b )
?
其中W和b是模型的參數,X是當前的輸入,f(·)是激活函數,*是矩陣乘法,O是當前的輸出。即輸出 等于 輸入經過線性與非線性映射后的結果。
?
加上反饋單元后,公式就變成了:
?
Ot=f(X * W + Ot-1 * V+ b)
?
其中W、V、b是模型的參數,下標t代表當前的序列位置/時間點,t-1代表上個位置/上個時間點,X是當前的輸入,f(·)是激活函數,*是矩陣乘法,O是模型輸出。
?
簡單的加上反饋單元的這個模型,就叫做循環神經網絡(RNN,R=Recurrent)。這也是后續LSTM、GRU等門限循環網絡的基礎模型。
?
RNN是淺層的還是深層的?
?
從前向過程來看,貌似是淺層的。比如1000層的前饋神經網絡,在做“xxxxx”的命名實體識別這個前文例子的時候,是每一個詞條都要跑一遍1000層的網絡才能出這個詞條的標注結果。而簡單的循環網絡來說,跑一層就會出一個標注結果。因此看起來是淺層的。然而,在計算序列的后幾個位置的label的時候,顯然也積累了前面所有位置的計算結果,因此這樣看又是深層的。
?
從反向過程看,也就是從優化的角度來看,RNN是深層的。因為在進行每一次誤差反向傳播的時候,誤差要從前饋網絡的第1000層開始逐層傳回第一層,誤差在循環網絡中也要從序列的末端輸出一直傳回到序列的首端。因此序列是1000長度的話,在RNN中誤差就相當于傳遞了1000層。
?
這個爭論也被公認為是爭論。小夕就不參與討論了。我們只關注這樣會帶來什么特殊的問題。
?
RNN的問題
?
首先,從淺層的角度去看RNN的前向過程,就可以認為它只有一層權重矩陣W(我們先不管V)。由此可見從深層的角度去看RNN的前向過程,就可以認為RNN是各個層的權重矩陣相同的深層網絡。我們忽略V和激活函數,就可以近似的認為網絡一共有T層(T等于序列的長度),那么第t層的輸出就是連乘t次W,也就是Wt!
在《線性代數(二)》中,小夕講過矩陣可以用它的特征值矩陣和特征向量矩陣去近似,即
W≈Vdiag(λ)V-1
所以Wt就可以展開成(Vdiag(λ)V-1)(Vdiag(λ)V-1)...,約掉中間的一堆V-1V,就是
Wt=Vdiag(λ)tV-1
也就是說,特征值矩陣中的每個特征值都會隨著t的增大發生指數級變化!所以某個特征值大于1時,就容易導致這個維度的值爆炸性增長;當特征值小于1時,會就會導致這個維度的值指數級速度衰減為0!
?
前向過程如此,誤差反向傳播的過程也必然近似為輸出層的誤差會乘以Wt來得到倒數第t層的梯度,然而由于剛才講的各個維度不是指數級衰減就是指數級爆炸,很容易看出當你去更新RNN的靠前的層的時候(即離著輸出層較遠的那些層,或者說與序列末端離得遠的位置),計算出的梯度要么大的嚇人,要么小的忽略。小的忽略的值不會對W的更新有任何指導作用,大的嚇人的值一下子就把W中的某些值弄的大的嚇人了,害得前面的優化都白做了...因此這顯然是不靠譜的。哦對了,這個現象叫做梯度消失和梯度爆炸。
?
解決方法呢?
?
一個很簡單的想法是進行梯度截斷,我們在優化RNN的參數的時候,給剃度值設置一個上限,免得發生爆炸摧毀我們之前積累的結果。但是這樣顯然就會導致模型難以再顧及很靠前的歷史信息了(梯度都被大幅閹割或者自己消失了),因此理論上RNN可以保存任意長的歷史信息來輔助當前時間點的決策,然而由于在優化時(訓練RNN時),梯度無法準確合理的傳到很靠前的時間點,因此RNN實際上只能記住并不長的序列信息(在NLP中,經驗上認為序列大于30的時候,RNN基本記不住多于30的部分,而從多于10的位置開始就變得記性很差了),因此RNN相比前饋網絡,可以記住的歷史信息要長一些,但是無法記住長距離的信息(比如段落級的序列甚至篇章級的序列,用RNN就雞肋了)。
?
使用梯度截斷的trick可以減輕參數矩陣連乘帶來的問題。同樣,如前所述,由于前向過程也會對參數矩陣進行連乘,顯然乘的次數多了,就會容易產生很大的值(包括很大的正值與很小的負值),而很大的正值或者很小的負值會在反向傳播時丟給激活函數的導數(忘了的回去復習《BP算法過程》),因此:
?
對于sigmoid的導數σ′(z) = σ(z)(1-σ(z))(有疑問的自己推導一下)來說,顯然無論輸入的z是超大正值也好,超小負值也好,都會導致其導數接近0!因此直接導致梯度傳到這里后就消失了!而ELU?的導數和ReLU的導數則不會有這個問題。因此在RNN中,更要注意一般情況下不要使用sigmoid作為激活函數!
?
好了。標準的RNN講完了。我們發現RNN的想法很簡單,直接引入了反饋單元來記憶歷史信息。然而由于訓練時的梯度爆炸與消失,導致其難以學習遠距離歷史信息(或者說與當前時間點的遠距離依賴關系),因此要注意使用梯度截斷的trick來處理優化過程,同時要避開sigmoid這類容易帶來梯度飽和的激活函數。那么如何讓循環神經網絡去學習長距離依賴關系呢?期待小夕的長短時記憶網絡(LSTM)吧!
總結
以上是生活随笔為你收集整理的从前馈到反馈:解析循环神经网络(RNN)及其tricks的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拿下字节offer,这些面试题命中率高达
- 下一篇: 再介绍一篇Contrastive Sel