當前位置:
首頁 > 最新 > 深度學習第6期:循環神經網路RNN

深度學習第6期:循環神經網路RNN

在深度學習中,有兩種結構特殊的神經網路是目前應用最多的,一種是卷積神經網路(CNN),另外一種是循環神經網路(RNN)。在前面,我們已經介紹過CNN的構造,以及其在計算機視覺領域中的應用。今天,我們來介紹RNN的主要思想。

在CNN有關的科普文中,我們提到,圖片數據是一種類型特殊的數據,其像素點之間具有一定的空間結構。而CNN正是由於利用了這種空間結構,才使得其在圖片型數據的問題上展現出比普通的神經網路更好的效果。而今天我們要介紹的RNN同樣適合處理一種特殊類型的數據,那就是時間序列型的數據。RNN的結構正是利用了這種數據在時間維度上的有序性,才得以發揮比普通神經網路更好的效果。

時間序列問題

舉個例子,我們有一架大風車,可以用來風力發電,為建設社會主義事業貢獻力量。我們有一段時間內各個等間距時刻的風速(x1,x2,...,xn),我們也有相應時刻的風車的發電量(y1,y2,...,yn)。我們需要擬合一個從風速預測發電量的函數。一種最樸素的想法是將每一個時刻的數據當成是獨立同分布的樣本,即假定每一個時刻的發電量只與該時刻的風速有關。則問題化為一個普通的回歸問題,我們只要用一個普通的回歸器回歸x與y之間的關係即可。

但是事實上,用這種思路建立的回歸器往往不能達到好的效果。我們想像有兩種情況,一種是在漫長的時間段里風平浪靜,而後忽然起風,使得風速達到5;另一種是在很長的一個時間段里狂風驟雨,然後逐漸雲淡風輕,風速減慢到5。這兩種情況下,風車的發電量會是相同的嗎?這啟發我們,影響一個時刻的發電量的絕不只有該時刻的風速,還包括上一段時間的風速、上一段時間的發電量。

另外,我們還要考慮到的是,一些我們不可見的變數(即手頭沒有數據的變數)也有可能會影響發電量,例如風車轉動的角加速度等等。在各個樣本獨立同分布的問題中,我們一般對這些可見的變數是無能為力的,只能簡單地將其視為混雜在模型的隨機雜訊。但是,在時間序列的問題中,我們或許可以根據一些我們可見變數的變化情況,推斷出背後不可見的變數的部分信息,並且將這些信息加以利用。

除了風速預測發電之外,天氣數據、金融數據、經濟數據,都是時間序列類型的數據。由於與我們的生活各方面息息相關,所以有很高的研究價值。目前,專門針對時間序列數據的研究已經從一般的統計學中獨立出來,發展成為了一個獨特的學科。對於時間序列的問題,已經有十分成熟的線性模型,包括自回歸(Auto Regression)、滑動平均(Moving Average)、ARMA等模型。但是,由於線性模型的表示能力較弱,所以其擬合能力較弱。並且,由於線性模型也無法添加隱含變數,這使得其結構過於簡單,無法針對複雜的時間序列問題作出充分的解釋與足夠好的擬合。

對於非線性的時間序列,也有不少傳統的模型。例如隱馬氏鏈(HMM)模型。其基本的模型結構如下圖所示:

我們還可以將隱馬氏鏈的結構設計得複雜一些:我們假定我們的序列有輸入xt,有一個隱含狀態zt,有可觀測狀態yt。模型假定隱含狀態之間,根據輸入會有某一轉移概率,即P(zt+1|zt, xt)。另外,模型還假定可觀測狀態是由隱含狀態與某一觀測分布函數P(yt|zt)產生的。對於一組數據xt,yt,t=1,2,3,…,n,為了模擬出一個隱馬氏鏈模型,我們會採用Baum–Welch演算法。這事實上是一種EM演算法,它用迭代的求期望-求最大似然的步驟求出隱馬氏鏈的參數,以求出能夠使得似然函數極大化的模型參數(即同時最大化狀態轉移概率P(zt+1|zt,xt)與觀測概率P(yt|zt)的聯合概率)。

對於預測風速發電的問題,如果我們不採取時間序列的觀點,而只是採取獨立同分布回歸的觀點,則我們只需要對P(yt|zt)進行極大似然估計,即可得到我們的模型。

如果我們採用隱馬氏鏈模型,則意味著我們要想像模型背後有一個隱含變數zt代表「風車的狀態」。某一時刻的風車的狀態由前一時刻的狀態,以及這個時刻的風速決定。而每一個時刻的發電量,又由該時刻的風車的狀態決定。在這種模型設定下,我們就要對P(zt+1|zt,xt)與P(yt|zt)的聯合概率進行極大似然估計。這無疑導致了更加複雜的計算量(無法直接用優化求解,而要用到EM演算法進行迭代),但由於其運用了時間維度上的有序性,這也將導致模型有更好的解釋性與更加強大擬合能力。

