閱讀708 返回首頁    go 阿裏雲 go 技術社區[雲棲]


零基礎入門深度學習(五):長短時記憶網絡

在上一篇文章《零基礎入門深度學習(4):循環神經網絡》中,我們介紹了循環神經網絡以及它的訓練算法。我們也介紹了循環神經網絡很難訓練的原因,這導致了它在實際應用中,很難處理長距離的依賴。在本文中,我們將介紹一種改進之後的循環神經網絡:長短時記憶網絡(Long Short Term Memory Network, LSTM),它成功地解決了原始循環神經網絡的缺陷,成為當前最流行的RNN,在語音識別、圖片描述、自然語言處理等許多領域中成功應用。

 

但不幸的一麵是,LSTM的結構很複雜,因此,我們需要花上一些力氣,才能把LSTM以及它的訓練算法弄明白。在搞清楚LSTM之後,我們再介紹一種LSTM的變體:GRU (Gated Recurrent Unit)。 它的結構比LSTM簡單,而效果卻和LSTM一樣好,因此,它正在逐漸流行起來。最後,我們仍然會動手實現一個LSTM。

 

長短時記憶網絡是啥

 

我們首先了解一下長短時記憶網絡產生的背景。回顧一下中推導的,誤差項沿時間反向傳播的公式:

 

20170120102242174.jpg

 

0?wx_fmt=png

 

梯度消失到底意味著什麼?在《零基礎入門深度學習(4):循環神經網絡》中我們已證明,權重數組W最終的梯度是各個時刻的梯度之和,即:

 

20170120102327200.jpg

 

假設某輪訓練中,各時刻的梯度以及最終的梯度之和如下圖:

 

20170120102336905.jpg

 

我們就可以看到,從上圖的t-3時刻開始,梯度已經幾乎減少到0了。那麼,從這個時刻開始再往之前走,得到的梯度(幾乎為零)就不會對最終的梯度值有任何貢獻,這就相當於無論t-3時刻之前的網絡狀態h是什麼,在訓練中都不會對權重數組W的更新產生影響,也就是網絡事實上已經忽略了t-3時刻之前的狀態。這就是原始RNN無法處理長距離依賴的原因。

 

既然找到了問題的原因,那麼我們就能解決它。從問題的定位到解決,科學家們大概花了7、8年時間。終於有一天,Hochreiter和Schmidhuber兩位科學家發明出長短時記憶網絡,一舉解決這個問題。

 

其實,長短時記憶網絡的思路比較簡單。原始RNN的隱藏層隻有一個狀態,即h,它對於短期的輸入非常敏感。那麼,假如我們再增加一個狀態,即c,讓它來保存長期的狀態,那麼問題不就解決了麼?如下圖所示:

 

20170120102344746.jpg

 

新增加的狀態c,稱為單元狀態(cell state)。我們把上圖按照時間維度展開:

 

20170120102350844.jpg

 

20170120102404680.jpg

 

LSTM的關鍵,就是怎樣控製長期狀態c。在這裏,LSTM的思路是使用三個控製開關。第一個開關,負責控製繼續保存長期狀態c;第二個開關,負責控製把即時狀態輸入到長期狀態c;第三個開關,負責控製是否把長期狀態c作為當前的LSTM的輸出。三個開關的作用如下圖所示:

 

20170120102357570.jpg

 

接下來,我們要描述一下,輸出h和單元狀態c的具體計算方法。

 

長短時記憶網絡的前向計算

 

前麵描述的開關是怎樣在算法中實現的呢?這就用到了門(gate)的概念。門實際上就是一層全連接層,它的輸入是一個向量,輸出是一個0到1之間的實數向量。假設W是門的權重向量,是偏置項,那麼門可以表示為:

 

20170120102412924.jpg
 

我們先來看一下遺忘門:

 

20170120102418755.jpg

 

下圖顯示了遺忘門的計算:

 

20170120102431365.jpg

 

接下來看看輸入門:

 

0?wx_fmt=png

 

上式中,Wi是輸入門的權重矩陣,bi是輸入門的偏置項。下圖表示了輸入門的計算:

 

