您好,登錄后才能下訂單哦!
這篇“靜態RNN和動態RNN的區別是什么”文章的知識點大部分人都不太理解,所以小編給大家總結了以下內容,內容詳細,步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“靜態RNN和動態RNN的區別是什么”文章吧。
函數static_rnn()函數通過連接記憶單元創建一個展開的RNN網絡,下面的代碼創建了一個RNN網絡,該網絡和上期中我們創建的是完全一樣的。
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
首先,和之前一樣我們創建了兩個用來輸入數據的placeholder,接下來,我們創建了BasicRNNCell(可以把這個函數想象為一個創建記憶單元的一個工廠),用來構建展開的RNN網絡。接下來調用static_rnn(),該函數輸入為創建好的cell,輸入的tensor以及tensor的類型。對于每一個輸入,static_rnn()調用記憶單元的__call__()函數,創建兩個記憶單元的兩個copy,每一個copy中都包含著有5個循環神經元的一層網絡,并且有著共享變量和偏置項,和之前做的一樣,連在一起。
static_rnn()函數返回兩個對象,其中一個是一個list,該list包含每一個時刻所輸出的tensor,另一個對象是一個tensor包含著網絡的最終狀態。如果我們用最基本的記憶單元的話,那么最后狀態和輸出是一致的。
如果有50個時刻,那么這樣定義50個輸入的placeholder和50個輸出的tensor就會顯得比較麻煩。還有在執行的時候,還得傳輸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的大小,第二個維度代表時間步長的個數,也就是有多少個時刻。第三個維度為每個時刻的輸入大小。X_seqs是一個擁有n_steps個shape為[None, n_inputs]的tensor。為了轉換成這種形式,我們得先通過transpose()函數,將前兩個維度互換一下,轉換之后時間步長就變成了第一個維度。然后我們可以通過unstack()函數根據第一個維度將它轉換成一個python列表的形式。接下來的兩行跟之前一樣,創建靜態RNN,最后我們通過stack()函數將所有的輸出tensor合并成一個tensor,最后交換輸出tensor的前兩個維度,轉換成[None, n_steps, n_inputs]形式。這樣的話,我們就可以通過傳輸一個包含mini-batch序列的tensor來運行網絡了。如下:
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})
運行結束,我們得到一個tensor(outputs_val) 包含著每個樣本在每個時刻每個神經元上的輸出情況。如下:
>>> 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]]]
然而,通過這種方法創建的圖會在每個時刻都創建一個單元,有50個時刻的話,看起來比較丑,有點像不用循環寫了50次。Y0=f(0, X0); Y1=f(Y0, X1); Y2=f(Y1, X2); ...; Y50=f(Y49,X50)。這么大的一張圖,一想就知道肯定會占用很大的內存空間,特別是在反向傳播的時候,對于一個內存受限的GPU,簡直就是要了老命。因為反向傳播的時候需要用所有前向傳播的權重值來計算梯度,這就不得不將前向傳播的值都存下來。那么對于有限的內存來說,關機,洗洗睡吧。
兵來將擋水來土掩,幸運的是,我們可以用動態RNN來解決這個問題,那么什么是動態RNN呢?
動態RNN的函數為dynamic_rnn(),這個函數內部用了一個while_loop()的操作,它會根據有多少時刻來動態調整參數運行網絡。我們也可以通過設置swap_memory=True來避免在反向傳輸的時候內存耗盡。這個設置允許在反向傳輸的時候將CPU內存和GPU內存互換。
很方便的,動態RNN對于所有的輸入也接收一個tensor,shape為[None, n_steps, n_inputs],并且和前面的一樣,輸出一個shape為[None, n_steps, n_inputs]的tensor。而且不用像前面一樣要通過unstack,stack,transpose等函數轉來轉去的。下面的代碼用dynamic_rnn()創建了和前面一樣的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)
以上就是關于“靜態RNN和動態RNN的區別是什么”這篇文章的內容,相信大家都有了一定的了解,希望小編分享的內容對大家有幫助,若想了解更多相關的知識內容,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。