TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

磐創AI發表於2018-11-22

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

編輯 | 安可

出品 | 磐創AI技術團隊

目錄:

  • 前言

  • RNN知識結構

  • 簡單迴圈神經網路

  • RNN的基本結構

  • RNN的運算過程和引數更新

    • RNN的前向運算

    • RNN的引數更新

一.前言

前饋神經網路不考慮資料之間的關聯性,網路的輸出只和當前時刻網路的輸入相關。然而在解決很多實際問題的時候我們發現,現實問題中存在著很多序列型的資料,例如文字、語音以及影片等。這些序列型的資料往往都是具有時序上的關聯性的,既某一時刻網路的輸出除了與當前時刻的輸入相關之外,還與之前某一時刻或某幾個時刻的輸出相關。而前饋神經網路並不能處理好這種關聯性,因為它沒有記憶能力,所以前面時刻的輸出不能傳遞到後面的時刻。

此外,我們在做語音識別或機器翻譯的時候,輸入和輸出的資料都是不定長的,而前饋神經網路的輸入和輸出的資料格式都是固定的,無法改變。因此,需要有一種能力更強的模型來解決這些問題。

在過去的幾年裡,迴圈神經網路的實力已經得到了很好的證明,在許多序列問題中,例如文字處理、語音識別以及機器翻譯等,迴圈神經網路都取得了顯著的成績。迴圈神經網路也正被越來越多的應用到其它領域。

二. RNN知識結構

在本章中,我們將會從最簡單的迴圈神經網路開始介紹,透過例項掌握迴圈神經網路是如何解決序列化資料的,以及迴圈神經網路前向計算和引數最佳化的過程及方法。在此基礎上我們會介紹幾種迴圈神經網路的常用結構,既雙向迴圈神經網路、深度迴圈神經網路以及遞迴神經網路。我們會使用TensorFlow實現迴圈神經網路,掌握使用TensorFlow搭建簡單迴圈神經網路的方法。

此外,我們還會學習一類結構更為複雜的迴圈神經網路——門控迴圈神經網路,包括長短期記憶網路(LSTM)和門控制迴圈單元(GRU),這也是目前最常使用的兩種迴圈神經網路結構。最後我們還會介紹一種注意力模型:Attention-basedmodel,這是近兩年來的研究熱點。在下一章的專案實戰中,我們會使用到Attention-basedmodel以及前面提到的LSTM等模型解決一些實際的問題。

本章內容結構如下:

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

圖1 本章內容結構 

三. 簡單迴圈神經網路

簡單迴圈網路(simple recurrent networks,簡稱SRN)又稱為Elman network,是由Jeff Elman在1990年提出來的。Elman在Jordan network(1986)的基礎上進行了創新,並且簡化了它的結構,最終提出了Elman network。Jordan network和Elman network的網路結構如下圖所示。

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

圖2 Jordan network(左)和Elman network(右)

圖片引用自ResearchGate:https://www.researchgate.net/figure/A-recurrent-neural-network-as-proposed-by-Jordan-1986_fig5_277603865

從圖2中可以很直觀的看出,兩種網路結構最主要的區別在於記憶單元中儲存的內容不同。Jordan network的記憶單元中儲存的是整個網路最終的輸出,而Elmannetwork的記憶單元只儲存中間的迴圈層,所以如果是基於Elman network的深層迴圈神經網路,那麼每一個迴圈的中間層都會有一個相應的記憶單元。有興趣深究的讀者可以查閱Elman和Jordan的論文:~elman/Papers/fsit.pdf,~gary/PAPER-SUGGESTIONS/Jordan-TR-8604.pdf。

Jordan network和Elman network都可以擴充套件應用到深度學習中來,但由於Elman network的結構更易於擴充套件(Elman network的每一個迴圈層都是相互獨立的,因此網路結構的設計可以更加靈活。另外,當Jordan network的輸出層與迴圈層的維度不一致時還需要額外的調整,而Elmannetwork則不存在該問題。),因此當前主流的迴圈神經網路都是基於Elman network的,例如我們後面會介紹的LSTM等。所以,通常我們所說的迴圈神經網路(RNN),預設指的就是Elman network結構的迴圈神經網路。本書中所提到的迴圈神經網路,如果沒有特別註明,均指Elman network結構的迴圈神經網路。

四. RNN的基本結構

迴圈神經網路的基本結構如下圖所示(注意:為了清晰,圖中沒有畫出所有的連線線。):

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

圖3 迴圈神經網路的基本結構

關於迴圈神經網路的結構有很多種不同的圖形化描述,但是其所表達的含義都與圖1一致。將迴圈神經網路的結構與一般的全連線神經網路比較,我們會發現迴圈神經網路只是多了一個記憶單元,而這個記憶單元就是迴圈神經網路的關鍵所在。

從圖3我們可以看到,迴圈神經網路的記憶單元會儲存時刻時迴圈層(既圖3中的隱藏層)的狀態TensorFlow系列專題(七):一文綜述RNN迴圈神經網路,並在t+1時刻,將記憶單元的內容和t+1時刻的輸入TensorFlow系列專題(七):一文綜述RNN迴圈神經網路一起給到迴圈層。為了更直觀的表示清楚,我們將迴圈神經網路按時間展開,如圖4所示。

圖4所示,左邊部分是一個簡化的迴圈神經網路示意圖,右邊部分是將整個網路按時間展開後的效果。在左邊部分中,x是神經網路的輸入,U是輸入層到隱藏層之間的權重矩陣,W是記憶單元到隱藏層之間的權重矩陣,V是隱藏層到輸出層之間的權重矩陣,s是隱藏層的輸出,同時也是要儲存到記憶單元中,並與下一時刻的x一起作為輸入,o是神經網路的輸出。

