2017-03-04 7 views
3

Ich habe zwei folgende Tensoren (beachten Sie, dass sie beideTensorflow Tensoren sind, was bedeutet, sie zu der Zeit noch praktisch symbolisch ich folgenden Slicing op konstruieren, bevor ich ein tf.Session() starten):einen Tensor durch einen Index-Tensor in Tensorflow Slicing

  • params: hat Form (64,784, 256)
  • indices: hat Form (64, 784)

und ich möchte ein op konstruieren, die die folgende Tensor zurückgibt:

  • output: hat Form (64,784), wo

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

Was die effizienteste Art und Weise in Tensorflow ist, dies zu tun ?

ps: Ich versuchte mit tf.gather, konnte aber nicht davon Gebrauch machen, um den oben beschriebenen Vorgang durchzuführen.

Vielen Dank.
-Bests

Antwort

5

Sie können genau das bekommen, was Sie mit tf.gather_nd wollen. Der letzte Ausdruck ist:

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)) 

Dieser Ausdruck hat die folgende Erklärung:

  • tf.gather_nd tut, was Sie erwartet, und verwendet die Indizes die Ausgabe der params
  • tf.stack Mähdreschern zu sammeln drei separate Tensoren, von denen der letzte die Indizes ist. Die ersten beiden Tensoren der Ordnung der ersten zwei Dimensionen spezifizieren (Achse 0 und Achse 1 von params/Indices)

    • Für das Beispiel vorgesehen ist, ist diese Anordnung einfach 0, 1, 2, ..., 63 für Achse 0 und 0, 1, 2, ... 783 für Achse 1. Diese Sequenzen werden mit tf.range(tf.shape(indices)[0]) bzw. tf.range(tf.shape(indices)[1]) erhalten.
    • Für das angegebene Beispiel hat Indizes die Form (64, 784).Die anderen beiden Tensoren aus dem letzten Punkt über Notwendigkeit, diese gleiche Form haben, um zu mit tf.stack

      • zuerst kombiniert zu werden, wird eine zusätzliche Dimension/Achse wird an jede der zwei Sequenzen unter Verwendung tf.expand_dims zugegeben.
      • Die Verwendung von tf.tile und tf.transpose kann am Beispiel gezeigt werden: Angenommen, die ersten beiden Achsen von Parametern und Index haben Form (5,3). Wir wollen, dass die erste Tensor sein:

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

        wir die zweite Tensor sein wollen: für die zugehörigen Indizes die Koordinaten in einem Raster

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

        Diese beiden Tensoren fast funktionieren wie angegeben wird.

  • Der letzte Teil der tf.stack kombiniert die drei Tensoren auf eine neue dritten Achse, so daß das Ergebnis die gleichen wie params 3 Achsen hat.


Denken Sie daran, wenn Sie mehr oder weniger Achsen als in der Frage, müssen Sie die Anzahl der Koordinatenspezifizierungs Tensoren in tf.stack entsprechend ändern.

+0

Danke. Das ist, was ich wollte –

+0

Es scheint mir einfacher zu paralysieren, die params zu (-1, 256) und Indizes zu (-1), verwenden Sie gather_nd, und dann unflatten, als Tiling – Maxim

+0

geez. das ist wirklich schlau und auch @! @ $. Rauch kommt aus meinem Kopf und liest ihn gerade. es ist auch nützlich! Vielen Dank. rettete mir viel Zeit. – thang

1

Was Sie wollen, ist wie eine benutzerdefinierte Reduktionsfunktion. Wenn man sich indices etwas wie Index Maximalwert hält dann würde ich vorschlagen tf.reduce_max mit:

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

Ansonsten hier ist eine Möglichkeit zu bekommen, was Sie wollen (Tensor-Objekte sind nicht übertragbar, so schaffen wir eine 2d Liste Tensoren und packen es tf.pack verwenden):

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

Vielen Dank für Ihre Idee der Umgehung mit 'tf.pack' (das ist tf.stack in tf 1.0). Ja, wenn Tensorflow eine eingebaute Funktion wie 'tf.custom_reduce 'hat, die einen Tensor durch einen anderen Indextensor auswählt, wäre das großartig. –

+0

Aber was ich will, ist eine effizientere Art und Weise (Slicen), die keine "for" -Schleife den ganzen Weg nach unten beinhaltet. –

Verwandte Themen