簡體   English   中英

如何在張量流中反饋RNN輸出到輸入

[英]How to feed back RNN output to input in tensorflow

如果假設我有一個訓練有素的RNN(例如語言模型),並且我想看看它自己會產生什么, 我應該如何將其輸出反饋給它的輸入?

我閱讀了以下相關問題:

理論上我很清楚,在tensorflow中我們使用截斷的反向傳播,所以我們必須定義我們想要“追蹤”的最大步驟。 我們還為批量保留了一個維度,因此如果我想訓練一個正弦波,我必須輸入[None, num_step, 1]輸入。

以下代碼有效:

tf.reset_default_graph()
n_samples=100

state_size=5

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(state_size, forget_bias=1.)
def_x = np.sin(np.linspace(0, 10, n_samples))[None, :, None]
zero_x = np.zeros(n_samples)[None, :, None]
X = tf.placeholder_with_default(zero_x, [None, n_samples, 1])
output, last_states = tf.nn.dynamic_rnn(inputs=X, cell=lstm_cell, dtype=tf.float64)

pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)

Y = np.roll(def_x, 1)
loss = tf.reduce_sum(tf.pow(pred-Y, 2))/(2*n_samples)


opt = tf.train.AdamOptimizer().minimize(loss)
sess = tf.InteractiveSession()
tf.global_variables_initializer().run()

# Initial state run
plt.show(plt.plot(output.eval()[0]))
plt.plot(def_x.squeeze())
plt.show(plt.plot(pred.eval().squeeze()))

steps = 1001
for i in range(steps):
    p, l, _= sess.run([pred, loss, opt])

LSTM的狀態大小可以變化,我也嘗試將正弦波饋入網絡和零,並且在兩種情況下它都在~500次迭代中收斂。 到目前為止,我已經了解到,在這種情況下,圖表包含n_samples共享其參數的LSTM單元格數量,我只能將輸入作為時間序列提供給它。 但是,在生成樣本時,網絡明確取決於其先前的輸出 - 這意味着我無法立即提供展開的模型。 我嘗試在每一步計算狀態和輸出:

with tf.variable_scope('sine', reuse=True):
    X_test = tf.placeholder(tf.float64)
    X_reshaped = tf.reshape(X_test, [1, -1, 1])
    output, last_states = tf.nn.dynamic_rnn(lstm_cell, X_reshaped, dtype=tf.float64)
    pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)


    test_vals = [0.]
    for i in range(1000):
        val = pred.eval({X_test:np.array(test_vals)[None, :, None]})
        test_vals.append(val)

然而,在該模型中,似乎LSTM細胞之間沒有連續性。 這里發生了什么?

我是否必須使用100個時間步驟初始化零數組,並將每個運行的結果分配給數組? 就像喂網絡一樣:

運行0: input_feed = [0, 0, 0 ... 0]; res1 = result input_feed = [0, 0, 0 ... 0]; res1 = result

運行1: input_feed = [res1, 0, 0 ... 0]; res2 = result input_feed = [res1, 0, 0 ... 0]; res2 = result

運行1: input_feed = [res1, res2, 0 ... 0]; res3 = result input_feed = [res1, res2, 0 ... 0]; res3 = result

等等...

如果我想使用這個訓練有素的網絡在下一個時間步驟中使用自己的輸出作為輸入,該怎么辦?

如果我理解正確,你想找到一種方法來輸出時間步t的輸出作為時間步t+1輸入,對吧? 為此,您可以在測試時使用相對簡單的工作:

  1. 確保輸入占位符可以接受動態序列長度,即時間維度的大小為None
  2. 確保您使用的是tf.nn.dynamic_rnn (您在發布的示例中執行此操作)。
  3. 將初始狀態傳遞給dynamic_rnn
  4. 然后,在測試時,您可以遍歷序列並單獨為每個時間步進給(即最大序列長度為1)。 此外,您只需要繼承RNN的內部狀態。 請參閱下面的偽代碼(變量名稱引用您的代碼段)。

即,將模型的定義更改為以下內容:

lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(state_size, forget_bias=1.)
X = tf.placeholder_with_default(zero_x, [None, None, 1])  # [batch_size, seq_length, dimension of input]
batch_size = tf.shape(self.input_)[0]
initial_state = lstm_cell.zero_state(batch_size, dtype=tf.float32)
def_x = np.sin(np.linspace(0, 10, n_samples))[None, :, None]
zero_x = np.zeros(n_samples)[None, :, None]
output, last_states = tf.nn.dynamic_rnn(inputs=X, cell=lstm_cell, dtype=tf.float64,
    initial_state=initial_state)
pred = tf.contrib.layers.fully_connected(output, 1, activation_fn=tf.tanh)

然后你可以這樣執行推理:

fetches = {'final_state': last_state,
           'prediction': pred}

toy_initial_input = np.array([[[1]]])  # put suitable data here
seq_length = 20  # put whatever is reasonable here for you

# get the output for the first time step
feed_dict = {X: toy_initial_input}
eval_out = sess.run(fetches, feed_dict)
outputs = [eval_out['prediction']]
next_state = eval_out['final_state']

for i in range(1, seq_length):
    feed_dict = {X: outputs[-1],
                 initial_state: next_state}
    eval_out = sess.run(fetches, feed_dict)
    outputs.append(eval_out['prediction'])
    next_state = eval_out['final_state']

# outputs now contains the sequence you want

請注意,這也適用於批次,但如果您在同一批次中使用不同長度的序列,則可能會更復雜一些。

如果您不僅要在測試時進行此類預測,還要在訓練時進行此類預測,也可以這樣做,但實現起來要復雜一些。

您可以使用自己的輸出(最后一個狀態)作為下一步輸入(初始狀態)。 一種方法是:

  1. 在每個時間步使用零初始化變量作為輸入狀態
  2. 每次完成截斷序列並獲得一些輸出狀態時,請使用剛剛獲得的輸出狀態更新狀態變量。

第二個可以通過以下任一方式完成:

  1. 將狀態提取到python並在下次將它們反饋回來,就像在tensorflow / models中的ptb示例中所做的那樣
  2. 在圖中構建更新操作並添加依賴關系,如在tensorpack中的ptb示例中所做的那樣

我知道我有點遲到了,但我認為這個要點可能有用:

https://gist.github.com/CharlieCodex/f494b27698157ec9a802bc231d8dcf31

它允許您通過過濾器自動輸入輸入並作為輸入返回到網絡。 要使形狀匹配,可以將processing設置為tf.layers.Dense圖層。

請問任何問題!

編輯:

在您的特定情況下,創建一個lambda,它將dynamic_rnn輸出處理到您的字符向量空間中。 例如:

# if you have:
W = tf.Variable( ... )
B = tf.Variable( ... )
Yo, Ho = tf.nn.dynamic_rnn( cell , inputs , state )
logits = tf.matmul(W, Yo) + B
 ...
# use self_feeding_rnn as
process_yo = lambda Yo: tf.matmul(W, Yo) + B
Yo, Ho = self_feeding_rnn( cell, seed, initial_state, processing=process_yo)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM