2017-03-04 114 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'循环。 –