從右邊的展開部分可以更清楚的看到,RNN每個時刻隱藏層的輸出都會傳遞給下一時刻,因此每個時刻的網路都會保留一定的來自之前時刻的歷史資訊,並結合當前時刻的網路狀態一併再傳給下一時刻。

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

圖4 迴圈神經網路及其按時間展開後的效果圖

圖片來源於Nature

理論上來說,RNN是可以記憶任意長度序列的資訊的,即RNN的記憶單元中可以儲存此前很長時刻網路的狀態,但是在實際的使用中我們發現,RNN的記憶能力總是很有限,它通常只能記住最近幾個時刻的網路狀態,在本章的第4節裡,我們會具體討論這個問題。

五. RNN的運算過程和引數更新

1. RNN的前向運算

在一個全連線的迴圈神經網路中,假設隱藏層只有一層。在時刻神經網路接收到一個輸入,則隱藏層的輸出為:                   

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

上式中,函式f(·)是隱藏層的啟用函式,在TensorFlow中預設是tanh函式。引數U和W在前面介紹過,分別是輸入層到隱藏層之間的權重矩陣和記憶單元到隱藏層之間的權重矩陣,引數b1是偏置項。在神經網路剛開始訓練的時候,記憶單元中沒有上一個時刻的網路狀態,這時候TensorFlow系列專題(七):一文綜述RNN迴圈神經網路就是一個初始值。

在得到隱藏層的輸出後,神經網路的輸出為:                       TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

上式中,函式g(·)是輸出層的啟用函式,當我們在做分類問題的時候,函式g(·)通常選為Softmax函式。引數V是隱藏層到輸出層的引數矩陣,引數b2是偏置項。

我們先看看TensorFlow原始碼中關於RNN隱藏層部分的計算。這部分程式碼在TensorFlow原始碼中的位置是:

在rnn_cell_impl.py檔案中定義了一個抽象類RNNCell,其它實現RNN的類都會繼承這個類,例如BasicRNNCell、BasicLSTMCell以及GRUCell等。我們以BasicRNNCell類為例,所有繼承了RNNCell的類都需要實現一個call方法,BasicRNNCell類中的call方法的實現如下:

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

從上面的TensorFlow原始碼裡可以看到,TensorFlow隱藏層的計算結果即是該層的輸出,同時也作為當前時刻的狀態,作為下一時刻的輸入。第2、3行的註釋說明了“call”方法的功能:TensorFlow系列專題(七):一文綜述RNN迴圈神經網路其實就是實現了我們前面給出的公式6.1。第5行程式碼中的“self._kernel”是權重矩陣,第6行程式碼中的“self._bias”是偏置項。

這裡有一個地方需要注意一下,這段程式碼在實現TensorFlow系列專題(七):一文綜述RNN迴圈神經網路時,沒有分別計算W*input和U*state,然後再相加,而是先用“concat”方法,將前一時刻的狀態“state”和當前的輸入“inputs”進行拼接,然後用拼接後的矩陣和拼接後的權重矩陣相乘。可能有些讀者剛開始看到的時候不太能理解,其實效果是一樣的,我們看下面這個例子:

我們有四個矩陣:a、b、c和d:

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路           

假設我們想要計算,則有:

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

如果我們把矩陣a和b、c和d先分別拼接到一起,得到e和f兩個矩陣:           

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

再來計算,會得到同樣的結果:         

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

下面我們用一段程式碼實現迴圈神經網路中完整的前向計算過程。

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

上面程式碼裡所使用的RNN結構如下:

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

圖5 程式碼中使用的RNN網路結構

在上面的示例程式碼中,我們用了一個如圖5所示的簡單迴圈神經網路。該網路結構輸入層有兩個單元,隱藏層有兩個神經元,輸出層一個神經元,所有的啟用函式均為tanh函式。在第四行程式碼中我們定義了輸入資料,總共三個time-step,每個time-step處理一個輸入。我們將程式執行過程中各個引數以及輸入和輸出的值以表格的形式展示如下(讀者可以使用下表的資料驗算一遍RNN的前向運算,以加深印象):

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路

TensorFlow系列專題(七):一文綜述RNN迴圈神經網路 

2. RNN的引數更新

迴圈神經網路中引數的更新主要有兩種方法:隨時間反向傳播(backpropagation through time,BPTT)和實時迴圈學習(real-time recurrent learning,RTRL)。這兩種演算法都是基於梯度下降,不同的是BPTT演算法是透過反向傳播的方式來更新梯度,而RTRL演算法則是使用前向傳播的方式來更新梯度。目前,在RNN的訓練中,BPTT是最常用的引數更新的演算法。

BPTT演算法和我們在前饋神經網路上使用的BP演算法本質上沒有任何區別,只是RNN中的引數存在時間上的共享,因此RNN中的引數在求梯度的時候,存在沿著時間的反向傳播。所以RNN中引數的梯度,是按時間展開後各級引數梯度的總和。

本此介紹了簡單RNN網路的構造原理,下一篇我們將會以實戰的形式介紹如何用TensorFlow實現RNN。

原文連結:https://mp.weixin.qq.com/s/mg41AOfNLsLuCvGhPUyOPw

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31555081/viewspace-2221140/,如需轉載,請註明出處,否則將追究法律責任。

相關文章