循環神經網絡RNN的簡單框架實現

循環神經網絡RNN結構與全連接或者卷積神經網絡結構相比,RNN比較複雜。通過閱讀各種資料,覺得《TensorFlow:實戰Google深度學習框架》中RNN講的最通俗易懂,在這裏將簡單的總結一下書上的內容。

循環神經網絡的主要用途是處理和預測序列數據,爲了刻畫一個序列當前的輸出與之前信息的關係。從網絡結構上看,RNN會利用之前的信息影響後面結點的輸出,也就是RNN的隱藏層之間的結點是有連接的,隱藏層的輸入不僅包含輸入層的輸入,還包含上一時刻隱藏層的輸出。
RNN結構
這張圖就是RNN循環體按時間展開後的結構。X爲網絡輸入,A爲隱藏層狀態,h爲輸出。在每一個時刻會有一個輸入Xl,然後RNN當前的狀態Al提供一個輸出。而當前狀態Al是根據上一時刻狀態Al-1和當前的輸入Xl共同決定的。
如何將狀態信息循環輸入神經網絡,這個循環結構被稱之爲循環體。下圖是一個使用最簡單的循環體結構的RNN,在這個循環體中只是用了一個類似全連接層的神經網絡結構。
循環體結構
循環神經網絡中的狀態是通過一個向量來存儲的,這個向量的維度也被稱爲RNN隱藏層的大小,設爲h。從圖中可以看出,循環體的輸入有兩個部分,一部分爲上一時刻的狀態,另一部分爲當前時刻的輸入樣本。對於語言模型來說,輸入樣例可以是當前單詞對應的單詞向量word embedding。
若輸入向量的維度爲x,則循環體的全連接層神經網絡的輸入大小爲h+x,也就是將上一時刻的狀態和輸入向量拼接起來。該循環體的輸出爲當前時刻的狀態,所以輸出層的大小也爲h,所以循環體中神經網絡的所有參數個數爲(h+x)*h(權重)+h(偏置)個。但是循環體輸出還作爲RNN的輸出,所以,循環體還需要另外一個全連接神經網絡來完成這個過程。下圖爲一個循環神經網絡前向傳播的全部過程。
過程圖
圖中輸入輸出的維度都是1,循環體中全連接層權重爲wrnn,偏置項爲brnn,用於RNN輸出的全連接層權重爲woutput,偏置項爲boutput。初始循環體狀態爲[0,0],因爲當前輸出爲1,所以拼接得到的向量爲[0,0,1],通過循環體中的全連接層神經網絡得到的結果爲:
結果
這一結果將作爲下一時刻的輸入狀態,同時循環體也會使用該狀態生成RNN的輸出,將該向量作爲輸入給用於輸出的全連接神經網絡可以得到當前時刻的最終輸出:
最終輸出
在得到循環神經網絡的前向傳播過程之後,可以和其他神經網絡類似地定義損失函數,唯一區別就在於RNN在每個時刻都有一個輸出,所以RNN的總損失爲所有(部分)時刻上的損失函數的總和。
下面代碼是用python簡單的實現了一個RNN的前向傳播過程,結合上面的過程圖能更好地理解。

import numpy as np

X = [1, 2]  # X爲輸入序列
state = [0.0, 0.0]  # 隱藏層初始值
# 循環體中的全連接層參數,分開定義不同輸入的權重
w_cell_state = np.asarray([[0.1, 0.2], [0.3, 0.4]])  # 隱藏層狀態state權重
w_cell_input = np.asarray([0.5, 0.6])  # 輸入序列進隱藏層所對應的權重
b_cell = np.asarray([0.1, -0.1])    # 偏置項

# 用於網絡輸出的全連接層參數
w_output = np.asarray([[1.0], [2.0]])
b_output = 0.1

# 按照輸入序列時間順序執行循環神經網絡的前向傳播過程
for i in range(len(X)):
    # 計算循環體中的全連接神經網絡, np.dot爲矩陣乘法
    before_activation = np.dot(state, w_cell_state) + X[i] * w_cell_input + b_cell
    # 當前的隱藏層狀態state
    state = np.tanh(before_activation)

    # 根據當前時刻狀態計算最終輸出
    final_output = np.dot(state, w_output) + b_output

    # 輸出每個時刻的信息
    print("before activation:", before_activation)
    print("state:", state)
    print("output", final_output)

輸出爲:

before activation: [0.6 0.5]
state: [0.53704957 0.46211716]
output [1.56128388]
before activation: [1.2923401  1.39225678]
state: [0.85973818 0.88366641]
output [2.72707101]

理論上RNN可以支持任意長度的序列,然而在實際中,如果序列過長會導致優化時出現梯度彌散的問題,所以實際中一般會規定一個最大長度。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章