傳統的語言模型在預測序列中的下一個單詞時只會考慮到前面的有限個單詞,RNN與之不同,RNN網絡會根據前面已經出現的所有輸入來調整整個網絡。下圖是RNN網絡的典型結構:
Xt表示在t時刻的輸入,ht表示t時刻的隱藏層狀態,yt表示t時刻的輸出。每一個隱藏層都有許多的神經元,這些神經元將上一層的輸入做線性變換(矩陣乘法,也就是乘以權重),然后再使用非線性激活函數進行激活。t時刻的輸入Xt和t-1時刻的隱藏層狀態作為t時刻隱藏層的輸入,並由隱藏層產生t時刻的輸出特征ht,再對ht使用全連接和softmax作為最終的輸出。用公式表示如下:
RNN網絡中的損失函數通常定義為交叉熵損失函數,假設序列長度為T,詞庫的大小為V,那么在時間步長為t時的損失可以表示為:
在整個時間步長內,損失函數可表示為:
語言模型效果好壞的評價指標通常是復雜度,其計算公式如下:
復雜度越低,模型預測的序列中下一個詞的可信度就越高。
梯度消失和梯度爆炸問題
在RNN網絡中,權重矩陣從一個時間步長被傳遞到下一個時間步長。在反向傳播的過程中,計算損失函數在t時刻的梯度需要將從0時刻到t時刻的所有梯度相加,而越早時刻的梯度越可能會出現梯度彌散或者梯度爆炸的現象。下面我們從數學角度來分析一下這一現象:
為計算損失函數對權重的梯度,我們需要將每一個時間步長處的損失累加起來,用公式表示為:,在每一個時刻時,我們使用鏈式法則可以將誤差對權重的導數表示為:
需要注意的是是ht對之前每一個時間步長(1<=k<=t)處的的偏導數,對於使用鏈式法則將其展開為:
因為hj是一個n維向量,所以是一個n*n維的矩陣,將上面幾個式子整合在一起可以得到:
這里分別表示權重矩陣和導數對角矩陣的L2范數的上界。所以有:
表達式的最右邊是一個指數函數,當大於1或者小於1時,隨着序列長度的增加,很容易發生梯度爆炸和梯度彌散的現象。在訓練過程中,梯度爆炸很容易被檢測到,因為計算機能夠表示的數是有限的,而當發生梯度彌散時,模型的學習效果會下降。
解決梯度彌散、爆炸的方法
下圖展示了RNN網絡損失函數對權重和偏置的關系圖。
從圖中可以看見,圖中存在一個非常陡峭的面,在更新參數的過程中,如果當前參數所處的位置剛好位於這個高高的“誤差牆”上,由於這個面上的梯度非常大,那么采用梯度下降法更新后的參數可能就跑得很遠,如圖中藍色的實線所示。因此,為了解決這個問題,gradient clipping算法為梯度的范數設置了一個閾值,當梯度的范數大於某個值的時候,將梯度設置為這個閾值,算法描述如下:
但是這個方法也存在一個問題:只能夠解決梯度爆炸的問題,而不能夠解決梯度彌散的問題。為了結局梯度彌散的問題,我們引入了兩種技術:
1、 對於隱層態的權重矩陣Whh使用單位矩陣進行初始化而不是隨機初始化;
2、 使用RELU激活函數而不是Sigmoid激活函數,因為RELU函數的導數為0或者1,在反向傳播的過程中不會衰減至0。
深度雙向RNN網絡
上面我們談到的RNN網絡是根據過去時刻的單詞來預測下一個單詞,其實我們也可以根據未來的單詞來預測這一個單詞。雙向RNN網絡就是這樣的結構,其結構示意圖如下所示:
這個網絡有兩個隱藏層,一個從右向左傳播,另一個從左向右傳播;由於網絡的權重和偏置參數是單向RNN網絡的兩倍,所以這個網絡也需要兩倍的內存空間來存儲參數。最終的輸出結果則是將這兩個隱藏層的輸出組合起來。數學表達式如下:
RNN機器翻譯模型
傳統的翻譯模型十分復雜,在翻譯的不同階段使用了大量不同的機器學習算法。這里我們使用RNN網絡來構建一種翻譯模型作為傳統翻譯模型的替代。該模型的網絡結構如下:
這個網絡前3個時間步長將源語言進行編碼,提取特征,后面兩個時間步長將h3解碼輸出為目標語言。數學表達式如下:
第一個方程表示編碼的過程,第二個方程和第三個方程表示解碼過程。
損失函數使用交叉熵損失。事實上,這個網絡的實際表現並不是那么令人滿意,在實際應用中,通常會有下面這幾個改進:
1、 在訓練過程中,編碼和解碼使用的權重分別采用獨立的不同的值,這相當於將兩組權重解耦和,從而能夠獲得更高的正確率;
2、 在解碼器的訓練過程中使用三種不同的輸入:上一時刻的預測結果、上一時刻的隱藏態和編碼器中最后時刻的隱藏態,即:ht= f(ht-1, c, yt-1);
3、 使用更深的更多層的循環神經網絡,因為更深的神經網絡有着更強的學習能力,能夠提升預測的精確度;
4、 訓練雙向的編碼器網絡;
5、 如果一個句子ABC經翻譯后的結果為DEF,那么我們在訓練的過程中可以將輸入的序列順序改為CBA,因為直觀地講,A被翻譯為D的可能性較大,這樣可以降低翻譯的錯誤率;
如何解決梯度爆炸和梯度彌散問題
一般的RNN網絡會存在梯度彌散和梯度爆炸問題,梯度爆炸的問題可以通過使用Gradient Clipping的方法來解決,而梯度彌散的問題則需要重新設計RNN的網絡結構。GRU和LSTM就是為了解決梯度彌散的問題而設計的。
GRU
門控循環單元的結構如下所示:
一般的循環神經網絡在理論上雖然可以獲得長期依賴,但是在實際訓練過程中卻很難做到。GRU擁有更持久的記憶,因而能夠更容易地獲得長期依賴。其數學表達式如下:
1、 產生新的記憶:將新的輸入xt和上一時刻的隱藏態結合起來產生我內心的記憶;
2、 重置門:重置門的作用是決定上一時刻的隱藏態在產生新的記憶過程中的重要程度,當它發現過去的隱藏態與新的記憶無關時,它可以完全消除過去的隱藏態對產生新的記憶的影響;
3、 更新門:更新門決定了上一時刻的隱藏態對當前時刻隱藏態的重要程度;當zt=0時,新的隱藏態全部由新產生的記憶組成,而當zt=1時,新的隱藏態與過去的隱藏態完全一樣;
4、 隱藏態:隱藏態由更新門的值、新的記憶值和上一時刻的隱藏態共同決定;
需要注意的是,在訓練GRU的過程中,W、U、W(r)、U(r)、 W(z)、U(z)全部都是需要學習的參數。
LSTM
LSTM是另一種復雜的激活單元,它和GRU有些許不同。設計LSTM的目的和GRU類似。LSTM的結構示意圖如下:
另一種圖像化表達形式:
其數學表達式為:
1、 產生新的記憶: 使用t時刻的輸入和上一時刻的隱藏態來計算新的記憶;
2、 輸入門:在產生新的記憶時,我們發現網絡並不會去檢查新的輸入對於新時刻的記憶有多重要,而輸入門的意義就在這里,它將新的輸入和上一時刻的隱藏態作為輸入來計算it,it被用來控制新產生的記憶對新時刻下最終記憶的貢獻程度;
3、 遺忘門:遺忘門的作用與輸入門類似,但是遺忘門不是用來檢查新時刻的輸入,而是用來控制上一時刻的最終記憶對於新時刻的最終記憶狀態的貢獻程度;
4、 最終記憶:最終記憶的產生依賴於輸入門和遺忘門的輸出以及上一時刻的最終記憶和新時刻產生的新記憶,它是將上一時刻的最終記憶和新時刻產生的新記憶綜合后的結果;
這里遺忘門的輸出ft和上一時刻的記憶狀態Ct-1是逐元素相乘,而不是矩陣相乘,輸入門it與新產生的記憶之間也是逐元素相乘的;
5、 輸出門:這個門在GRU里不存在,這個門的作用是將最終記憶與隱藏態分離開來;最終記憶里包含了大量的不需要在隱藏態里保存的信息,因此輸出們的作用是決定最終記憶里哪些部分需要被暴露在隱藏態中。
LSTM能夠解決梯度彌散和梯度爆炸問題的原因
1、 遺忘門與上一時刻的記憶之間是矩陣元素相乘,而不是矩陣相乘;
2、 遺忘門在不同的時間步長會取不同的值;
3、 遺忘門的激活函數是sigmoid函數,值域范圍為(0,1)。