天天看點

零基礎入門深度學習(5) - 循環神經網絡

在前面的文章系列文章中,我們介紹了全連接配接神經網絡和卷積神經網絡,以及它們的訓練和使用。他們都隻能單獨的取處理一個個的輸入,前一個輸入和後一個輸入是完全沒有關系的。但是,某些任務需要能夠更好的處理序列的資訊,即前面的輸入和後面的輸入是有關系的。

比如,當我們在了解一句話意思時,孤立的了解這句話的每個詞是不夠的,我們需要處理這些詞連接配接起來的整個序列;當我們處理視訊的時候,我們也不能隻單獨的去分析每一幀,而要分析這些幀連接配接起來的整個序列。這時,就需要用到深度學習領域中另一類非常重要神經網絡:循環神經網絡(recurrent

neural network)。rnn種類很多,也比較繞腦子。

不過讀者不用擔心,本文将一如既往地對複雜的東西剝繭抽絲,幫助您了解rnn以及它的訓練算法,并動手實作一個循環神經網絡。

語言模型

rnn是在自然語言處理領域中最先被用起來的,比如,rnn可以為語言模型來模組化。那麼,什麼是語言模型呢?

我們可以和電腦玩一個遊戲,我們寫出一個句子前面的一些詞,然後,讓電腦幫我們寫下接下來的一個詞。比如下面這句:

我昨天上學遲到了,老師批評了____。

我們給電腦展示了這句話前面這些詞,然後,讓電腦寫下接下來的一個詞。在這個例子中,接下來的這個詞最有可能是『我』,而不太可能是『小明』,甚至是『吃飯』。

語言模型就是這樣的東西:給定一個一句話前面的部分,預測接下來最有可能的一個詞是什麼。

語言模型是對一種語言的特征進行模組化,它有很多很多用處。比如在語音轉文本(stt)的應用中,聲學模型輸出的結果,往往是若幹個可能的候選詞,這時候就需要語言模型來從這些候選詞中選擇一個最可能的。當然,它同樣也可以用在圖像到文本的識别中(ocr)。

使用rnn之前,語言模型主要是采用n-gram。n可以是一個自然數,比如2或者3。它的含義是,假設一個詞出現的機率隻與前面n個詞相關。我們以2-gram為例。首先,對前面的一句話進行切詞:

我 昨天 上學 遲到 了 ,老師 批評 了 ____。

如果用2-gram進行模組化,那麼電腦在預測的時候,隻會看到前面的『了』,然後,電腦會在語料庫中,搜尋『了』後面最可能的一個詞。不管最後電腦選的是不是『我』,我們都知道這個模型是不靠譜的,因為『了』前面說了那麼一大堆實際上是沒有用到的。如果是3-gram模型呢,會搜尋『批評了』後面最可能的詞,感覺上比2-gram靠譜了不少,但還是遠遠不夠的。因為這句話最關鍵的資訊『我』,遠在9個詞之前!

現在讀者可能會想,可以提升繼續提升n的值呀,比如4-gram、5-gram.......。實際上,這個想法是沒有實用性的。因為我們想處理任意長度的句子,n設為多少都不合适;另外,模型的大小和n的關系是指數級的,4-gram模型就會占用海量的存儲空間。

是以,該輪到rnn出場了,rnn理論上可以往前看(往後看)任意多個詞。

循環神經網絡是啥

循環神經網絡種類繁多,我們先從最簡單的基本循環神經網絡開始吧。

 基本循環神經網絡 

下圖是一個簡單的循環神經網絡如,它由輸入層、一個隐藏層和一個輸出層組成:

零基礎入門深度學習(5) - 循環神經網絡

納尼?!相信第一次看到這個玩意的讀者内心和我一樣是崩潰的。因為循環神經網絡實在是太難畫出來了,網上所有大神們都不得不用了這種抽象藝術手法。不過,靜下心來仔細看看的話,其實也是很好了解的。如果把上面有w的那個帶箭頭的圈去掉,它就變成了最普通的全連接配接神經網絡。

如果我們把上面的圖展開,循環神經網絡也可以畫成下面這個樣子:

零基礎入門深度學習(5) - 循環神經網絡

現在看上去就比較清楚了,這個網絡在t時刻接收到輸入之後,隐藏層的值是,輸出值是。關鍵一點是,的值不僅僅取決于,還取決于。我們可以用下面的公式來表示循環神經網絡的計算方法:

零基礎入門深度學習(5) - 循環神經網絡

