所有人都能學會用Python寫出RNN-LSTM程式碼

發表於2017-03-27

概要

我通過玩具程式碼一邊學習一邊除錯能達到最好的學習效果。本文通過一個簡單的python實現,教會你迴圈神經網路。

原文作者@iamtrask說他會在twitter上繼續釋出第二部分LSTM,敬請關注。

廢話少說, 給我看看程式碼

執行時輸出

第一部分:什麼是神經元記憶

順著背出字母表,你很容易做到吧?

倒著背呢, 有點難哦。

試著想一首你記得的歌詞。為什麼順著回憶比倒著回憶難?你能直接跳到第二小節的中間麼?額, 好像有點難。 這是為什麼呢?

這其實很符合邏輯。 你記憶字母表或者歌詞並不是像計算機把資訊儲存在硬碟上那樣的(譯者注:計算機可以隨機訪問磁碟。)。你是順序記憶的。知道了前一個字母,你很容易知道下一個。這是一種條件記憶,只有你最近知道了前一個記憶,你才容易想起來下一個記憶,就想你熟悉的連結串列一樣。

但是,並不是說你不唱歌的時候,歌就不在你腦子裡了。而是說你如果想直接跳到中間那部分,你會發現很難直接找到其在腦中的呈現(也許是一堆神經元)。你想直接搜尋到一首歌的中間部分,這是很難的, 因為你以前沒有這樣做過,所以沒有索引可以指向歌曲的中間部分。 就好比你鄰居家有很多小路, 你從前門進去順著路走很容易找到後院,但是讓你直接到後院去就不太容易。想了解更過關於大腦的知識,請看這裡

跟連結串列很像,記憶這樣儲存很高效。我們可以發現這樣儲存在解決很多問題時候有優勢。

如果你的資料是一個序列,那麼記憶就很重要(意味著你必須記住某些東西)。看下面的視訊:

每一個資料點就是視訊中的一幀。如果你想訓練一個神經網路來預測下一幀小球的位置, 那麼知道上一幀小球的位置就很重要。這樣的序列資料就是我們需要構建迴圈神經網路的原因。那麼, 神經網路怎麼記住以前的資訊呢?

神經網路有隱藏層。一般而言,隱藏層的狀態由輸入決定。所以,一般而言神經網路的資訊流如下圖:

這很簡單直接。特定的輸入決定特定的隱藏層,特定的隱藏層又決定了輸出。這是一種封閉系統。記憶改變了這種狀況。記憶意味著,隱藏狀態是由當前時間點的輸入和上一個時間點的隱藏狀態決定的。

為什麼是隱藏層而不是輸入層呢?我們也可以這樣做呀:

現在,仔細想想,如果有四個時間點,如果我們採用隱藏層迴圈是如下圖:
hidden layer recurrence
如果採用輸入層迴圈會是:
input layer recurrence
看到區別沒,隱藏層記憶了之前所有的輸入資訊,而輸入層迴圈則只能利用到上一個輸入。舉個例子,假設一首歌詞裡面有”….I love you…”和”…I love carrots…”,如果採用輸入層迴圈,則沒法根據”I love”來預測下一個詞是什麼?因為當前輸入是love,前一個輸入是I,這兩種情況一致,所以沒法區分。 而隱藏層迴圈則可以記住更久之前的輸入資訊,因而能更好地預測下一個詞。理論上而言,隱藏層迴圈可以記住所有之前的輸入,當然記憶會隨著時間流逝逐漸忘卻。有興趣的可以看這篇blog

第二部分:RNN – 神經網路記憶

現在我們已經有了一些直觀認識, 接下來讓我們更進一步分析。正如在反向傳播這篇blog裡介紹的,神經網路的輸入層是由輸入資料集決定的。每一行輸入資料用來產生隱藏層(通過正向傳播)。每個隱藏層又用於產生輸出層(假設只有一層隱藏層)。如我們之前所說,記憶意味著隱藏層是由輸入資料和前一次的隱藏層組合而成。怎麼做的呢?很像神經網路裡面其他傳播的做法一樣, 通過矩陣!這個矩陣定義了當前隱藏層跟前一個隱藏層的關係。

rnn
這幅圖中很重要的一點是有三個權重矩陣。有兩個我們很熟悉了。SYNAPSE_0用於把輸入資料傳播到隱藏層。SYNAPSE_1把隱藏層傳播到輸出資料。新矩陣(SYNAPSE_h,用於迴圈)把當前的隱藏層(layer_1)傳播到下一個時間點的隱藏層(還是layer_1)。

forward
上面的gif圖展示了迴圈神經網路的神奇之處以及一些很重要的性質。它展示了四個時間點隱藏層的情況。第一個時間點,隱藏層僅由輸入資料決定。第二個時間點,隱藏層是由輸入資料和第一個時間點的隱藏層共同決定的。以此類推。你應該注意到了,第四個時間點的時候,網路已經“滿了”。所以大概第五個時間點來的時候,就要選擇哪些記憶保留,哪些記憶覆蓋。現實如此。這就是記憶“容量”的概念。如你所想,更大的隱藏層,就能記住更長時間的東西。同樣,這就需要神經網路學會忘記不相關的記憶然後記住重要的記憶。第三步有沒看出什麼重要資訊?為什麼綠色的要比其他顏色的多呢?

另外要注意的是隱藏層夾在輸入層和輸出層中間,所以輸出已經不僅僅取決於輸入了。輸入僅僅改變記憶,而輸出僅僅依賴於記憶。有趣的是,如果2,3,4時間節點沒有輸入資料的話,隱藏層同樣會隨著時間流逝而變化。

第三部分:基於時間的反向傳播

那麼迴圈神經網路是怎麼學習的呢?看看下面的圖。黑色表示預測結果,明黃色表示錯誤,褐黃色表示導數。
bp
網路通過從1到4的全部前向傳播(可以是任意長度的整個序列),然後再從4到1的反向傳播導數來學習。你可以把它看成一個有點變形的普通神經網路,除了我們在不同的地方共享權值(synapses 0,1,and h)。除了這點, 它就是一個普通的神經網路。

我們的玩具程式碼

來,我們用迴圈神經網路做個模型來實現二進位制加法。看到下面的圖沒,你猜猜頂上的彩色的1表示什麼意思呢?
toy code
方框裡的彩色的1表示進位。我們就要用迴圈神經網路來記住這個進位。求和的時候需要記住進位(如果不懂,可以看這裡)。

二進位制加法做法就是,從右往左,根據上面兩行的bit來預測第三行的bit為1還是0。我們想要神經網路遍歷整個二進位制序列記住是否有進位,以便能計算出正確的結果。不要太糾結這個問題本身,神經網路也不在乎這個問題。它在乎的只是每個時刻它會收到兩個輸入(0或者1),然後它會傳遞給用於記憶是否有進位的隱藏層。神經網路會把所有這些資訊(輸入和隱藏層的記憶)考慮進去,來對每一位(每個時間點)做出正確的預測。


下面原文裡面是針對每行程式碼做的註釋, 為了方便閱讀, 我直接把註釋寫到了程式碼裡面, 便於大家閱讀。

譯者注:RNN在自然語言處理裡面大量使用,包括機器翻譯,對話系統,機器做詩詞等,本文只是簡單介紹了一下原理。後續我會寫一些應用方面的文章,敬請期待。

相關文章