20170120102437154.jpg

 

20170120102452944.jpg

 

20170120102459680.jpg

 

20170120102507486.jpg

 

20170120102514987.jpg

 

20170120102522758.jpg

 

下圖表示輸出門的計算:

 

20170120102529274.jpg

 

LSTM最終的輸出,是由輸出門和單元狀態共同確定的:

 

20170120102538213.jpg

 

下圖表示LSTM最終輸出的計算:

 

20170120102545569.jpg

 

式1到式6就是LSTM前向計算的全部公式。至此,我們就把LSTM前向計算講完了。

 

長短時記憶網絡的訓練

 

熟悉我們這個係列文章的同學都清楚,訓練部分往往比前向計算部分複雜多了。LSTM的前向計算都這麼複雜,那麼,可想而知,它的訓練算法一定是非常非常複雜的。現在隻有做幾次深唿吸,再一頭紮進公式海洋吧。

 

LSTM訓練算法框架

 

LSTM的訓練算法仍然是反向傳播算法,對於這個算法,我們已經非常熟悉了。主要有下麵三個步驟:

 

20170120102553471.jpg
 

關於公式和符號的說明

 

首先,我們對推導中用到的一些公式、符號做一下必要的說明。

 

接下來的推導中,我們設定gate的激活函數為sigmoid函數,輸出的激活函數為tanh函數。他們的導數分別為:

 

20170120102631891.jpg

 

從上麵可以看出,sigmoid和tanh函數的導數都是原函數的函數。這樣,我們一旦計算原函數的值,就可以用它來計算出導數的值。

 

20170120102640446.jpg
 

20170120102648726.jpg

 

20170120102654306.jpg

 

誤差項沿時間的反向傳遞

 

20170120102702390.jpg

 

下麵,我們要把式7中的每個偏導數都求出來。根據式6,我們可以求出:

 

20170120102711267.jpg

 

根據式4,我們可以求出:

 

20170120102719263.jpg

 

因為:

 

20170120102726803.jpg

 

我們很容易得出:

 

20170120102733104.jpg

 

將上述偏導數帶入到式7,我們得到:

 

20170120102740383.jpg
 

式8到式12就是將誤差沿時間反向傳播一個時刻的公式。有了它,我們可以寫出將誤差項向前傳遞到任意k時刻的公式:

 

20170120102749273.jpg

 

將誤差項傳遞到上一層

 

我們假設當前為第l層,定義l-1層的誤差項是誤差函數對l-1層加權輸入的導數,即:

 

20170120102755660.jpg
 

20170120102801836.jpg

 

式14就是將誤差傳遞到上一層的公式。

 

權重梯度的計算

 

對於20170120102811591.jpg的權重梯度,我們知道它的梯度是各個時刻梯度之和(證明過程請參考文章),我們首先求出它們在t時刻的梯度,然後再求出他們最終的梯度。

 

我們已經求得了誤差項20170120102820595.jpg,很容易求出t時刻的20170120102828248.jpg

 

20170120102836552.jpg

 

將各個時刻的梯度加在一起,就能得到最終的梯度:

 

20170120102845627.jpg

 

對於偏置項20170120102855503.jpg的梯度,也是將各個時刻的梯度加在一起。下麵是各個時刻的偏置項梯度:

 

20170120102903516.jpg

 

下麵是最終的偏置項梯度,即將各個時刻的偏置項梯度加在一起:

 

20170120102912856.jpg

 

對於20170120102920732.jpg的權重梯度,隻需要根據相應的誤差項直接計算即可:

 

20170120104010449.jpg

 

以上就是LSTM的訓練算法的全部公式。因為這裏麵存在很多重複的模式,仔細看看,會發覺並不是太複雜。

 

當然,LSTM存在著相當多的變體,讀者可以在互聯網上找到很多資料。因為大家已經熟悉了基本LSTM的算法,因此理解這些變體比較容易,因此本文就不再贅述了。

 

長短時記憶網絡的實現

 

在下麵的實現中,LSTMLayer的參數包括輸入維度、輸出維度、隱藏層維度,單元狀態維度等於隱藏層維度。gate的激活函數為sigmoid函數,輸出的激活函數為tanh。

 

