【機器學習筆記】循環神經網絡RNN



1. 從一個栗子開始 - Slot Filling

比如在一個訂票系統上,我們的輸入 “Arrive Taipei on November 2nd” 這樣一個序列,我們設置幾個槽位(Slot),希望算法能夠將關鍵詞'Taipei'放入目的地(Destination)槽位, 將November和2nd放入到達時間(Time of Arrival)槽位,將Arrive和on放入其他(Other)槽位,實現對輸入序列的一個歸類,以便后續提取相應信息。

用前饋神經網絡(Feedforward Neural Network)來解決這個問題的話,我們首先要對輸入序列向量化,將每一個輸入的單詞用向量表示,可以使用 One-of-N Encoding 或者是 Word hashing 等編碼方法,輸出預測槽位的概率分布。

但是這樣做的話,有個問題就出現了。如果現在又有一個輸入是 “Leave Taipei on November 2nd”,這里Taipei是作為一個出發地(Place of Departure),所以我們應當是把Taipei放入Departure槽位而不是Destination 槽位,可是對於前饋網絡來說,對於同一個輸入,輸出的概率分布應該也是一樣的,不可能出現既是Destination的概率最高又是Departure的概率最高。

所以我們就希望能夠讓神經網絡擁有“記憶”的能力,能夠根據之前的信息(在這個例子中是Arrive或Leave)從而得到不同的輸出。將兩段序列中的Taipei分別歸入Destionation槽位和Departure槽位。


2. RNN

  • 基本概念

    在RNN中,隱層神經元的輸出值都被保存到記憶單元中,下一次再計算輸出時,隱層神經元會將記憶單元中的值認為是輸入的一部分來考慮

    RNN中考慮了輸入序列順序,序列順序的改變會影響輸出的結果。

  • 常見變體

    • Elman Network
      將隱層的輸出(即記憶單元中的值)作為下一次的輸入

    \(h_t = \sigma_h(W_hx_t + U_h\color{green}{h_{t-1}} + b_h)\)

    \(y_t = \sigma_h(W_yh_t + b_y)\)

    • Jordan Network
      將上一時間點的輸出值作為輸入

    \(h_t = \sigma_h(W_hx_t + U_h\color{green}{y_{t-1}} + b_h)\)

    \(y_t = \sigma_h(W_yh_t + b_y)\)

    • Bidirectional RNN

3. Long Short-term Memory (LSTM)

enter image description here

  • 基本結構

    • 由Memory Cell, Input Gate, Output Gate, Forget Gate 組成
    • 特殊的神經元結構,包含4個input(三個Gate的控制信號以及輸入的數據),1個output
    • 激活函數通常選用sigmoid function, sigmoid的輸出介於0到1之間,表征了Gate的打開程度。
  • Traditional LSTM

\[\begin{align} f_t & = \sigma_g(W_fx_t + \color{green}{U_fh_{t-1}} + b_f) \\ i_t & = \sigma_g(W_i x_t + \color{green}{U_ih_{t-1}} + b_i) \\ o_t & = \sigma_g(W_o x_t + \color{green}{U_oh_{t-1}} + b_o) \\ c_t & = f_t\,{\circ}\,c_{t-1} + i_t\,{\circ}\,\sigma_c(W_cx_t\color{green}{+ U_ch_{t-1}} +b_c) \\ h_t & = o_t \,{\circ}\, \sigma_h(c_t) \end{align} \]

  • Peephole LSTM, 在大部分的情況下,用\(\color{blue}{c_{t-1}}\)取代\(\color{green}{h_{t-1}}\)

\[\begin{align} f_t & = \sigma_g(W_fx_t + \color{green}{U_f\color{blue}{c_{t-1}}} + b_f) \\ i_t & = \sigma_g(W_i x_t + \color{green}{U_i\color{blue}{c_{t-1}}} + b_i) \\ o_t & = \sigma_g(W_o x_t + \color{green}{U_o\color{blue}{c_{t-1}}} + b_o) \\ c_t & = f_t\,{\circ}\,c_{t-1} + i_t\,{\circ}\,\sigma_c(W_cx_t +b_c) \\ h_t & = o_t \,{\circ}\, \sigma_h(c_t) \end{align} \]

