2016-12-21 83 views
1

我正在嘗試tensorflow RNN的一個非常簡單的例子。 在那個例子中,我使用動態rnn。代碼如下:張量流動的動態張量形狀RNN

data = tf.placeholder(tf.float32, [None, 10,1]) #Number of examples, number of input, dimension of each input 
target = tf.placeholder(tf.float32, [None, 11]) 
num_hidden = 24 
cell = tf.nn.rnn_cell.LSTMCell(num_hidden,state_is_tuple=True) 
val, _ = tf.nn.dynamic_rnn(cell, data, dtype=tf.float32) 
val = tf.transpose(val, [1, 0, 2]) 
last = tf.gather(val, int(val.get_shape()[0]) - 1) 
weight = tf.Variable(tf.truncated_normal([num_hidden, int(target.get_shape()[1])])) 
bias = tf.Variable(tf.constant(0.1, shape=[target.get_shape()[1]])) 
prediction = tf.nn.softmax(tf.matmul(last, weight) + bias) 
cross_entropy = -tf.reduce_sum(target * tf.log(tf.clip_by_value(prediction,1e-10,1.0))) 
optimizer = tf.train.AdamOptimizer() 
minimize = optimizer.minimize(cross_entropy) 
mistakes = tf.not_equal(tf.argmax(target, 1), tf.argmax(prediction, 1)) 
error = tf.reduce_mean(tf.cast(mistakes, tf.float32)) 

實際上,代碼取自這個tutorial。 該RNN網絡的輸入是一串二進制數字。每個數字都被放入一個數組中。例如,一個序列的格式如下:
[[1],[0],[0],[1],[1],[0],[1],[1],[1],[0]] 輸入的形狀是[None,10,1],它們分別是批量大小,序列大小和嵌入大小。現在,因爲動態RNN能接受可變輸入的形狀,我更改代碼如下:

data = tf.placeholder(tf.float32, [None, None,1]) 

基本上,我想使用可變長度序列(在同一批次的所有序列的過程相同的長度,但之間不同批)。然而,它拋出的錯誤:

Traceback (most recent call last): 
    File "rnn-lstm-variable-length.py", line 48, in <module> 
    last = tf.gather(val, int(val.get_shape()[0]) - 1) 
TypeError: __int__ returned non-int (type NoneType) 

據我所知,第二個維度是None,不能在get_shape()[0]使用。但是,我相信一定有辦法解決這個問題,因爲RNN一般接受可變的長度輸入。 我該怎麼辦?

+0

簽出此[博客](https://danijar.com/variable-sequence-lengths-in-tensorflow/)帖子。 – TheM00s3

+0

你確定它們是正確的嗎?他們使用'sequence = tf.placeholder(tf.float32,[None,max_length,frame_size])',這意味着序列長度是固定的。 – lenhhoxung

+1

出於某種原因,我有印象的東西實際上不是動態的長度,而是填充。 –

回答

0

tf.gather預計張量,因此您可以使用tf.shape(val)來獲得在運行時計算的張量,形狀爲val - 例如, tf.gather(val, tf.shape(val)[0] - 1)

3

tl; dr:嘗試使用tf.batch(..., dynamic_pad=True)批量處理您的數據。


@chris_anderson的評論是正確的。最終,你的網絡需要數字與合作的密集矩陣,有一對夫婦的戰略,以可變長度的數據轉換成hyperrectangles:

  1. 墊所有批次到一個固定大小(例如假設的說,500個項目的最大長度每個輸入和每批次的每個項目填充到500)。這一戰略沒有任何動態。
  2. 將批次填充應用於批次中最長項目的長度(動態填充)。
  3. 根據長度分塊輸入並應用每批次填充。這與#2相同,但整體填充較少。

還有other strategies也可以使用。

爲此批處理,您可以使用:

  1. tf.train.batch - 默認情況下,它確實沒有填充,你需要自己實現它。
  2. tf.train.batch(..., dynamic_pad=True)
  3. tf.contrib.training.bucket_by_sequence_length

我懷疑你還通過使用tf.nn.dynamic_rnn混淆。需要注意的是dynamic_rnn中的dynamic指的是TensorFlow展開網絡循環部分的方式。在tf.nn.rnn中,循環在圖中靜態完成(沒有內部循環,它在圖構建時展開)。然而,在dynamic_rnn中,TensorFlow使用tf.while_loop在運行時在圖內進行迭代。要使用動態填充,您需要使用動態展開,但不會自動執行。

+1

我的問題是不同的。實際上,批次中的每個項目都具有相同的序列長度。但是,這個長度是未知的,並且在不同批次間是不同的。因此,我無法分配輸入數據佔位符的形狀。如果在後面的'tf.gather(val,int(val.get_shape()[0]) - 1)'中使用[batch_size,None,None],則會拋出錯誤TypeError:__int__返回非int類型)' – lenhhoxung

+1

哦,對了,'tf.gather'無論如何都期望一個張量,所以你可以使用'tf.shape(val)'來得到一個在運行時計算的'val'形狀的張量 - 例如'tf.gather(val,tf.shape(val)[0] - 1)'。 –

+0

正確,我試過了,它正常。如果您通過此評論替換答案,我會接受它。非常感謝。 – lenhhoxung