式1是輸出層的計算公式,輸出層是一個全連接配接層,也就是它的每個節點都和隐藏層的每個節點相連。v是輸出層的權重矩陣,g是激活函數。式2是隐藏層的計算公式,它是循環層。u是輸入x的權重矩陣,w是上一次的值作為這一次的輸入的權重矩陣,f是激活函數。

從上面的公式我們可以看出,循環層和全連接配接層的差別就是循環層多了一個權重矩陣 w。

如果反複把式2帶入到式1,我們将得到:

零基礎入門深度學習(5) - 循環神經網絡

從上面可以看出,循環神經網絡的輸出值,是受前面曆次輸入值…….影響的,這就是為什麼循環神經網絡可以往前看任意多個輸入值的原因。

 雙向循環神經網絡 

對于語言模型來說,很多時候光看前面的詞是不夠的,比如下面這句話:

我的手機壞了,我打算____一部新手機。

可以想象,如果我們隻看橫線前面的詞,手機壞了,那麼我是打算修一修?換一部新的?還是大哭一場?這些都是無法确定的。但如果我們也看到了橫線後面的詞是『一部新手機』,那麼,橫線上的詞填『買』的機率就大得多了。

在上一小節中的基本循環神經網絡是無法對此進行模組化的,是以,我們需要雙向循環神經網絡,如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡

當遇到這種從未來穿越回來的場景時,難免處于懵逼的狀态。不過我們還是可以用屢試不爽的老辦法:先分析一個特殊場景,然後再總結一般規律。我們先考慮上圖中,y2的計算。

從上圖可以看出,雙向卷積神經網絡的隐藏層要儲存兩個值,一個a參與正向計算,另一個值a'參與反向計算。最終的輸出值y2取決于a2和a'2。其計算方法為:

零基礎入門深度學習(5) - 循環神經網絡

a2和a'2則分别計算:

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

從上面三個公式我們可以看到,正向計算和反向計算不共享權重,也就是說u和u'、w和w'、v和v'都是不同的權重矩陣。

 深度循環神經網絡 

前面我們介紹的循環神經網絡隻有一個隐藏層,我們當然也可以堆疊兩個以上的隐藏層,這樣就得到了深度循環神經網絡。如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

循環神經網絡的訓練

 循環神經網絡的訓練算法:bptt 

bptt算法是針對循環層的訓練算法,它的基本原理和bp算法是一樣的,也包含同樣的三個步驟:

前向計算每個神經元的輸出值;

反向計算每個神經元的誤差項值,它是誤差函數e對神經元j的權重輸入的偏導數;

 計算每個權重的梯度。

最後再用随機梯度下降算法更新權重。

循環層如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡

前向計算 

使用前面的式2對循環層進行前向計算:

零基礎入門深度學習(5) - 循環神經網絡

注意,上面的

零基礎入門深度學習(5) - 循環神經網絡

都是向量,用黑體字母表示;而u、v是矩陣,用大寫字母表示。向量的下标表示時刻,例如,表示在t時刻向量s的值。

我們假設輸入向量x的次元是m,輸出向量s的次元是n,則矩陣u的次元是,矩陣w的次元是。下面是上式展開成矩陣的樣子,看起來更直覺一些:

零基礎入門深度學習(5) - 循環神經網絡

在這裡我們用手寫體字母表示向量的一個元素,它的下标表示它是這個向量的第幾個元素,它的上标表示第幾個時刻。例如,表示向量s的第j個元素在t時刻的值。表示輸入層第i個神經元到循環層第j個神經元的權重。表示循環層第t-1時刻的第i個神經元到循環層第t個時刻的第j個神經元的權重。

誤差項的計算 

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

同理,上式第二項也是一個jacobian矩陣:

零基礎入門深度學習(5) - 循環神經網絡

其中,diag[a]表示根據向量a建立一個對角矩陣,即

零基礎入門深度學習(5) - 循環神經網絡

最後,将兩項合在一起,可得:

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

式3就是将誤差項沿時間反向傳播的算法。

零基礎入門深度學習(5) - 循環神經網絡

式4就是将誤差項傳遞到上一層算法。

權重梯度的計算 

現在,我們終于來到了bptt算法的最後一步:計算每個權重的梯度。

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

按照上面的規律就可以生成式5裡面的矩陣。

零基礎入門深度學習(5) - 循環神經網絡

式6就是計算循環層權重矩陣w的梯度的公式。

------數學公式超高能預警-----