激活函數的實現

 

我們先實現兩個激活函數:sigmoid和tanh。

 

20170120102952564.jpg

 

LSTM初始化

 

和前兩篇文章代碼架構一樣,我們把LSTM的實現放在LstmLayer類中。

 

根據LSTM前向計算和方向傳播算法,我們需要初始化一係列矩陣和向量。這些矩陣和向量有兩類用途,一類是用於保存模型參數,例如20170120103003581.jpg;另一類是保存各種中間計算結果,以便於反向傳播算法使用,它們包括20170120103011454.jpg,以及各個權重對應的梯度。

 

在構造函數的初始化中,隻初始化了與forward計算相關的變量,與backward相關的變量沒有初始化。這是因為構造LSTM對象的時候,我們還不知道它未來是用於訓練(既有forward又有backward)還是推理(隻有forward)。

 

20170120103024683.jpg

 

20170120103033604.jpg
 

前向計算的實現

 

forward方法實現了LSTM的前向計算:

 

20170120103044166.jpg
 

從上麵的代碼我們可以看到,門的計算都是相同的算法,而門和的計算僅僅是激活函數不同。因此我們提出了calc_gate方法,這樣減少了很多重複代碼。

 

反向傳播算法的實現

 

backward方法實現了LSTM的反向傳播算法。需要注意的是,與backword相關的內部狀態變量是在調用backward方法之後才初始化的。這種延遲初始化的一個好處是,如果LSTM隻是用來推理,那麼就不需要初始化這些變量,節省了很多內存。

 

20170120103052855.jpg

 

算法主要分成兩個部分,一部分使計算誤差項:

 

20170120103101795.jpg

20170120103111822.jpg

 

另一部分是計算梯度:

 

20170120103121702.jpg

20170120103130106.jpg

 

梯度下降算法的實現

 

下麵是用梯度下降算法來更新權重:

 20170120103142948.jpg
 

梯度檢查的實現

 

和RecurrentLayer一樣,為了支持梯度檢查,我們需要支持重置內部狀態:

 

20170120103150104.jpg

  

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

 

20170120103159657.jpg

20170120103206294.jpg

 

我們隻對做了檢查,讀者可以自行增加對其他梯度的檢查。下麵是某次梯度檢查的結果:

 

20170120103214868.jpg

 

GRU

 

前麵我們講了一種普通的LSTM,事實上LSTM存在很多變體,許多論文中的LSTM都或多或少的不太一樣。在眾多的LSTM變體中,GRU (Gated Recurrent Unit)也許是最成功的一種。它對LSTM做了很多簡化,同時卻保持著和LSTM相同的效果。因此,GRU最近變得越來越流行。

 

GRU對LSTM做了兩個大改動:

 

  1. 將輸入門、遺忘門、輸出門變為兩個門:更新門(Update Gate)Zt和重置門(Reset Gate)rt。

  2. 將單元狀態與輸出合並為一個狀態:h。

 

GRU的前向計算公式為:

 

20170120103225750.jpg

 

下圖是GRU的示意圖:

 

20170120103232406.jpg

 

GRU的訓練算法比LSTM簡單一些,留給讀者自行推導,本文就不再贅述了。

 

小結

 

至此,LSTM——也許是結構最複雜的一類神經網絡——就講完了,相信拿下前幾篇文章的讀者們搞定這篇文章也不在話下吧!現在我們已經了解循環神經網絡和它最流行的變體——LSTM,它們都可以用來處理序列。但是,有時候僅僅擁有處理序列的能力還不夠,還需要處理比序列更為複雜的結構(比如樹結構),這時候就需要用到另外一類網絡:遞歸神經網絡(Recursive Neural Network),巧合的是,它的縮寫也是RNN。

原文發布時間為:2011-01-20

本文來自雲棲社區合作夥伴DBAplus

最後更新:2017-05-15 17:33:45

  上一篇:go  營銷型網站與響應式網站的區別是什麼
  下一篇:go  互聯網企業安全高級指南3.7.4 SDL在互聯網企業的發展