之前面的部落格中,我們已經描述了基本的rnn模型。但是基本的rnn模型有一些缺點難以克服。其中梯度消失問題(vanishing gradients)最難以解決。為了解決這個問題,gru(gated recurrent unit)神經網路應運而生。本篇部落格將描述gru神經網路的工作原理。gru主要思想來自下面兩篇**:
chung et al., 2014. empirical evaluation of gated recurrent neural networks on sequence modeling
一、梯度消失(vanishing gradients)
梯度消失(vanishing gradients)是深度學習中乙個很重要的問題。即在乙個比較深層次的網路中,梯度的計算會隨著層數的增加接近於0,導致網路引數無法更新。與之相對應的還有個問題是梯度**(exploding gradients),即梯度相乘結果太大,最終計算得到了nan值(變數過大導致溢位)。與梯度消失相比,梯度**相對容易解決。一般的做法是,當梯度的結果大於某個值的時候對所有的梯度重新調整(rescaling gradients),然後繼續執行。但是梯度消失這個問題就相對難一點。而標準的遞迴神經網路就很難解決梯度消失的問題。而gru就是為了解決rnn的梯度消失問題。
二、gru神經網路工作原理
為了解決標準rnn的梯度消失問題,gru提出使用兩個向量,即更新門(update gate)和重置門(reset gate)的概念,用來決定什麼樣的資訊應該被傳遞給輸出。它可以儲存很久之前的資訊,也會去掉不相關的資訊。我們舉個例子(來自吳恩達sequence models的課程)。
thecat
, which already ate …,was
full.
注意到這個句子開始提了乙個單數名詞cat
,後面接的是was
。而中間的這些單詞其實對這個was
是沒起到作用的。因此實際上,深度學習在學習was
這個單詞的時候,只需要記住cat
就可以了。下面我們看gru如何解決這個問題。
首先,我們回顧一下標準rnn中乙個rnn-cell裡面的處理,如下圖所示:
每個rnn-cell的輸入都包含了前一階段的輸出a^a和該階段的資料x^x。首先根據這兩個變數計算a^a,然後根據a^a計算輸出的標籤\hat^y^。我們可以看到,標準的rnn使用aa變數來傳遞儲存前面的資訊。這裡就會導致梯度消失和儲存了很多不相關的資訊了。
而gru中的乙個cell的輸入還是一樣,前乙個階段的狀態變數c^c和輸入資料x^x,輸出也依然是新的狀態變數c^c和**標籤\hat^y^,但是它的計算方法卻是如下所示:
先定義乙個臨時變數\tilde^c~,其計算方法如下:
\tilde^ = \text(w_c[c^,x^] + b_c)c~=tanh(wc[c,x]+bc)
然後定義乙個更新門變數\gamma_uγu,計算方法如下:
\gamma_u = \sigma(w_u[c^,x^] + b_u)γu=σ(wu[c,x]+bu)
這裡的\sigmaσ是sigmoid函式,一般來說這個\gamma_uγu是乙個接近於0或者1的值。它的作用就是決定了這一階段的狀態變數c^c是重新計算,還是沿用前面的狀態變數:
c^ = \gamma_u \times \tilde^ + (1-\gamma_u) \times c^c=γu×c~+(1−γu)×c
可以看到,當\gamma_u=0γu=0的時候,c^ = c^c=c,表示當前cell的狀態變數不需要重新計算,直接使用上乙個階段即可。當\gamma_u=1γu=1的時候,c^ = \tilde^c=c~,它是重新計算的結果。最後,我們依然使用c^c來**該cell的標籤\hat^y^。
可以看到上述修改之後會使得最優情況下的狀態變數只會保留前面有用的資訊,而不會儲存太多的資訊,進而導致梯度消失或者是計算成本的上公升。我們還是以上述案例為例,理想情況下,我們應該計算得到如下結果:
thecat
which
already
ate…
wasfull10
0001
新計算同上
同上同上
同上新計算
這裡的第二行計算結果是\gamma_uγu,可以看到cat對應的值是1,說明需要在這裡重新計算狀態變數cc,後面的單詞,一直到was之前的\gamma_u=0γu=0,說明,這些單詞對應的狀態變數都和\textcat一樣。最終,到was的時候,它所依賴的前一階段的狀態變數都是cat計算的,然後was的結果需要根據前一階段重新計算,即它是根據cat單詞計算的,而cat是單數形式,所以這裡的was概率最大。這裡只是乙個簡單的示例,表明原理。
三、完整版gru
上述gru的計算過程是乙個簡化版本。完整的gru的cell計算還包括乙個額外的變數,即重置門\gamma_rγr,它的作用是告訴先前的狀態和當前的狀態是多麼的相關。其完整的計算過程如下(注意,這裡新變數影響了\tilde^c~的計算):
\tilde^ = \text(w_c[\gamma_r\times c^,x^] + b_c)c~=tanh(wc[γr×c,x]+bc)
\gamma_u = \sigma(w_u[c^,x^] + b_u)γu=σ(wu[c,x]+bu)
\gamma_r = \sigma(w_r[c^,x^] + b_r)γr=σ(wr[c,x]+br)
c^ = \gamma_u \times \tilde^ + (1-\gamma_u) \times c^c=γu×c~+(1−γu)×c
四、gru總結
上面就是gru如何使用更新門和重置門儲存和過濾資訊的原理,可以看到,gru並不會每次都把之前的變數拿過來計算,只會儲存相關的資訊,因而會解決梯度消失的問題。與lstm相比,gru的變數更少,計算更簡單,在某些場景下,它的表現能夠和lstm一樣好,因此可以替代lstm的計算。
研究者設計過各種不同的版本來儲存資訊,也解決梯度消失的問題。gru是其中最具代表性和最廣泛應用的乙個。我們可以根據實際情況來更改這種方法。
迴圈神經網路 GRU
這裡我們首先來看一下gru是如何將lstm的三個門簡化成兩個門的結構的 這裡的r rr門 r門這裡同樣是乙個啟用函式 控制的是上乙個時間戳的狀態st 1s st 1 對我們的當前時間戳狀態s ts t st 的乙個影響,r的取值範圍依舊是在0到1之間,也就是說,當你的r門全部關閉 r 0 的時候,就...
迴圈神經網路 GRU
gru是由cho在2014年提出的,全稱是gated recurrent unit。它與lstm最大的不同在於gru將遺忘門和輸入門合成了乙個 更新門 同時網路不再額外給出記憶狀態c tc t ct 而是將輸出結果h th t ht 作為記憶狀態不斷向後迴圈傳遞,網路的輸入和輸出都變得特別簡單。具體...
迴圈神經網路 卷積 池化 GRU
卷積 池化 卷積 gru from keras.models import sequential from keras import layers from keras.optimizers import rmsprop model sequential model.add layers.conv1...