使用Keras進行深度學習:(五)RNN和雙向RNN講解及實踐
作者 | Ray
編輯 | 磐石
出品 | 磐創AI技術團隊
介紹
通過對前面文章的學習,對深度神經網路(DNN)和卷積神經網路(CNN)有了一定的了解,也感受到了這些神經網路在各方面的應用都有不錯的效果。然而這些網路都有一個共同的特點:每一層的神經元之間是相互獨立的,如輸入層的神經元彼此之間是獨立的。然而,現實世界中很多元素之間都是有相互聯繫的。比如一部連續劇的內容,上一集和這一集的內容會有一定的聯繫;同樣的,一句話,如「天空很藍」,我們通過「天空」和「很」會認為接下來的詞為「藍」的概率會較高。正如這種時序數據問題,使用之前所學的模型(除了text-CNN)可能很難做到準確的推斷,因此我們引入今天所講的循環神經網路(recurrent neural network),其主要的用處就是處理和預測序列數據。
目錄
lRNN網路結構及原理講解
l雙向RNN網路結構及原理講解
l深層RNN網路結構
lKeras對RNN的支持
l使用Keras RNN、BRNN、DBRNN模型進行實踐
一、RNN網路結構及原理講解
RNN的網路結構如下圖:
圖中左側是未展開RNN模型,在模型中間有個大圓圈表示循環,正是這個循環允許信息的持久化。但這個看起來可能不太好理解,因此將其展開為右側的模型,並做進一步詳細介紹如何實現信息的持久化。
右圖中圓圈可以看作一個單元。定義Xi為第i時刻的輸入,hi為第i時刻的記憶,yi為第i時刻的輸出。
舉個例子說明RNN實現過程:假設有一個句子的輸入是」今天天空很」,要預測下個詞是什麼。通過分詞後可能得到三個詞作為輸入:「今天」,「天空」,「很」,對應的就是上圖的Xi-1,Xi,Xi+1,那麼輸出yi-1應該是「天空」,yi應該是「很」,預測下個詞yi+1是什麼,根據這句話,「藍」的概率比較大。因此預測下個詞應該是「藍」。
通過上述淺顯易懂的例子讀者應該對RNN實現過程有個大概的了解,接下來將具體講解RNN實現的詳細過程。
輸入層到隱藏層:
從上圖的箭頭指示,讀者或許發現第i時刻的輸出是由上一時刻的記憶和當前時刻共同決定的。這個思想很符合對時序數據處理的思路。正如我們在看連續劇的時候如果直接看中間某一集,可能會對部分劇情不能理解,但是,當我們看過前幾集後會對劇情有所記憶,再加上該集劇情內容,我們就能更好的理解接下來劇情內容。因此用公式表示RNN當前時刻的記憶為:
其中f()函數為激活函數。在此處要加上激活函數也很好理解,因為得到的信息並不是所有的都是重要的信息,而我們只需要記住重要的信息即可。這個時候就可以使用激活函數,如tanh,去對一些不重要的信息進行過濾,保留重要的信息即可。
隱藏層到輸出層:
同樣使用電視劇的例子進行通俗解釋,當我們對上幾集和該集的劇情進行整理,留下一些重要信息之後,我們會試圖去猜測下一集的內容大概會是怎麼樣的。同樣的,RNN的思路也如此。當我們hi中保留了i時刻的重要信息後,就試圖使用這些重要信息進行預測下一個詞應該是什麼。用公式表示RNN當前時刻的輸出為:
使用softmax函數是RNN希望預測每個詞出現的概率,然後概率最高的詞就是預測的下一個詞。
註:U、W、V分別是對應的權重矩陣,通過反向傳播演算法調整相應的值使得預測的結果更加準確。與CNN一樣,網路中的每個單元都共享同一組(U、V、W),可以極大的降低了計算量。
具體的前向傳播計算過程如下:
在t1時刻的輸入為2,結合上一時刻的記憶(0.537,0.462),得到(0.54,0.46,2.0),然後與隱藏層的權重矩陣相乘得到該時刻的記憶(0.860,0.884)。通過該時刻的記憶與輸出層的權重矩陣相乘得到該時刻的預測值2.73。這就是一個時刻RNN前向傳播的具體過程。
因此,通過上述思想,RNN就能有效的處理時序數據,對每個輸入保留一些重要的信息,理論上最後就能得到整個輸入的所有重要信息,進而綜合考慮所有輸入去預測輸出。
二、雙向RNN(BRNN)網路結構及原理講解
在RNN中只考慮了預測詞前面的詞,即只考慮了上下文中「上文」,並沒有考慮該詞後面的內容。這可能會錯過了一些重要的信息,使得預測的內容不夠準確。正如電視劇的例子,當在該集新出現了一個人物,若要預測該人物的名字,單從前幾集的內容,並不能有效的進行預測。但如果我們看了後幾集的內容,可能就能更加有效的進行預測。雙向RNN也是基於這種思想,不僅從前往後(如下圖黃色實箭頭)保留該詞前面的詞的重要信息,而且從後往前(如下圖黃色虛箭頭)去保留該詞後面的詞的重要信息,然後基於這些重要信息進行預測該詞。雙向RNN模型如下:
用公式表示雙向RNN過程如下:
另外,雙向RNN需要保存兩個方向的權重矩陣,所以需要的內存約為RNN的兩倍。
三、深層RNN(DRNN)網路結構
深層RNN網路是在RNN模型多了幾個隱藏層,是因為考慮到當信息量太大的時候一次性保存不下所有重要信息,通過多個隱藏層可以保存更多的重要信息,正如我們看電視劇的時候也可能重複看同一集記住更多關鍵劇情。同樣的,我們也可以在雙向RNN模型基礎上加多幾層隱藏層得到深層雙向RNN模型。
註:每一層循環體中參數是共享的,但是不同層之間的權重矩陣是不同的。
四、Keras對RNN的支持
在Keras同樣對RNN模型進行了封裝,並且調用起來十分方便,我們將會在下一節搭建RNN模型來呈現使用Keras搭建是多麼方便。
Keras在layers包的recurrent模塊中實現了RNN相關層模型的支持,並在wrapper模型中實現雙向RNN包裝器。
recurrent模塊中的RNN模型包括RNN、LSTM、GRU等模型(後兩個模型將在後面Keras系列文章講解):
1.RNN:全連接RNN模型
SimpleRNN(units,activation="tanh",dropout=0.0,recurrent_dropout=0.0, return_sequences=False)
2.LSTM:長短記憶模型
LSTM(units,activation="tanh",dropout=0.0,recurrent_dropout=0.0,return_sequences=False)
3.GRU:門限循環單元
GRU(units,activation="tanh",dropout=0.0,recurrent_dropout=0.0,return_sequences=False)
4.參數說明:
units: RNN輸出的維度
activation: 激活函數,默認為tanh
dropout: 0~1之間的浮點數,控制輸入線性變換的神經元失活的比例
recurrent_dropout:0~1之間的浮點數,控制循環狀態的線性變換的神經元失活比例
return_sequences: True返回整個序列,用於stack兩個層,False返回輸出序列的最後一個輸出,若模型為深層模型時設為True
input_dim: 當使用該層為模型首層時,應指定該值
input_length: 當輸入序列的長度固定時,該參數為輸入序列的長度。當需要在該層後連接Flatten層,然後又要連接Dense層時,需要指定該參數
wrapper模塊實現雙向RNN模型:
1.雙向RNN包裝器
Bidirectional(layer, merge_mode=』concat』, weights=None)
參數說明:
layer: SimpleRNN、LSTM、GRU等模型結構,確定是哪種RNN的雙向模型
Merge_mode: 前向和後向RNN輸出的結合方式,為sum,mul,concat,ave和None之一,若為None,則不結合,以列表形式返回,若是上文說到的拼接則為concat
五、使用Keras RNN、BRNN模型、DBRNN模型進行實踐
本次實踐同樣使用上一篇文章中使用到的Imdb數據集進行情感分析。對於該數據集的預處理在本篇文章中就不再介紹,若想了解可閱讀上一篇文章。
Keras在實現循環神經網路很方便,已經將其封裝好,只需要調用相應的層就可以搭建該模型,接下來簡單的搭建上述三種模型。
搭建一層的RNN模型,只需要在模型中加入SImpleRNN層,並設置該層的輸出即可,其他模型的搭建都和上篇文章中講解的一樣,相當方便。
BRNN模型需要使用wrappers包的Bidirecitional模塊實現雙向RNN模型,並且要將return_sequences參數設置為True,因為如上文所述需要將前、後向的重要信息拼接起來,所以需要將整個序列返回,而不是只返回最後一個預測詞。
並且上文提到的是將前後向的進行拼接,所以使用的是』concat』,也可以使用sum對前後向結果求和或者其他對結果進行相應的操作。
DBRNN模型的搭建也很方便,比如在這裡我們要搭建一個兩層的DBRNN模型,只需要再加一層SimpleRNN即可。要注意的是,如果要搭建多層DBRNN模型,除了最後一層SimpleRNN外,其他的SimpleRNN層都需要將return_sequences參數設置為True。
可能讀者會認為雖然Keras搭建模型很方便,但是這會導致新手對於模型的輸入輸出欠缺理解。同樣的,Keras也考慮到了這一點,因此Keras中有model.summary()的內置函數,通過這個函數就可以知道我們搭建的模型的輸入輸出和參數等信息,便於我們理解模型和debug。下圖給出上圖搭建的DBRNN的summary。
模型的損失函數,優化器和評價指標如下:
在訓練模型之前,介紹Keras中一種優化模型效果且可以加快模型學習速度的方法:EarlyStopping。
EarlyStopping介紹
EarlyStopping是Callbacks的一種,callbacks用於指定在每個epoch開始和結束的時候進行哪種特定操作,即用於提前停止訓練的callbacks。之所以要提前停止訓練,是因為繼續訓練會導致測試集上的準確率下降。那繼續訓練導致測試準確率下降的原因筆者猜測可能是1. 過擬合 2. 學習率過大導致不收斂 3. 使用正則項的時候,Loss的減少可能不是因為準確率增加導致的,而是因為權重大小的降低。
EarlyStopping的使用
一般是在model.fit函數中調用callbacks,fit函數中有一個參數為callbacks。注意這裡需要輸入的是list類型的數據,所以通常情況只用EarlyStopping的話也要是[EarlyStopping()]
keras.callbacks.EarlyStopping(monitor="val_loss", patience=0, verbose=0, mode="auto")
參數說明:
monitor:需要監視的量,如"val_loss", "val_acc", "acc", "loss"。
patience:能夠容忍多少個epoch內都沒有improvement。
verbose:信息展示模式
mode:『auto』,『min』,『max』之一,在min模式下,如果檢測值停止下降則中止訓練。在max模式下,當檢測值不再上升則停止訓練。例如,當監測值為val_acc時,模式應為max,當檢測值為val_loss時,模式應為min。在auto模式下,評價準則由被監測值的名字自動推斷。
可以看到在第13次訓練完成後,驗證集的準確率下降後就停止了繼續訓練,這樣可以既可以加快訓練模型速度,也可以使得在驗證集的準確率不再下降。
最後我們使用三種訓練好的模型進行預測測試集,得到在RNN和DBRNN上模型的準確率在0.85左右,在BRNN模型在0.87左右。讀者可以通過調參進一步提高模型的準確率。
至此,我們應該對RNN模型以及Keras實現RNN模型有了一定的了解。下一篇文章我們將會對RNN模型的改進模型LSTM模型進行詳細講解。歡迎持續關注我們的Keras系列文章!
※TensorFlow+Keras 實戰 YOLO v3 目標檢測圖文並茂教程
TAG:磐創AI |