遞迴神經網路 RNN 簡介

2021-07-22 10:22:52 字數 4346 閱讀 6573

首先有請讀者看看我們的遞迴神經網路的容貌:

乍一看,好複雜的大傢伙,沒事,老樣子,看我如何慢慢將其拆解,正所謂見招拆招,我們來各個擊破。

上圖左側是遞迴神經網路的原始結構,如果先拋棄中間那個令人生畏的閉環,那其實就是簡單」輸入層=>隱藏層=>輸出層」的三層結構,我們在多層感知器的介紹中已經非常熟悉,然而多了乙個非常陌生的閉環,也就是說輸入到隱藏層之後,隱藏層還會給自己也來一發,環環相扣,暈亂複雜。

我們知道,一旦有了環,就會陷入「先有蛋還是先有雞」的邏輯困境,為了跳出困境我們必須人為定義乙個起始點,按照一定的時間序列規定好計算順序,做到有條不紊,於是實際上我們會將這樣帶環的結構展開成乙個序列網路,也就是上圖右側被「unfold」之後的結構。先別急著能理解rnn,我們來點輕鬆的,先介紹這樣的序列化網路結構包含的引數記號:

上一小節我們簡單了解了網路的結構,並介紹了其中一些記號,是時候介紹它具體的運作過程了。首先在t=

0 的時刻,u,

v,w 都被隨機初始化好,h0

通常初始化為0,然後進行如下計算: s

1=ux

1+wh

0h1=

f(s1

)o1=

g(vh

1)這樣時間就向前推進,此時的狀態h1

作為時刻0的記憶狀態將參與下一次的**活動,也就是s2

=ux1

+wh1

h2=f

(s2)

o2=g

(vh2

) ,以此類推st

=uxt

+wht

−1ht

=f(u

xt+w

ht−1

)ot=

g(vh

t)其中

f 可以是ta

nh,r

elu,

logi

stic

任君選擇,

g 通常是so

ftma

x 也可以是其他,也是隨君所欲。

值得注意的是,我們說遞迴神經網路擁有記憶能力,而這種能力就是通過

w 將以往的輸入狀態進行總結,而作為下次輸入的輔助。可以這樣理解隱藏狀態:h=

f(現有

的輸入+

過去記憶

總結)

上一小節我們說到了rnn如何做序列化**,也就是如何一步步**出o0

,o1,

....

ot−1

,ot,

ot+1

....

. ,接下來我們來了解網路的知識u,

v,w 是如何煉成的。

其實沒有多大新意,我們還是利用在之前講解多層感知器和卷積神經網路用到的backpropagation方法。也就是將輸出層的誤差co

st,求解各個權重的梯度∇u

,∇v,

∇w,然後利用梯度下降法更新各個權重。現在問題就是如何求解各個權重的梯度,其它的所有東西都在之前介紹中談到了,所有的trick都可以復用。

由於是序列化**,那麼對於每一時刻

t ,網路的輸出ot

都會產生一定誤差et

e=∑t

et,我們的目標就是要求取 ∇

u=∂e

∂u=∑

t∂et

∂u∇v

=∂e∂

v=∑t

∂et∂

v∇w=

∂e∂w

=∑t∂

et∂w

我們知道輸出ot

=g(v

st) ,對於任意的co

st函式,求取∇v

將是簡單的,我們可以直接求取每個時刻的∂e

t∂v ,由於它不存在和之前的狀態依賴,可以直接求導取得,然後簡單地求和即可。我們重點關注∇w

,∇u 的計算。

回憶之前我們介紹

多層感知器的backprop演算法,我們知道演算法的trick是定義乙個δ=

∂e∂s

,首先計算出輸出層的δl

,再向後傳播到各層δl

−1,δ

l−2,

....

,那麼如何計算

δ 呢?先看下圖:

之前我們推導過,只要關注當前層次發射出去的鏈結即可,也就是δh

t=(v

tδot

+wtδ

ht+1

).∗f

′(st

) 只要計算出所有的δo

t,δh

t ,就可以通過以下計算出∇w

