針對初學者的循環神經網絡介紹 [復制鏈接]

2019-8-19 10:38
EmailLi 閱讀:137 評論:0 贊:0
Tag:  神經網絡

簡單介紹什么是RNN,它們如何運行,以及如何用Python從頭構建一個RNN。

循環神經網絡(RNN)是一種專門處理序列的神經網絡。它們通常用于自然語言處理(NLP)任務,因為它們在處理文本方面非常有效。在本文中,我們將探索什么是RNN,了解它們是如何工作的,并使用Python從頭構建一個真正的RNN(僅使用numpy庫)。

這篇文章假設你有神經網絡的基本知識。我對神經網絡的介紹涵蓋了你需要知道的一切,所以我建議你先讀一下(https://victorzhou.com/blog/intro-to-neural-networks/ )。

我們開始吧!

1、為什么有用

標準神經網絡(以及CNN)的一個問題是,它們只能處理預先確定的大小: 它們接受固定大小的輸入并產生固定大小的輸出。RNN是有用的,因為它允許我們使用可變長度的序列作為輸入和輸出。下面是一些RNN的例子:

針對初學者的循環神經網絡介紹

輸入為紅色,RNN本身為綠色,輸出為藍色。來源:Andrej Karpathy

這種處理序列的能力使RNN非常有用。例如:

  • 機器翻譯(比如谷歌翻譯)是通過“多對多”RNN完成的。原始文本序列被輸入一個RNN,然后該RNN會生成翻譯文本作為輸出。
  • 情感分析 (例如,這是一個積極的還是消極的評論?)通常是通過“多對一” 的RNN完成的。要分析的文本被輸入一個RNN,然后該RNN會生成一個單獨的輸出分類(例如,這是一個積極的評論)。

在本文的后面,我們將從頭構建一個“多對一”的RNN來執行基本的情感分析。

2、工作原理

我們假設有一個帶有輸入x0,x1,...xn的“多對多”的RNN,我們希望它產生輸出y0,y1,...yn。這些xi 和yi是向量,可以有任意的維數。

RNN利用以任意給定的步長t反復地更新一個隱藏狀態h來運行,h是一個向量,也可以有任意的維數。

  1. 下一個隱藏狀態ht是使用前一個隱藏狀態ht -1和下一個輸入xt進行計算的。
  2. 下一個輸出yt是使用ht進行計算的。
針對初學者的循環神經網絡介紹

一個多對多RNN

這就是使RNN循環的東西: 它對每個步驟使用相同的權重。具體來說,一個典型的標準RNN只使用3組權重來進行計算:

  • Wxh, 用于所有的 xt → ht 連接。
  • Whh, 用于所有的 ht-1 → ht 連接。
  • Why, 用于所有的 ht → yt 連接。

我們也對我們的RNN使用兩個偏差:

  • bh,計算ht時加上。
  • by, 計算yt時加上。

我們用矩陣表示權重,用向量表示偏差。這3個權重和2個偏差就構成了整個RNN!

下面是把所有東西放在一起的方程式:

針對初學者的循環神經網絡介紹

不要略過這些方程。停下來,盯著這個方程看一分鐘。另外,記住權重是矩陣,其它變量是向量。

所有的權重都使用矩陣乘法進行應用,并將偏差加到結果乘積中。然后,我們使用tanh作為第一個方程的激活函數(其它激活函數像sigmoid也可以使用)。

不知道什么是激活函數?請認真閱讀我之前提到的神經網絡介紹。

3、要解決的問題

我們來動手干吧!我們將從頭實現一個RNN來執行一個簡單的情感分析任務: 確定給定的文本字符串是積極的還是消極的。

下面是我為本文收集的小數據集中的一些例子:

針對初學者的循環神經網絡介紹

4. 計劃

由于這是一個分類問題,我們將使用“多對一" RNN。這與我們前面討論的“多對多”RNN類似,只不過它只使用最終的隱藏狀態來產生一個輸出y:

針對初學者的循環神經網絡介紹

一個多對一RNN

每個xi都是一個向量,表示文本中的一個單詞。輸出y將是一個包含兩個數字的向量,一個表示積極的,另一個表示消極的。我們將使用Softmax將這些值轉換為概率,并最終在積極的/消極的之間進行決定。

我們來開始構建我們的RNN!

5. 預處理

我前面提到的數據集由兩個Python字典組成:

針對初學者的循環神經網絡介紹

True=積極的,False=消極的

我們必須做一些預處理才能把數據轉換成可用的格式。首先,我們將構造一個包含我們數據中所有單詞的詞匯表:

針對初學者的循環神經網絡介紹

vocab現在包含了至少在一個訓練文本中出現的所有單詞的列表。接下來,我們將分配一個整數索引來表示vocab中的每個單詞。

針對初學者的循環神經網絡介紹

我們現在可以用對應的整數索引表示任意給定的單詞!這是必要的,因為RNN不能理解單詞——我們必須給它們提供數字。

最后,回想一下RNN的每個輸入xi都是一個向量。我們將使用one-hot向量,它除了包含一個1之外,其余值都是0。每個one-hot向量中的“1”將位于這個單詞對應的整數索引處。

由于我們的詞匯表中有18個唯一的單詞,每個xi將是一個18維的one-hot向量。

針對初學者的循環神經網絡介紹

稍后,我們將使用createInputs()來創建向量輸入,并將其傳入我們的RNN。

6. 正向階段

是時候開始實現我們的RNN了!我們將從初始化我們的RNN所需要的3個權重和2個偏差開始:

針對初學者的循環神經網絡介紹

注意:我們除以1000是為了減小權重的初始方差。這并不是初始化權重的最佳方法,但它很簡單,適合本文。

我們使用np.random.randn()從標準正態分布來初始化我們的權重。

接下來,我們來實現RNN的正向傳遞。還記得我們之前看到的這兩個方程嗎?

針對初學者的循環神經網絡介紹

下面是這些同樣的方程被寫入代碼中的形式:

針對初學者的循環神經網絡介紹

很簡單,對吧?注意,我們在第一步中將h初始化為零向量,因為此時沒有可以供我們使用的前一個h。

讓我們來試試:

針對初學者的循環神經網絡介紹

如果你需要復習一下Softmax,請閱讀我對Softmax的簡要說明。

我們的RNN可以運行,但還不是很有用。我們來改變這一點……

7. 逆向階段

為了訓練我們的RNN,我們首先需要一個損失函數。我們將使用交叉熵損失函數,它通常與Softmax配對使用。我們是這樣計算它的:

針對初學者的循環神經網絡介紹

其中pc 是我們的RNN對正確類(積極的或消極的)的預測概率。例如,如果一個積極的文本被我們的RNN預測為90%的積極度,則損失為:

針對初學者的循環神經網絡介紹

現在我們有了一個損失,我們將使用梯度下降訓練我們的RNN來最小化損失。這意味著是時候推導一些梯度了!

??以下部分假設你有多變量微積分的基本知識。如果你愿意,你可以跳過它,但我建議即使你不太明白也要略讀一下。我們將在推導結果時逐步編寫代碼,即使表面的理解也會有所幫助。

如果你想了解這部分的額外背景知識,我建議你先閱讀我的《神經網絡介紹》中的《訓練神經網絡》部分。此外,這篇文章的所有代碼都在Github上,所以如果你愿意,你可以follow它。

準備好了嗎?我們開始吧。

7.1 定義

首先,我們來看一些定義:

  • 讓 y代表來自我們RNN的原始輸出。
  • 讓p代表最終的概率:p=softmax(y).
  • 讓c 指代一個特定文本例子的真實標簽,也可以說是“正確的”類。
  • 讓L代表交叉熵損失:L=-ln(pc)
  • 讓Wxh 、Whh 和Why代表我們的RNN中的3個權重矩陣。
  • 讓bh和by 代表我們的RNN中的兩個偏差向量。

7.2設置

接下來,我們需要編輯正向階段來緩存一些數據,以便在反向階段中使用。在此過程中,我們還將為反向階段設置骨架。它是這樣的:

針對初學者的循環神經網絡介紹

想知道我們為什么要進行緩存嗎?請閱讀我在我的CNN介紹的訓練概述中的說明。我在其中做了同樣的事情。

7.3梯度

是用到數學的時候了!我們從計算?L/?y開始。我們知道:

針對初學者的循環神經網絡介紹

我將把使用鏈式法則推導?L/?y的過程留給你,但是推導出來的結果是漂亮的:

針對初學者的循環神經網絡介紹

例如,如果我們有p = [0.2, 0.2, 0.6],并且其正確的類是c=0,那么我們就會得到 ?L/?y=[?0.8,0.2,0.6] 。這轉換稱代碼也是很容易的:

針對初學者的循環神經網絡介紹

漂亮!下一步,我們來為Why和by嘗試一下梯度,它們的梯度只用與將最終的隱藏狀態轉換為RNN的輸出。我們有:

針對初學者的循環神經網絡介紹

式中,hn是最終的隱藏狀態,因此,

針對初學者的循環神經網絡介紹

類似地,

針對初學者的循環神經網絡介紹

現在,我們可以開始實現 backprop()!

針對初學者的循環神經網絡介紹

提醒: 我們之前在forward()中創建了self.last_hs。

最后,我們需要Whh 、Wxh 和bh的權重,它們將在RNN中的每一步使用。我們有:

針對初學者的循環神經網絡介紹

因為改變Wxh會影響每一個ht ,而每一個ht都會影響y,并最終影響L。為了完全計算Wxh的梯度,我們需要反向傳播所有的步長,這也被稱為隨時間反向傳播(BPTT):

針對初學者的循環神經網絡介紹

隨時間進行的反向傳播

Wxh被用于所有的xt —> ht 正向連接,因此我們必須反向傳播回這些連接的每一個。

一旦我們到達了一個給定的步長t,我們需要計算?ht/?Wxh

針對初學者的循環神經網絡介紹

tanh的推導是眾所周知的:

針對初學者的循環神經網絡介紹

我們和平常一樣使用鏈式法則:

針對初學者的循環神經網絡介紹

類似地,

針對初學者的循環神經網絡介紹

我們需要的最后一個東西是?y/?ht,我們可以遞歸地計算它:

針對初學者的循環神經網絡介紹

我們將從最后的隱藏狀態開始,并逆向運行來實現BPTT,這樣當我們想要計算?y/?ht+1的時候我們就已經有了?y/?ht!最后的隱藏狀態hn是一個例外:

針對初學者的循環神經網絡介紹

現在我們有了最終實現BPTT和完成backprop()所需要的所有東西:

針對初學者的循環神經網絡介紹

針對初學者的循環神經網絡介紹

一些需要注意的東西:

  • 為了方便起見,我們已經將(?L/?y)*(?y/?h)合并到 ?L/?h中了。
  • 我們需要不斷地更新一個保存最近的?L/?ht+1值的變量d_h,我們計算?L/?ht需要用到這個值。
  • 在完成BPTT之后,我們使用np.clip()截取小于-1或大于1的梯度值。這有助于緩解梯度爆炸問題,這是因為有很多相乘項時,梯度就會變的非常大。對于普通的RNN來說,梯度爆炸或梯度消失是很有問題的——像LSTM這樣更復雜的RNN通常能夠很好地處理它們。
  • 一旦所有的梯度被計算出,我們就使用梯度下降來更新權重和偏差。

我們做到了!我們的RNN是完整的。

8. 高潮

終于到了我們一直等待的時刻——我們來測試我們的RNN!

首先,我們將編寫一個輔助函數來使用我們的RNN處理數據:

針對初學者的循環神經網絡介紹

現在,我們可以編寫訓練循環:

針對初學者的循環神經網絡介紹

運行main.py應該會輸出如下內容:

針對初學者的循環神經網絡介紹

從結果來看我們自己建立的RNN還不錯。

想自己嘗試或修改這段代碼嗎?請在瀏覽器中運行這個RNN(https://repl.it/@vzhou842/A-RNN-from-scratch)。你也可以在Github上找到它。(https://github.com/vzhou842/rnn-from-scratch)

9. 結尾

就是這樣!在這篇文章中,我們完成了一個循環神經網絡的一個演示,包括它們是什么,它們是如何工作的,它們為什么有用,如何訓練它們,以及如何實現一個。雖然如此,你還有很多事情可以做:

  • 學習長短期記憶網絡,一個更強大更流行的RNN架構,或者學習門控循環單元(GRU),一個著名的LSTM變體。
  • 使用合適的ML庫(比如Tensorflow、 Keras或 PyTorch)對更大/更好的RNN進行實驗。
  • 閱讀關于雙向RNN的內容。它會正向和反向處理序列,因此,有更多的信息對于輸出層來說是可用的。
  • 嘗試詞嵌入(比如 GloVe 或 Word2Vec),你可以使用它們將單詞轉換成更有用的向量表示形式。
  • 嘗試自然語言工具集(NLTK),一個流行的處理人類語言數據的Python庫。

我來說兩句
您需要登錄后才可以評論 登錄 | 立即注冊
facelist
所有評論(0)
領先的中文移動開發者社區
18620764416
7*24全天服務
意見反饋:[email protected]

掃一掃關注我們

Powered by Discuz! X3.2© 2001-2019 Comsenz Inc.( 粵ICP備15117877號 )

两码中特期期