RNN Tutorial(1)
主要採用CS231n RNN部分的slide和CS224 RNN部分的note,綜合了兩者的說法,盡量保證內容完整,清晰,邏輯連貫,因此部分內容使用原paper的說法,以及Tensorflow的tutorial部分。內容以自然語言處理為主,以機器視覺為輔。
主要作用:較完整的RNN入門;相關內容的查漏補缺;鼓勵通過做筆記來紮實學習的方法。
導引:
1.RNN基礎模型:
1.1Recurrent Neural Networks(RNN)
1.2LSTM and GRU
1.3語言模型 Language Models
2.RNN在NLP中應用:
2.1翻譯模型(NMT)
2.2Deep Bidirectional RNNs
2.3Attention 機制
3.與視覺相關模型
3.1圖像描述 Image Captioning
3.2問答系統 Question Answering和VQA
其中1、2、3分別為一節,每節一篇文章。
以語言模型作為問題的出發點:由m個詞組成的句子的概率:
按照傳統的觀點看,要建模和計算之前所有詞的條件概率是很困難的,所以以前常採用當前詞僅與前一個詞有關(Markov假設),或者當前詞僅與固定長度(窗口)的詞有關:
然而在現實應用時,這種模型具有局限性。
Recurrent Neural Networks(RNN)
不像之前有限窗口的方法,RNN可以利用之前所有詞的信息:RNN使用狀態(state)變數來儲存之前的信息,每次計算後,狀態會更新,吸收新的詞的信息。因此理論上RNN能利用任意長度的序列信息,然而實際上RNN只能利用有限長的先前信息(之後詳細討論)。
RNN的基礎結構:
上圖的摺疊表示的RNN(左)等價於展開表示(右)
計算過程:
每一個時刻t,對當前詞和先前狀態進行計算:得到新的狀態,為一激活函數,如sigmoid,tanh,relu等,可以看出新狀態與之前狀態和當前詞都有關,因此其與之前所有詞相關,儲存了所有詞的信息。注意點:
- 為當前輸入,在NLP任務中,使用one-hot的向量表示,或者使用詞向量表示。而在視覺任務中,可以是圖像經過CNN提取的特徵。
- 初始狀態,常取零向量。
- 網路參數W,U,V,不隨時間改變,被整個序列共用,因此可以寫成摺疊表示來簡潔表達結構。
- 額外的,可以計算得到當前輸出,在語言模型中,表示根據之前詞和當前詞的信息,預測下一詞的概率分布:是對的估計。但在一些任務(如機器翻譯)中,就不需要這種輸出。
LSTM and GRU
梯度彌散問題
RNN的本意就是希望能保持任意長度的信息,如"Jane walked into the room. John walked in too. It was late in the day, and everyone was walking home after a long day at work. Jane said hi to ___",要回答出"John",需要RNN有長時的記憶。
然而使用之前介紹的vanilla RNN,會面臨梯度彌散的問題(詳細證明過程見cs224):這是由於每次梯度沿序列反向傳播時會乘上一個W:,當W的值很小時,多步反向傳播後梯度就變得很小,這就說明了多步之前的信息只能起很小的作用;反之當W的值很大時,會導致反向傳播時梯度越來越大(梯度爆炸),不利於網路訓練。
而這種梯度彌散的問題對於網路模型的訓練也是一個問題(見cs231n Lecture 6),為了解決深網路的梯度彌散問題:1.使用更好的初始化方法,而非零初始或簡單隨機初始。2.使用Relu,而非sigmoid。3.使用batch normalization。但這三種方法只能解決一般前向網路的梯度彌散,對於RNN的問題,還是需要對結構進行改良,即使用LSTM或GRU。
而梯度爆炸的情況可以使用clipping的方法解決。
Long Short Term Memory(LSTM)
[Hochreiter et al., 1997]為了解決這個問題,提出了一種改進結構,稱為LSTM。之前RNN只有一個狀態變數,而LSTM還引入了一個新的cell,稱為memory cell,記為,它包含了之前所有詞的總信息,而且我們對它進行盡量簡單的運算,來保證梯度能更容易反向傳播。
LSTM的組成結構和運算過程:
在vanilla RNN,我們僅僅對輸入進行一次線性計算和一次非線性激活函數:。
在LSTM中我們對輸入則進行四次線性計算以及分別的非線性激活函數,得到四個h維輸出:i,f,o,g(or),
利用這四個輸出可以計算得到新的memory cell
含義和作用為:
- New memory cell:表示根據過去狀態和當前詞整合的新記憶雛形,之後會根據,,來決定最後的新記憶
- Input gate:用來決定新生成的記憶是否要寫入最後的新記憶中,寫入多少,因此與進行element-wise乘
- Forget gate:用來決定舊的記憶應該遺忘多少,因此與進行element-wise乘
- Output gate:用來決定新的記憶應該在新的狀態中表現多少,如果,說明它認為下一個詞的信息提取,不依賴於之前的信息。
i,f,o都是gate,決定多少,取值應該在0,1之間,因此用sigmoid激活函數。而g(or)是新的記憶變數,因此用tanh函數。
分析:
因此LSTM中的序列信息由兩個變數攜帶:memory cell和 hidden state,可以認為是攜帶長時信息的,對它的操作盡量簡單:只有element-wise乘和加法,因此gradient在能更容易地反向傳播;而和在RNN中的作用差不多,可以認為是從誘導出,受當前狀態控制的短時記憶,用來處理新的信息。
通過只有element-wise乘和加法,梯度能在整個序列中反向傳播,這一點和ResNet很像。因此LSTM能保留長時的信息,更好地處理當前詞的選擇。
Gated Recurrent Units(GRU)
[Learning phrase representations using rnn encoder-decoder for statistical machine translation, Cho et al. 2014]提出一種更簡潔的結構,稱為GRU,與LSTM原理類似(只用element-wise乘和加法更新memory),可以使梯度更容易的反向傳播。與LSTM不同的是GRU只使用了一個hidden state,因為可以看到LSTM中的變數並沒有更多的信息,完全可以只用來傳遞信息。
一個GRU單元的內部結構:
GRU的計算過程:
其中只使用了兩個gate(相比於LSTM的4個gate),
闡述上式的含義:
- Reset gate:用來決定之前的狀態對於當前詞的總結的是否有作用。如果的取值很小,那說明之前的狀態與當前詞幾乎無關,那麼新的總結應該只提取新詞的信息,而丟棄之前的無用信息,這樣能得到更緊緻的表示。(其作用與LSTM的Output gate類似)
- Update gate:用來決定當前的總結有多少值得傳遞到下一狀態。如果取值很大,那麼幾乎為上一狀態,說明當前總結不需要傳遞下去,即之後詞的處理無需當前總結的信息。如果取值很小,那麼新總結幾乎直接傳給下一狀態,說明當前詞的總結信息對之後詞的處理有價值。
分析:
因為採用的element-wise乘來使用兩個gate,因此在中的每個分量unit都有各自的Reset gate和Update gate(即的分量),那麼這些unit自動學會保持多少的時間跨度:那些保持短時記憶的unit,它們的Reset gate會一直active(1,需要短時工作記憶來做當前總結);那些保持長時記憶的unit,它們的Update gate會一直active(,記憶不會頻繁更新,保證了記憶的持久性)。因此這種自動調控時長的hidden unit就把LSTM中人為控制長短時的兩個cell整合到一起了。
在GRU paper中的實驗部分可以看出這種具有實際意義的gate單元會比沒有意義的tanh unit效果好。
語言模型Language Models
然後在這個概率分布上採樣就能得到一句真實話的樣本。為了達到這個目的,優化RNN時,我們需要真實句子的概率最大化,即提高最大擬然概率,即把負的擬然概率作為loss:
將下式作為t時刻的loss function:,使用RNN時,為的第(所對應的標號)個分量。
那麼一句T長度的話的loss為:。
使用梯度下降方法(SGD)來最小化loss function即可。
使用perplexity來作為衡量標準:。perplexity值越低代表有更多的信心預測下一個詞。
需要說明的是:在訓練時,RNN的輸入為數據集中的一句話(實際編程時,是batch句話),即把一句話樣本中的每一個詞依次輸入到RNN中,而RNN每輸入一個詞都會對下一個詞做一次預測,最後把這句話預測的所有loss求和得到總loss。但在test時,RNN的初始輸入為零狀態和起始標誌詞,每一次也會計算下一個詞的預測,然後在預測概率上採樣得到下一個詞,將採樣詞作為下一個輸入,最後輸出結束標誌詞。
註:在語言模型的test中上圖應該使用單詞而非字母。
noise-contrastive estimation (NCE)
在RNN輸出單詞最後一步,我們使用softmax來輸出一個|V|維向量(|V|為單詞庫中單詞總數),代表了每個單詞的概率,這樣就能用maximum likelihood (ML)來優化模型:,設為之前的單詞,我們需要預測的下個單詞的概率分布為:
注意到分母中需要對單詞庫里所有的單詞的RNN輸出值進行求和,因此每預測一個詞我們需要計算所有詞的得分,並做歸一化,這在單詞庫很大時,計算開銷十分大。
noise-contrastive estimation (NCE)就提出用二分類問題代替原多分類問題:因為我們使用softmax計算概率只是為了計算ML的loss,而,可以看出我們只關心正確答案的概率,而不使用其他詞的概率值,因此其他單詞的值只是用來做歸一化約束,換句話說是作為懲罰項,鼓勵正確詞的值明顯高於其他詞,如果沒有歸一化約束,那麼所有詞的值就都很高,就沒有意義了。
明白了softmax只需要正確答案的概率,而其他值是作為懲罰項後,我們可以把正確詞作為一類,而隨機選k個其他值作為另一類,那麼就轉換為二分類問題,而且只需要計算k個值,而非所有詞的值:
NEG loss(或NCE loss)中表示把作為輸入RNN的二分類器:,輸出的概率值,所以loss第一項就是計算了正確答案的概率,讓其變高。
而第二項是隨機取k個其他詞作為負類,,作為懲罰項,要被分入這類的概率儘可能低。由此我們只需要計算k個值,而非整個詞庫|V|個值。
上述過程只要使用tensorflow的tf.nn.nce_loss()就可以直接實現。
樣例:
我們可以用語言模型來生成一本代數幾何書,只需要數據集是很多本代數幾何書的latex文本。(github項目)
如果數據集是C語言文本,那我們可以用來生成C語言代碼:
雖然這些都沒有實際的含義,但是至少看起像是代數幾何的用語或C語言代碼(至少它知道定理的proof常常讓你當練習做(笑)),說明RNN的語言模型能把握文本內在的語言結構(雖然無法把握數學或代碼含義)。
推薦閱讀:
※阿里知識圖譜首次曝光:每天千萬級攔截量,億級別全量智能審核
※通俗講解平方損失函數平方形式的數學解釋?
※智能時代的怪獸四:語言的運算(上)
※cs.CL weekly 2016.08.29-2016.09.02
※Word2Vec如何解決多義詞的問題?