前面已經介紹了的計算方法,看上去還是比較直覺的。然而,讀者也許會困惑,為什麼最終的梯度是各個時刻的梯度之和呢?我們前面隻是直接用了這個結論,實際上這裡面是有道理的,隻是這個數學推導比較繞腦子。感興趣的同學可以仔細閱讀接下來這一段,它用到了矩陣對矩陣求導、張量與向量相乘運算的一些法則。

我們還是從這個式子開始:

零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡
零基礎入門深度學習(5) - 循環神經網絡

接下來,我們計算式7加号右邊的部分:

零基礎入門深度學習(5) - 循環神經網絡

于是,我們得到了如下遞推公式:

零基礎入門深度學習(5) - 循環神經網絡

------數學公式超高能預警解除-----

權重矩陣u的計算方法和全連接配接神經網絡的計算方法完全一樣,這裡就不再贅述了。感興趣的讀者可以看後面的代碼實作。

 rnn的梯度爆炸和消失問題 

不幸的是,實踐中前面介紹的幾種rnns并不能很好的處理較長的序列。一個主要的原因是,rnn在訓練中很容易發生梯度爆炸和梯度消失,這導緻訓練時梯度不能在較長序列中一直傳遞下去,進而使rnn無法捕捉到長距離的影響。

為什麼rnn會産生梯度爆炸和消失問題呢?我們接下來将詳細分析一下原因。我們根據式3可得:

零基礎入門深度學習(5) - 循環神經網絡

上式的定義為矩陣的模的上界。因為上式是一個幂函數,如果t-k很大的話(也就是向前看很遠的時候),會導緻對應的誤差項的值增長或縮小的非常快,這樣就會導緻相應的梯度爆炸和梯度消失問題(取決于大于1還是小于1)。

通常來說,梯度爆炸更容易處理一些。因為梯度爆炸的時候,我們的程式會收到nan錯誤。我們也可以設定一個梯度門檻值,當梯度超過這個門檻值的時候可以直接截取。

梯度消失更難檢測,而且也更難處理一些。總的來說,我們有三種方法應對梯度消失問題:

合理的初始化權重值。初始化權重,使每個神經元盡可能不要取極大或極小值,以躲開梯度消失的區域。

使用其他結構的rnns,比如長短時記憶網絡(ltsm)和gated recurrent unit(gru),這是最流行的做法。我們将在以後的文章中介紹這兩種網絡。

rnn的應用舉例——基于rnn的語言模型

現在,我們介紹一下基于rnn語言模型。我們首先把詞依次輸入到循環神經網絡中,每輸入一個詞,循環神經網絡就輸出截止到目前為止,下一個最可能的詞。例如,當我們依次輸入:

我 昨天 上學 遲到 了

神經網絡的輸出如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡

其中,s和e是兩個特殊的詞,分别表示一個序列的開始和結束。

 向量化 

我們知道,神經網絡的輸入和輸出都是向量,為了讓語言模型能夠被神經網絡處理,我們必須把詞表達為向量的形式,這樣神經網絡才能處理它。

神經網絡的輸入是詞,我們可以用下面的步驟對輸入進行向量化:

建立一個包含所有詞的詞典,每個詞在詞典裡面有一個唯一的編号。

任意一個詞都可以用一個n維的one-hot向量來表示。其中,n是詞典中包含的詞的個數。假設一個詞在詞典中的編号是i,v是表示這個詞的向量,是向量的第j個元素,則:

零基礎入門深度學習(5) - 循環神經網絡

上面這個公式的含義,可以用下面的圖來直覺的表示:

零基礎入門深度學習(5) - 循環神經網絡

使用這種向量化方法,我們就得到了一個高維、稀疏的向量(稀疏是指絕大部分元素的值都是0)。處理這樣的向量會導緻我們的神經網絡有很多的參數,帶來龐大的計算量。是以,往往會需要使用一些降維方法,将高維的稀疏向量轉變為低維的稠密向量。不過這個話題我們就不再這篇文章中讨論了。

語言模型要求的輸出是下一個最可能的詞,我們可以讓循環神經網絡計算計算詞典中每個詞是下一個詞的機率,這樣,機率最大的詞就是下一個最可能的詞。是以,神經網絡的輸出向量也是一個n維向量,向量中的每個元素對應着詞典中相應的詞是下一個詞的機率。如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡

 softmax層 

前面提到,語言模型是對下一個詞出現的機率進行模組化。那麼,怎樣讓神經網絡輸出機率呢?方法就是用softmax層作為神經網絡的輸出層。

我們先來看一下softmax函數的定義:

零基礎入門深度學習(5) - 循環神經網絡