除了下面我們將要介紹的RNN則是實現非線性時間序列模型的另一個好方法。正如目前神經網路在其他領域相對傳統模型都表現出一定的優勢一樣,RNN在非線性時間序列這個領域也展示出優於傳統模型的性能。

RNN

我們通過一個最簡單的RNN與NN的對比,來理解二者的不同。設RNN只有一個隱藏層。其輸入為x,輸出為o,中間有一個隱藏層s。其一共有三組參數,輸入層到隱藏層的參數U,隱藏層到輸出層的參數V,以及隱藏層之間循環結構的參數W。一般的神經網路只有前兩組參數U與V,而RNN之所以與普通的神經網路不同,正是由於加入了W。其示意圖如下:

RNN之間信息傳遞的運算公式如下所示:

其時間上的相關性主要體現在狀態隨著時間傳遞的係數——W上。如果我們去掉了W及狀態隨時間傳遞的關係,則RNN變回普通的NN,其運算公式如下:

如果我們採取普通的NN,就相當於是忽略了數據在時間上的相關性。於是,我們將數據中的一個batch拿去訓練,與將一個樣本拿去訓練,其效果是差不多的。故而NN的訓練中,假定輸入x、輸出的標籤y給定。總的損失函數為Loss=(y–o)2/2,BP演算法求出對各個參數的導數如下:

而在RNN中,由於隱藏層的狀態x1,x2,…,xt與輸出y1,y2,…,yt一起拿去訓練,才能正確地算出對於各個參數的更新方式。我們設總的損失函數為各個預測與真實值的標籤的平方誤差之和。RNN對於各個參數的更新將會是十分複雜的。

首先,我們求Loss1=(y1–o1)2/2對於各項參數的梯度。它與上面NN給出的梯度沒有任何區別:

接下來求Loss2=(y2–o2)2/2對於各項參數的梯度:

可以看到的是,Loss2對於V的梯度與Loss1對於V的梯度形式一樣的,但是Loss2對於U的梯度對比Loss2對於U的梯度要更為複雜。這是因為在o2的計算公式中包含了兩個U。從x2生成s2時候與U有關,從x1生成s1時候也與U有關,而另一方面,s2的生成與s1有關。所以,Loss2對於U的梯度就需要分成兩部分計算,這也使得其更加複雜。

可以想像,Loss3=(y3–o3)2/2對於各項參數的梯度將會更加複雜,其具體的梯度公式推導為:

由於在o3的表達式中出現了3項U與2項W,所以其對於U與W的梯度的表達式也變得比o2更加複雜。我們可以想像,對於Loss4,Loss5,…,其對於U與W的梯度的表達式將會越來越複雜。

對於用風速預測發電的情況而言,每一個時刻的情況只受到過去的影響,而不可能受到未來的影響。這是時間單向流動的性質所決定的。但是,對於其他序列生成問題,如果這個序列不是時間維度的序列,而是其他維度(比如從左到右)的序列,則該序列中每一個位置除了受到之前的影響,也有可能受到之後的影響。這時候就要採用雙向RNN,即設定兩組參數W1和W2,分別代表隱含層在時間維度上的前傳與後傳關係。即設定每一個隱含狀態st=f(Uxt+W1st?1+W2st+1)。其示意圖如下:

不難想到,在雙向RNN中,所有的ot與整個序列的輸入x1,x2,…,xn都有關係。所以,對於所有Lossi,其對於U的梯度是同樣複雜的。

上面,我們只是用了一個結構最為簡單的RNN做為例子。在現實中,如果要模擬稍微複雜一些的序列生成機制,則只有兩層的RNN顯然是不夠的。為此,要使用深度的RNN,其示意圖如下(以下為一個多層的雙向RNN):

不難想到,當我們採用了比較深的RNN結構,如果輸入的序列比較長,則我們訓練時用BP演算法求出的對於各個參數的梯度將會極其複雜。所以,我們在訓練的時候盡量不會選取太長的序列。例如,我們擁有的風速-發電量的數據有1000項的長度,但是在訓練時候,我們很可能只是將其截取為50項的序列,依次放入RNN進行訓練。而另一方面,當我們訓練完成後,我們可以用來生產任意長的序列。

RNN的局限性

在早期的NN中,人們習慣採用Sigmoid函數為激活函數。但是Sigmoid有一個特點——其導數無論如何都在0到1/4之間。使用BP演算法的時候,我們是從輸出端逐漸地往輸入端求各項參數的梯度。而由於Sigmoid函數導數在0到1/4之間的特點,當我們後傳導數較多次的時候,則有可能會導致梯度過小,無法有效地更新較接近輸入端的參數,這就是所謂的「梯度消失」的問題。早期神經網路正是由於受到「梯度消失」的限制,所以無法將層數加深。

