溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

靜態(tài)RNN和動態(tài)RNN的區(qū)別是什么

發(fā)布時間:2022-05-07 15:28:14 來源:億速云 閱讀:231 作者:iii 欄目:大數(shù)據(jù)

這篇“靜態(tài)RNN和動態(tài)RNN的區(qū)別是什么”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“靜態(tài)RNN和動態(tài)RNN的區(qū)別是什么”文章吧。

1. 靜態(tài)RNN

函數(shù)static_rnn()函數(shù)通過連接記憶單元創(chuàng)建一個展開的RNN網(wǎng)絡(luò),下面的代碼創(chuàng)建了一個RNN網(wǎng)絡(luò),該網(wǎng)絡(luò)和上期中我們創(chuàng)建的是完全一樣的。

X0 = tf.placeholder(tf.float32, [None, n_inputs])
X1 = tf.placeholder(tf.float32, [None, n_inputs])
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
output_seqs, states = tf.contrib.rnn.static_rnn(
                       basic_cell, [X0, X1], dtype=tf.float32)
Y0, Y1 = output_seqs

首先,和之前一樣我們創(chuàng)建了兩個用來輸入數(shù)據(jù)的placeholder,接下來,我們創(chuàng)建了BasicRNNCell(可以把這個函數(shù)想象為一個創(chuàng)建記憶單元的一個工廠),用來構(gòu)建展開的RNN網(wǎng)絡(luò)。接下來調(diào)用static_rnn(),該函數(shù)輸入為創(chuàng)建好的cell,輸入的tensor以及tensor的類型。對于每一個輸入,static_rnn()調(diào)用記憶單元的__call__()函數(shù),創(chuàng)建兩個記憶單元的兩個copy,每一個copy中都包含著有5個循環(huán)神經(jīng)元的一層網(wǎng)絡(luò),并且有著共享變量和偏置項,和之前做的一樣,連在一起。
static_rnn()函數(shù)返回兩個對象,其中一個是一個list,該list包含每一個時刻所輸出的tensor,另一個對象是一個tensor包含著網(wǎng)絡(luò)的最終狀態(tài)。如果我們用最基本的記憶單元的話,那么最后狀態(tài)和輸出是一致的。
如果有50個時刻,那么這樣定義50個輸入的placeholder和50個輸出的tensor就會顯得比較麻煩。還有在執(zhí)行的時候,還得傳輸50個placeholder和50個輸出tensor,你說麻煩不麻煩?既然麻煩,那么就會有簡單的辦法,如下:

X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
X_seqs = tf.unstack(tf.transpose(X, perm=[1, 0, 2]))
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
output_seqs, states = tf.contrib.rnn.static_rnn(
                       basic_cell, X_seqs, dtype=tf.float32)
outputs = tf.transpose(tf.stack(output_seqs), perm=[1, 0, 2])

如上,這里我們只需要用1個placeholder就可以了,它的shape是[None, n_steps, n_inputs],其中第一維度None代表mini-batch的大小,第二個維度代表時間步長的個數(shù),也就是有多少個時刻。第三個維度為每個時刻的輸入大小。X_seqs是一個擁有n_steps個shape為[None, n_inputs]的tensor。為了轉(zhuǎn)換成這種形式,我們得先通過transpose()函數(shù),將前兩個維度互換一下,轉(zhuǎn)換之后時間步長就變成了第一個維度。然后我們可以通過unstack()函數(shù)根據(jù)第一個維度將它轉(zhuǎn)換成一個python列表的形式。接下來的兩行跟之前一樣,創(chuàng)建靜態(tài)RNN,最后我們通過stack()函數(shù)將所有的輸出tensor合并成一個tensor,最后交換輸出tensor的前兩個維度,轉(zhuǎn)換成[None, n_steps, n_inputs]形式。這樣的話,我們就可以通過傳輸一個包含mini-batch序列的tensor來運行網(wǎng)絡(luò)了。如下:

X_batch = np.array([
       # t = 0 t = 1
       [[0, 1, 2], [9, 8, 7]], # instance 0
       [[3, 4, 5], [0, 0, 0]], # instance 1
       [[6, 7, 8], [6, 5, 4]], # instance 2
       [[9, 0, 1], [3, 2, 1]], # instance 3
   ])
with tf.Session() as sess:
   init.run()
   outputs_val = outputs.eval(feed_dict={X: X_batch})

運行結(jié)束,我們得到一個tensor(outputs_val) 包含著每個樣本在每個時刻每個神經(jīng)元上的輸出情況。如下:

>>> print(outputs_val)
[[[-0.2964572 0.82874775 -0.34216955 -0.75720584 0.19011548]
 [ 0.51955646 1. 0.99999022 -0.99984968 -0.24616946]]
[[-0.12842922 0.99981797 0.84704727 -0.99570125 0.38665548]
[-0.70553327 -0.11918639 0.48885304 0.08917919 -0.26579669]]
[[ 0.04731077 0.99999976 0.99330056 -0.999933 0.55339795]
[-0.32477224 0.99996376 0.99933046 -0.99711186 0.10981458]]
[[ 0.70323634 0.99309105 0.99909431 -0.85363263 0.7472108 ]
[-0.43738723 0.91517633 0.97817528 -0.91763324 0.11047263]]]

然而,通過這種方法創(chuàng)建的圖會在每個時刻都創(chuàng)建一個單元,有50個時刻的話,看起來比較丑,有點像不用循環(huán)寫了50次。Y0=f(0, X0); Y1=f(Y0, X1); Y2=f(Y1, X2); ...; Y50=f(Y49,X50)。這么大的一張圖,一想就知道肯定會占用很大的內(nèi)存空間,特別是在反向傳播的時候,對于一個內(nèi)存受限的GPU,簡直就是要了老命。因為反向傳播的時候需要用所有前向傳播的權(quán)重值來計算梯度,這就不得不將前向傳播的值都存下來。那么對于有限的內(nèi)存來說,關(guān)機,洗洗睡吧。
兵來將擋水來土掩,幸運的是,我們可以用動態(tài)RNN來解決這個問題,那么什么是動態(tài)RNN呢?

2. 動態(tài)RNN

動態(tài)RNN的函數(shù)為dynamic_rnn(),這個函數(shù)內(nèi)部用了一個while_loop()的操作,它會根據(jù)有多少時刻來動態(tài)調(diào)整參數(shù)運行網(wǎng)絡(luò)。我們也可以通過設(shè)置swap_memory=True來避免在反向傳輸?shù)臅r候內(nèi)存耗盡。這個設(shè)置允許在反向傳輸?shù)臅r候?qū)PU內(nèi)存和GPU內(nèi)存互換。
很方便的,動態(tài)RNN對于所有的輸入也接收一個tensor,shape為[None, n_steps, n_inputs],并且和前面的一樣,輸出一個shape為[None, n_steps, n_inputs]的tensor。而且不用像前面一樣要通過unstack,stack,transpose等函數(shù)轉(zhuǎn)來轉(zhuǎn)去的。下面的代碼用dynamic_rnn()創(chuàng)建了和前面一樣的RNN。比較漂亮!

X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32)

以上就是關(guān)于“靜態(tài)RNN和動態(tài)RNN的區(qū)別是什么”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

rnn
AI