,∇u :

∇w=∑

tδht

×ht∇

u=∑t

δht×

xt其中

× 表示兩個向量的外積。這樣看來,只要你熟悉mlp的backprop演算法,rnn寫起程式來和mlp根本沒有多大差異!手寫*****的demo至少比cnn容易很多。

雖然上一節中,我們強調了rnn的訓練程式和mlp沒太大差異,雖然寫程式容易,但是訓練起來卻是千難萬阻。為什麼呢?因為我們的網路是根據輸入而展開的,輸入越長,展開的網路越深,那麼對於「深度」網路訓練有什麼困難呢?最常見的是「gradient explode」和「gradient vanish」。這種問題在rnn中如何體現呢?為了強調這個問題,我們模仿yoshua bengio的**《on the difficulty of training recurrent neural networks》的推導,重寫一下rnn的梯度求解過程,為了推導方便,我們人為地為w,

u 打上標籤wt

,ut ,即認為當確定好時間長度

t ,rnn就變成普通的mlp。打上標籤後的rnn變成如下:

假如對於時刻t+

1 產生的誤差et

+1,我們想計算它對於w1

,w2,

....

,wt,

wt+1

的梯度,可以如下計算: ∂

et+1

∂wt+

1=∂e

t+1∂

ht+1

∂ht+

1∂wt

+1

∂et+

1∂wt

=∂et

+1∂h

t+1∂

ht+1

∂ht∂

ht∂w

t ∂

et+1

∂wt−

1=∂e

t+1∂

ht+1

∂ht+

1∂ht

∂ht∂

ht−1

∂ht−

1∂wt

−1

....

..

反覆運用鏈式法則,我們可以求出每乙個∇w

1,∇w

2,..

..,∇

wt,∇

wt+1

,需要注意的是,實際rnn模型對於w,

u 都是不打標籤的,也就是在不同時刻都是共享同樣的引數,這樣可以大大減少訓練引數,和cnn的共享權重類似。對於共享引數的rnn,我們只需將上述的一系列式子抹去標籤並求和,就可以得到yoshua bengio**中所推導的梯度計算式子: ∂e

t∂w=

∑1≤k

≤t∂e

t∂ht

∏kt∂hi

∂hi−

1∂+h

k∂w

其中∂+

hk∂w

代表不利用鏈式法則直接求導,也就是假如對於函式f(

h(x)

) ,對其直接求導結果如下:∂f

(h(x

))∂x

=f′(

h(x)

) 也就是將h(

x)看成常數了。網上許多rnn教程都用yoshua bengio類似的推導,卻省略了這個小步驟,使得初學者常常搞得暈頭轉向,摸不著頭腦。**中證明了:||

∏kt∂hi

∂hi−

1||≤

ηt−k

從而說明了這是梯度求導的一部分環節是乙個指數模型,當

η<

1 時,就會出現」gradient vanish」問題,而當

η>

1 時,「gradient explode」也就產生了。為了克服這樣的問題,lstm和gru模型便後續被推出了。有趣的是,正是因為訓練深度網路的困難,才導致神經網路這種古老模型沉寂了幾十年,不過現在硬體的發展,訓練資料的增多,神經網路重新得以復甦,並以重新以深度學習的外號殺出江湖。

遞迴神經網路RNN

import tensorflow as tf from tensorflow.examples.tutorials.mnist import input data 載入資料 mnist input data.read data sets mnist data one hot true 輸入是28 ...

遞迴神經網路RNN

import tensorflow as tf from tensorflow.examples.tutorials.mnist import input data in 2 載入資料集 mnist input data.read data sets mnist data one hot true ...

RNN 迴圈神經網路or遞迴神經網路?

我 內心os 有嗎,我感覺我看到的都是迴圈神經網路啊?我 這個應該就是翻譯的問題吧 回去以後我查了一下,發現我錯了,迴圈神經網路和遞迴神經網路還是有點區別的。很明顯,它倆名字就是不一樣的,迴圈神經網路是recurrent neural network,遞迴神經網路是recursive neural ...