- $x_t$表示輸入向量,$h_t$表示輸出向量,$c_t$表示記憶單元的狀態向量,$\circ$代表Hadamard product(A.k.a. Schur product)
- $W$表示輸入權重,$U$表示循環權重,$b$表示偏置
- $\delta_g$代表sigmoid function,$\delta_c$代表hyperbolic tangent, $\delta_h$表示 hyperbolic tangent(peephole LSTM論文中建議選用$\delta_h(x)=x$)
- $f_t$,$i_t$和$o_t$表示門控向量值		
    - $f_t$表示遺忘門向量,表征記憶舊信息的能力
	- $i_t$表示輸入門向量,表征獲取新信息的能力
	- $o_t$表示輸出門向量,表征輸出信息的能力
  • 補充知識點
    • Short-term,表示保留對前一時間點輸出的短期記憶,相比於最原始的RNN結構中的記憶單元(每次有新的輸入時記憶體的狀態就會被更新,因此是短期的記憶),而LSTM的記憶體則擁有相對較長的記憶時間(由Forget Gate決定),所以是Long Short-term
    • LSTM一般采用多層結構組合,Multiple-layer LSTM
    • Keras中實現了LSTM,GRU([Cho,Learning Phrase Representations using RNN Encoder-Decoder for Statistical Machine Translation,EMNLP'14] 只有兩個Gate,容易訓練),SimpleRNN層,可以方便的調用。

4. RNN如何學習?

  • 損失函數的定義:

    • 每一個時間點的RNN的輸出和標簽值的交叉熵(cross-entropy)之和
  • 訓練過程:

    • 使用被稱作Backpropagation through time(BPTT)的梯度下降法
    • 訓練其實是比較困難的,因為Total Loss可能會出現劇烈的抖動
      rnn training
    • 根據論文[Razvan Pascanu,On the difficulty of training Recurrent Neural Networks,ICML'13]上對RNN的分析,損失函數的表面要么非常平坦,要么非常陡峭(The error surface is either very flat or very steep),當你的參數值在較為平坦的區域做更新時,因此該區域梯度值比較小,此時的學習率一般會變得的較大,如果突然到達了陡峭的區域,梯度值陡增,再與此時較大的學習率相乘,參數就有很大幅度更新(實線表示的軌跡),因此學習過程非常不穩定。Razvan Pascanu使用了叫做“Clipping”的訓練技巧:為梯度設置閾值,超過該閾值的梯度值都會被cut,這樣參數更新的幅度就不會過大(虛線表示的軌跡),因此容易收斂。
  • 為什么在RNN中會有這種問題?

    • 是因為激活函數選用了sigmoid而不是ReLU么?然而並不是。事實上,在RNN中使用ReLU反而效果會不如Sigmoid,不過也是看你的參數初始化值的選取,所以也不一定,比如后面提到的Quoc V.Le的那篇文章,使用特別初始化技巧硬訓ReLU的RNN得到了可比擬LSTM的效果。因此激活函數並不是這里的關鍵點。
    • 那究竟是什么原因呢?我們來分析梯度更新公式中的\(w-\eta\frac{\partial{L}}{\partial{w}}\)來探尋一番。但是這樣一個偏微分的關系我們應該如何來分析呢?這里我們用一個技巧:給w值一個微小的變化,觀察對應的Loss的變化情況。假設當前模型是1000個只含有一個線性隱層的RNN級聯結構。並假設我們當前的輸入是100000……(只有第一個值是1,剩下全是0),因此最后的輸出值是\(w^{999}\)。現在假設我們\(w\)的值是1,那么RNN在最后時間點的輸出是1,給\(w\)一個微小的變化+0.01,此時的輸出變成了大約20000!這段區域呈現出一個陡峭的趨勢。如果給\(w\)一個微小的變化-0.01變為0.99,測試的輸出基本變成0,哪怕是\(w\)變到0.01時,輸出依舊是0,這段區域呈現出一個平坦的趨勢。因此我們可以看出由於RNN采用時間序列的結構,權重值在不同時間點被反復使用,這種累積性的變化可能對結果造成極大的影響,也可能會很長一段時間保持平穩。
  • 常用的技巧


5. RNN的更多應用場景


6. 其他的學習資料


7. 本文參考資料

Deep & Structured 未完待續


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM