轉自:http://blog.csdn.net/wuzqchom/article/details/75453327
使用tensorflow.nn.bidirectional_dynamic_rnn()這個函數,就可以很方便的實現雙向LSTM,很簡潔。
首先來看一下,函數:
def bidirectional_dynamic_rnn( cell_fw, # 前向RNN cell_bw, # 后向RNN inputs, # 輸入 sequence_length=None,# 輸入序列的實際長度(可選,默認為輸入序列的最大長度) initial_state_fw=None, # 前向的初始化狀態(可選) initial_state_bw=None, # 后向的初始化狀態(可選) dtype=None, # 初始化和輸出的數據類型(可選) parallel_iterations=None, swap_memory=False, time_major=False, # 決定了輸入輸出tensor的格式:如果為true, 向量的形狀必須為 `[max_time, batch_size, depth]`. # 如果為false, tensor的形狀必須為`[batch_size, max_time, depth]`. scope=None ) 返回值: 一個(outputs, output_states)的元組 其中, 1. outputs為(output_fw, output_bw),是一個包含前向cell輸出tensor和后向cell輸出tensor組成的元組。假設 time_major=false,tensor的shape為[batch_size, max_time, depth]。實驗中使用tf.concat(outputs, 2)將其拼接。 2. output_states為(output_state_fw, output_state_bw),包含了前向和后向最后的隱藏狀態的組成的元組。 output_state_fw和output_state_bw的類型為LSTMStateTuple。 LSTMStateTuple由(c,h)組成,分別代表memory cell和hidden state。
而cell_fw和cell_bw的定義是完全一樣的。如果這兩個cell選LSTM cell整個結構就是雙向LSTM了。
# lstm模型 正方向傳播的RNN lstm_fw_cell = tf.nn.rnn_cell.BasicLSTMCell(embedding_size, forget_bias=1.0) # 反方向傳播的RNN lstm_bw_cell = tf.nn.rnn_cell.BasicLSTMCell(embedding_size, forget_bias=1.0)
但是看來看去,輸入兩個cell都是相同的啊?
其實在bidirectional_dynamic_rnn函數的內部,會把反向傳播的cell使用array_ops.reverse_sequence的函數將輸入的序列逆序排列,使其可以達到反向傳播的效果。
在實現的時候,我們是需要傳入兩個cell作為參數就可以了:
(outputs, output_states) = tf.nn.bidirectional_dynamic_rnn(lstm_fw_cell, lstm_bw_cell, embedded_chars, dtype=tf.float32)
embedded_chars為輸入的tensor,[batch_szie, max_time, depth]。batch_size為模型當中batch的大小,應用在文本中時,max_time可以為句子的長度(一般以最長的句子為准,短句需要做padding),depth為輸入句子詞向量的維度。
當然你也可以使用循環的方式,時長為句子的長度,每一次都以上一時刻(假設一詞為句子的基本單位的話,即上一個詞)的隱藏狀態和當前時刻的tensor為輸入,但是這樣寫的時候相對會比較麻煩,若使用bidirectional_dynamic_rnn()則會清爽很多。
本篇僅僅是在應用接口層面介紹了bidirectional_dynamic_rnn,內部實現並沒有做過多的探討,dynamic_rnn()函數也有一些工程上的優化,比如加入buckets機制。
具體解釋見知乎問題:tensorflow中的seq2seq例子為什么需要bucket?賈楊清的回答。
另外關於dynamic_rnn和普通的rnn區別可見另外一個
知乎問題: tensor flow dynamic_rnn 與rnn有啥區別?