2017-03-04 83 views
3

我有以下兩個張量(注意,他們是Tensorflow張量,這意味着他們仍然當時我構建了以下切片運算實際上象徵我發動tf.Session()前):通過索引張量Tensorflow切片張量

  • params:具有形狀(64,784,256)
  • indices:具有形狀(64,784)

,我想構建一個返回以下張量運算:

  • output:具有形狀(64,784),其中

output[i,j] = params_tensor[i,j, indices[i,j] ]

什麼是Tensorflow最有效的方式這樣做?

ps:我試過tf.gather,但無法利用它來執行上面描述的操作。

非常感謝。
-Bests

回答

5

你可以得到正是你想要使用tf.gather_nd什麼。最終的表達是:

tf.gather_nd(params, tf.stack([tf.tile(tf.expand_dims(tf.range(tf.shape(indices)[0]), 1), [1, tf.shape(indices)[1]]), tf.transpose(tf.tile(tf.expand_dims(tf.range(tf.shape(indices)[1]), 1), [1, tf.shape(indices)[0]])), indices], 2)) 

這個表達瞭如下解釋:

  • tf.gather_nd做你所期望的,並使用該指數從PARAMS
  • tf.stack聯合收集輸出三個單獨的張量,其中最後一個是指數。前兩個張量指定前兩個維度(參數/索引的軸0和軸1)的排序

    • 對於所提供的示例,該排序簡單地爲0,1,2,...,63軸0和0,1,2,... 783。這些序列分別用tf.range(tf.shape(indices)[0])tf.range(tf.shape(indices)[1])獲得。
    • 對於所提供的示例,索引具有形狀(64,784)。從上述需要的最後一個點的另外兩個張量,以具有此相同的形狀,以便與tf.stack

      • 首先,一個額外的維度/軸被添加到每個使用tf.expand_dims兩個序列的組合。
      • tf.tiletf.transpose的使用可以通過示例來顯示:假設參數和索引的前兩個軸具有形狀(5,3)。我們希望第一張是:

        [[0, 0, 0], [1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]] 
        

        我們希望第二張是:

        [[0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2], [0, 1, 2]] 
        

        這兩個張量差不多的功能就像在網格中指定的座標爲相關指數。

  • tf.stack最後一部分結合了新的第三軸這三個張量,以使結果具有相同的3個軸作爲PARAMS。


請記住,如果你有比這個問題或多或少軸,需要相應修改tf.stack座標確定張量的數量。

+0

謝謝。這就是我想要的 –

+0

對於我來說,將參數平滑爲(-1,256)和索引爲(-1)似乎更容易些,使用gather_nd然後解開平鋪,而不是平鋪 – Maxim

+0

geez。這真的很聰明,也@ @ @ $。煙霧從我頭上讀出來。它也很有用!謝謝。爲我節省了很多時間。 – thang

1

你想要的就像是一個自定義的減少功能。如果要保持像最大值的指數indices話,我會建議使用tf.reduce_max

max_params = tf.reduce_max(params_tensor, reduction_indices=[2]) 

否則,這裏是讓你想要什麼(張量對象是不可轉讓的,所以我們創建的二維表的一種方式張量和它使用tf.pack)包裝:

import tensorflow as tf 
import numpy as np 
with tf.Graph().as_default(): 

    params_tensor = tf.pack(np.random.randint(1,256, [5,5,10]).astype(np.int32)) 

    indices = tf.pack(np.random.randint(1,10,[5,5]).astype(np.int32)) 

    output = [ [None for j in range(params_tensor.get_shape()[1])] for i in range(params_tensor.get_shape()[0])] 
    for i in range(params_tensor.get_shape()[0]): 
     for j in range(params_tensor.get_shape()[1]): 
      output[i][j] = params_tensor[i,j,indices[i,j]] 
    output = tf.pack(output) 

    with tf.Session() as sess: 
     params_tensor,indices,output = sess.run([params_tensor,indices,output]) 

     print params_tensor 
     print indices 
     print output 
+1

感謝您使用'tf.pack'(這是tf 1.0中的'tf.stack')的解決方法。是的,如果tensorflow有一些像'tf.custom_reduce'這樣的內置函數,它可以通過另一個索引張量來選擇一個張量,那很好。 –

+0

但我想要的是一種更加有效的方法(切片),它不涉及'for'循環。 –