而後來由於使用了ReLU函數做為激活函數,神經網路得到了較大的發展。由於ReLU的導數屬於[,1],故而能夠比較有效地解決梯度消失的問題。正是由於ReLU函數的廣泛使用,神經網路才得以往深的方向發展,真正開啟了深度學習的熱潮。目前,在NN或是CNN的領域,ReLU都是最為常用的激活函數。

但是,在RNN的領域,ReLU卻並非是最合適的函數。相比之下,tanh是更加常用的函數。深度學習界的泰斗人物Hinton在其論文《A Simple Way to Initialize Recurrent Networks of Rectified Linear Units》中指出:

在上一節中,我們大致推出了RNN對於各項參數的公式。雖然我們只列出了前三項,但是我們不難推想出,在後面的項中將會出現多個W與f′連乘的部分。如果我們選用ReLU為激活函數,當我們的序列較長,而W的特徵值大於1時,則有可能會使得求出的梯度過大。當梯度過大的時候,可能會導致訓練十分不穩定,難以收斂到合適的位置,甚至不能真正使得訓練損失有效下降。這正是與「梯度消失」完全相反的另一問題——「梯度爆炸」。

為了解決梯度爆炸的問題,我們需要激活函數具有一定的壓縮性,例如Sigmoid或是tanh函數都具有這種性質。人們經歷實踐後發現選用tanh函數能夠使得訓練效率較高,網路的能力較好。所以,目前在RNN領域,tanh函數是最為常見的激活函數。

RNN在擬合一些較為簡單的時間序列數據上表現出了強大的能力,逐漸超過了傳統做法,成為了時間序列領域最佳的模型之一。隨著人工智慧在各個領域的應用普及,人們逐漸將目光轉移到更加重要的一個領域——自然語言處理(NLP)。自然語言,即人們平時使用的語言,從本質上看也是一類時間序列數據。因為當我們說話的時候,有意義的各個詞語必須要按照一定的語法順序正確組織起來,才能具有意義。如果將同樣的詞語調換順序,則語句很有可能變成完全不同的意思。如何將RNN的技術應用於自然語言處理成為了人們關注的重點。

例如,我們是否能夠將剛才預測風力發電的模型(輸入為風速,輸出為風力發電量)改造成為一個實時機器翻譯的模型,使得我們能不斷按順序地輸入一個語句中的英文單詞,而模型輸出中文單詞,使得這些中文單詞能夠連成翻譯完成後的句子?

但是,人們發現在自然語言處理的領域中,RNN的表現不盡如人意。其效果甚至還不如一些傳統模型,諸如我們前面介紹過的HMM之類的。這由於在RNN中,輸入對於輸出在時間上的影響是快速下降的。這正是由於使用tanh這樣的激活函數所導致的後果。這也導致了某一個時刻的輸入在經歷了幾次時間維度上的傳遞之後,效果會迅速衰減,以至於其可能無法影響到幾個時刻以後的輸出。

對於風力發電而言,某個時刻的發電量或許與一分鐘之間的風速有重大關係,但是其與十分鐘之間的風速可能關係不大。所以對於風力發電這樣的數據而言,RNN的結構是合適的。但是對於自然語言這樣的序列而言,各個輸入可能對於輸入有著長度不同的影響。其中有的輸入可能未來的輸出具有極其深遠的影響。例如我們在文章開頭申明了故事發生的時間是在三個月以前,這就意味著全篇所有動詞要採用過去式等等。而RNN的結構對於這種輸入的深遠影響是無能無力的。

針對RNN的這個缺憾,人們發明了LSTM模型。

LSTM

LSTM的全稱為Long Short Term Memory。由於其具有狀態能夠隨著時間傳遞的性質,所以它本質上也屬於RNN。不過,LSTM的結構與第二節中提到的RNN有較大的不同。所以當LSTM發明之後,人們一般用RNN特指代前面所提及的、結構較為簡單樸素的RNN,以將其與結構較為複雜的LSTM分開。

在普通的RNN中,由於循環結構的設計,模型是具有一定的記憶的。但是另一方面,由於隱藏層是由公式st=f(Wst?1+Uxt)計算出來的,信息從st?1到st可能發生了翻天覆地的變化。這也就是說,模型頂多只具有「短期的記憶」。而我們希望發明一種更加穩健的記憶方式,即st?1到st大致上是不變的。輸入的xt只能為其帶來一定的微小變化。如果我們擁有這樣的結構,則我們可以說模型具有了一種「長期的記憶」。