這個公式看起來可能很暈,我們舉一個例子。softmax層如下圖所示:

零基礎入門深度學習(5) - 循環神經網絡

從上圖我們可以看到,softmax layer的輸入是一個向量,輸出也是一個向量,兩個向量的次元是一樣的(在這個例子裡面是4)。輸入向量x=[1 2 3 4]經過softmax層之後,經過上面的softmax函數計算,轉變為輸出向量y=[0.03 0.09 0.24 0.64]。計算過程為:

零基礎入門深度學習(5) - 循環神經網絡

我們來看看輸出向量y的特征:

每一項為取值為0-1之間的正數;

所有項的總和是1。

我們不難發現,這些特征和機率的特征是一樣的,是以我們可以把它們看做是機率。對于語言模型來說,我們可以認為模型預測下一個詞是詞典中第一個詞的機率是0.03,是詞典中第二個詞的機率是0.09,以此類推。

 語言模型的訓練

可以使用監督學習的方法對語言模型進行訓練,首先,需要準備訓練資料集。接下來,我們介紹怎樣把語料:

轉換成語言模型的訓練資料集。

首先,我們擷取輸入-标簽對:

零基礎入門深度學習(5) - 循環神經網絡

然後,使用前面介紹過的向量化方法,對輸入x和标簽y進行向量化。這裡面有意思的是,對标簽y進行向量化,其結果也是一個one-hot向量。例如,我們對标簽『我』進行向量化,得到的向量中,隻有第2019個元素的值是1,其他位置的元素的值都是0。它的含義就是下一個詞是『我』的機率是1,是其它詞的機率都是0。

最後,我們使用交叉熵誤差函數作為優化目标,對模型進行優化。

在實際工程中,我們可以使用大量的語料來對模型進行訓練,擷取訓練資料和訓練的方法都是相同的。

 交叉熵誤差 

一般來說,當神經網絡的輸出層是softmax層時,對應的誤差函數e通常選擇交叉熵誤差函數,其定義如下:

零基礎入門深度學習(5) - 循環神經網絡

在上式中,n是訓練樣本的個數,向量是樣本的标記,向量是網絡的輸出。标記是一個one-hot向量,例如,如果網絡的輸出,那麼,交叉熵誤差是(假設隻有一個訓練樣本,即n=1):

零基礎入門深度學習(5) - 循環神經網絡

我們當然可以選擇其他函數作為我們的誤差函數,比如最小平方誤差函數(mse)。不過對機率進行模組化時,選擇交叉熵誤差函數更make sense。具體原因,感興趣的讀者請閱讀參考文獻7。

rnn的實作

我們用recurrentlayer類來實作一個循環層。下面的代碼是初始化一個循環層,可以在構造函數中設定卷積層的超參數。我們注意到,循環層有兩個權重數組,u和w。

在forward方法中,實作循環層的前向計算,這部分比較簡單。

在backword方法中,實作bptt算法。

有意思的是,bptt算法雖然數學推導的過程很麻煩,但是寫成代碼卻并不複雜。

在update方法中,實作梯度下降算法。

上面的代碼不包含權重u的更新。這部分實際上和全連接配接神經網絡是一樣的,留給感興趣的讀者自己來完成吧。

循環層是一個帶狀态的層,每次forword都會改變循環層的内部狀态,這給梯度檢查帶來了麻煩。是以,我們需要一個reset_state方法,來重置循環層的内部狀态。

最後,是梯度檢查的代碼。

需要注意,每次計算error之前,都要調用reset_state方法重置循環層的内部狀态。下面是梯度檢查的結果,沒問題!

零基礎入門深度學習(5) - 循環神經網絡

小結

至此,我們講完了基本的循環神經網絡、它的訓練算法:bptt,以及在語言模型上的應用。rnn比較燒腦,相信拿下前幾篇文章的讀者們搞定這篇文章也不在話下吧!然而,循環神經網絡這個話題并沒有完結。我們在前面說到過,基本的循環神經網絡存在梯度爆炸和梯度消失問題,并不能真正的處理好長距離的依賴(雖然有一些技巧可以減輕這些問題)。

事實上,真正得到廣泛的應用的是循環神經網絡的一個變體:長短時記憶網絡。它内部有一些特殊的結構,可以很好的處理長距離的依賴,我們将在下一篇文章中詳細的介紹它。現在,讓我們稍事休息,準備挑戰更為燒腦的長短時記憶網絡吧。

原文位址:https://zybuluo.com/hanbingtao/note/541458

繼續閱讀