LSTM的主要思想是要為模型加入一個較為長期的記憶。只有擁有長期記憶,在面對自然語言處理這類問題的時候,它才有可能記得住現在的時間、地點、人稱,以及語境,還有各個單詞的組織順序,繼而才能翻譯出合乎人類邏輯的句子。其設計思路如下:

1.增加遺忘機制。例如當一個場景結束是,模型應該重置場景的相關信息,例如位置、時間等。而一個角色死亡,模型也應該記住這一點。所以,我們希望模型學會一個獨立的忘記/記憶機制,當有新的輸入時,模型應該知道哪些信息應該丟掉。

2.增加保存機制。當模型得到新的輸入的時候,需要學會其中是否有值得使用和保存的信息。即面對新的輸入,模型首先忘掉哪些用不上的長期記憶信息,然後學習新輸入有什麼值得使用的信息,然後存入長期記憶中。

3.把長期記憶聚焦到工作記憶中。最後,模型需要學會長期記憶的哪些部分立即能派上用場。不要一直使用完整的長期記憶,而要知道哪些部分是重點。

LSTM的結構示意圖如下:

在上圖中,我們假定中央的細胞是C,而三個標記 σ 的圓圈表示「三重門」:輸入門 i,輸出門 o,遺忘門 f,均使用有壓縮性的函數(比如Sigmoid或tanh)將取值範圍限制到 (0, 1) 之內。計算公式如下,其中σ表示Sigmoid、g表示tanh、Φ表示softmax:

其中W表示權值矩陣(例如Wix表示從輸入門到輸入的權值矩陣,Wic表示窺連孔連接的對角權值矩陣)。 由於其計算公式十分複雜,所以我們不對其進行詳細的一一解釋了。並且可以預想到,如果要求給定訓練集各個參數的梯度,那無疑會更加複雜,甚至比第二節中我們看到的RNN對各項參數的梯度公式還要複雜很多。所以,我們也不再列出其公式了,有興趣的讀者可以自己上網查閱有關資料。有關LSTM,我們最主要需要記住的就是,它含有長記憶,以及有關遺忘與增添記憶的機制。正是藉助這種結構,它可以把序列中一些特殊元素對於序列的影響保持很久。

以下是LSTM的另一種形式的圖例。它有助於我們更好地理解LSTM的工作方式:

總的來說,LSTM結構過於複雜。所以作為LSTM的簡化,有人提出了GRU(Gated Recurrent Unit)。LSTM有三個門——遺忘門、輸入門與輸出門。而GRU只有兩個門——更新門與重置門。所以,在同樣能夠長期保留輸入的影響的前提下,GRU的結構比起LSTM要相對簡單一些。其示意圖如下:

GRU的輸出、輸出與隱藏狀態的計算公式如下:

而Jos vander Westhuizen等人目前的工作又進一步指出,如果在LSTM的基礎上進行修改,使得其只有一個門——遺忘門,則其結構又會變得比GRU更加簡單,並且他們通過實驗證明這種簡化後的LSTM在許多數據集上表現出比普通的LSTM與GRU更好的結果。它們將這種新式的簡化版LSTM稱作JANET(Just Another NET)。 JANET的計算公式為:

總的來說,帶有長記憶結構的RNN,例如LSTM、GRU、JANET等,目前是自然語言處理領域表現最佳的模型。由於其計算輸出的前傳公式與計算梯度的後傳公式都極其複雜,所以本文不進行詳細的介紹。感興趣的同學可以查閱有關資料。

小結

在本文中,我們首先介紹了序列型的數據與其它普通數據的不同之處,介紹了其不能當做一般獨立同分布回歸問題用普通NN回歸的原因。然後,我們介紹了能夠利用序列的特性的RNN結構,並且舉了一個簡單的例子,以說明其從輸入前傳計算輸出的機制,以及從輸出端的誤差後傳求各個參數的梯度的方法。

接下來,我們介紹了使用RNN時候的一些注意事項(例如不適宜使用CNN領域最火的ReLU做為激活函數)以及其導致的RNN的局限性(輸入對輸出造成的影響不能持續太久)。為此,我們給出了LSTM結構的簡要介紹。LSTM的特殊結構可以使其較長時間保留住一些特殊輸入的影響,也正是由於這個特點,它才能在自然語言處理領域取得如此大的成功。

對於RNN以及LSTM,尤其是具有一定深度的結構而言,其前傳與後傳的表達式都是十分複雜的。所以在本文中我們省略了這個部分。在大多數深度學習框架中,一般也可以有封裝好的RNN以及LSTM可以直接調用,不需要從頭寫起。對於希望能夠更加深刻的理解模型的同學,可以查閱有關論文,並且對相關公式進行詳細推導。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

懷宋齋正式開張啦
沛納海復刻表高端品牌

TAG:全球大搜羅 |