Recherche…


Introduction

Divers exemples montrant comment Tensorflow prend en charge l'indexation dans les tenseurs, en soulignant les différences et les similitudes avec l'indexation numpy lorsque cela est possible.

Extraire une tranche d'un tenseur

Reportez-vous à la documentation tf.slice(input, begin, size) pour obtenir des informations détaillées.

Arguments:

  • input : Tenseur
  • begin : lieu de départ pour chaque dimension d' input
  • size : nombre d'éléments pour chaque dimension d' input , en utilisant -1 inclut tous les éléments restants

Numpy-like slicing:

# x has shape [2, 3, 2]
x = tf.constant([[[1., 2.], [3., 4. ], [5. , 6. ]],
                 [[7., 8.], [9., 10.], [11., 12.]]])

# Extracts x[0, 1:2, :] == [[[ 3.,  4.]]]
res = tf.slice(x, [0, 1, 0], [1, 1, -1])

En utilisant l’indexation négative, pour récupérer le dernier élément de la troisième dimension:

# Extracts x[0, :, -1:] == [[[2.], [4.], [6.]]]
last_indice = x.get_shape().as_list()[2] - 1
res = tf.slice(x, [0, 1, last_indice], [1, -1, -1])

Extraire des tranches non contiguës de la première dimension d'un tenseur

En général, tf.gather vous donne accès à des éléments de la première dimension d'un tenseur (par exemple, les lignes 1, 3 et 7 dans un tenseur bidimensionnel). Si vous avez besoin d'accéder à une autre dimension que la première, ou si vous n'avez pas besoin de la totalité de la tranche, mais uniquement de la 5ème entrée dans la 1ère, 3ème et 7ème ligne, vous tf.gather_nd utiliser tf.gather_nd (voir à venir). exemple pour cela).

arguments tf.gather :

  • params : Un tenseur dont vous voulez extraire les valeurs.
  • indices : un tenseur spécifiant les indices pointant dans les params

Reportez-vous à la documentation tf.gather (params, indices) pour des informations détaillées.


Nous voulons extraire la 1ère et la 4ème ligne dans un tenseur à 2 dimensions.

# data is [[0, 1, 2, 3, 4, 5],
#          [6, 7, 8, 9, 10, 11],
#          ...
#          [24, 25, 26, 27, 28, 29]]
data = np.reshape(np.arange(30), [5, 6])
params = tf.constant(data)
indices = tf.constant([0, 3])
selected = tf.gather(params, indices)

selected a la forme [2, 6] et l'impression de sa valeur donne

[[ 0  1  2  3  4  5]
 [18 19 20 21 22 23]]

indices peuvent également être simplement un scalaire (mais ne peuvent pas contenir d'indices négatifs). Par exemple dans l'exemple ci-dessus:

tf.gather(params, tf.constant(3))

imprimerait

[18 19 20 21 22 23]

Notez que les indices peuvent avoir n'importe quelle forme, mais les éléments stockés dans les indices réfèrent toujours uniquement à la première dimension des params . Par exemple, si vous souhaitez récupérer à la fois la 1ère et la 3ème ligne et les 2ème et 4ème lignes simultanément, vous pouvez le faire:

indices = tf.constant([[0, 2], [1, 3]])
selected = tf.gather(params, indices)

Maintenant selected aura la forme [2, 2, 6] et son contenu se lit comme suit:

[[[ 0  1  2  3  4  5]
  [12 13 14 15 16 17]]

 [[ 6  7  8  9 10 11]
  [18 19 20 21 22 23]]]

Vous pouvez utiliser tf.gather pour calculer une permutation. Par exemple, ce qui suit inverse toutes les lignes de params :

indices = tf.constant(list(range(4, -1, -1)))
selected = tf.gather(params, indices)

selected est maintenant

[[24 25 26 27 28 29]
 [18 19 20 21 22 23]
 [12 13 14 15 16 17]
 [ 6  7  8  9 10 11]
 [ 0  1  2  3  4  5]]

Si vous avez besoin d'accéder à une autre dimension que la première, vous pouvez contourner ce tf.transpose utilisant tf.transpose : par exemple, pour rassembler des colonnes au lieu de lignes dans notre exemple, vous pouvez le faire:

indices = tf.constant([0, 2])
selected = tf.gather(tf.transpose(params, [1, 0]), indices)
selected_t = tf.transpose(selected, [1, 0]) 

selected_t est de forme [5, 2] et se lit comme suit:

[[ 0  2]
 [ 6  8]
 [12 14]
 [18 20]
 [24 26]]

Cependant, tf.transpose est plutôt cher, il serait donc préférable d'utiliser tf.gather_nd pour ce cas d'utilisation.

Indexation numpie à l'aide de tenseurs

Cet exemple est basé sur cet article: TensorFlow - indexation du tenseur de type numpy .

Dans Numpy, vous pouvez utiliser des tableaux pour indexer dans un tableau. Par exemple, pour sélectionner les éléments à (1, 2) et (3, 2) dans un tableau à deux dimensions, vous pouvez le faire:

# data is [[0, 1, 2, 3, 4, 5],
#          [6, 7, 8, 9, 10, 11],
#          [12 13 14 15 16 17],
#          [18 19 20 21 22 23],
#          [24, 25, 26, 27, 28, 29]]
data = np.reshape(np.arange(30), [5, 6])
a = [1, 3]
b = [2, 2]
selected = data[a, b]
print(selected)

Cela va imprimer:

[ 8 20]

Pour obtenir le même comportement dans Tensorflow, vous pouvez utiliser tf.gather_nd , qui est une extension de tf.gather . L'exemple ci-dessus peut être écrit comme ceci:

x = tf.constant(data)
idx1 = tf.constant(a)
idx2 = tf.constant(b)
result = tf.gather_nd(x, tf.stack((idx1, idx2), -1))
        
with tf.Session() as sess:
    print(sess.run(result))

Cela va imprimer:

[ 8 20]

tf.stack est l'équivalent de np.asarray et dans ce cas empile les deux vecteurs d'index le long de la dernière dimension (qui dans ce cas est le 1er) pour produire:

[[1 2]
 [3 2]]

Comment utiliser tf.gather_nd

tf.gather_nd est une extension de tf.gather en ce sens qu'il vous permet non seulement d'accéder à la 1ère dimension d'un tenseur, mais potentiellement à toutes.

Arguments:

  • params : un Tensor de rang P représentant le tenseur dans lequel on veut indexer
  • indices : un Tenseur de rang Q représentant les indices dans les params on veut accéder

La sortie de la fonction dépend de la forme des indices . Si la dimension la plus interne des indices a la longueur P , nous params des éléments individuels à partir des params . Si elle est inférieure à P , nous tf.gather tranches, comme avec tf.gather mais sans la restriction que nous ne pouvons accéder qu'à la 1ère dimension.


Collecter des éléments d'un tenseur de rang 2

Pour accéder à l'élément en (1, 2) dans une matrice, on peut utiliser:

# data is [[0, 1, 2, 3, 4, 5],
#          [6, 7, 8, 9, 10, 11],
#          [12 13 14 15 16 17],
#          [18 19 20 21 22 23],
#          [24, 25, 26, 27, 28, 29]]
data = np.reshape(np.arange(30), [5, 6])
x = tf.constant(data)
result = tf.gather_nd(x, [1, 2])

où le result sera juste 8 comme prévu. Notez que ceci est différent de tf.gather : les mêmes indices passés à tf.gather(x, [1, 2]) auraient donné comme deuxième et troisième ligne des data .

Si vous souhaitez récupérer plus d'un élément à la fois, transmettez simplement une liste de paires d'index:

result = tf.gather_nd(x, [[1, 2], [4, 3], [2, 5]])

qui reviendra [ 8 27 17]


Collecter des lignes à partir d'un tenseur de rang 2

Si, dans l'exemple ci-dessus, vous souhaitez collecter des lignes (c.-à-d. Des tranches) au lieu d'éléments, ajustez le paramètre indices comme suit:

data = np.reshape(np.arange(30), [5, 6])
x = tf.constant(data)
result = tf.gather_nd(x, [[1], [3]])

Cela vous donnera les 2ème et 4ème lignes de data , c.-à-d.

[[ 6  7  8  9 10 11]
 [18 19 20 21 22 23]]

Collecter des éléments d'un tenseur de rang 3

La notion d'accès aux tenseurs de rang 2 se traduit directement par des tenseurs de plus grande dimension. Donc, pour accéder aux éléments dans un tenseur de rang 3, la dimension la plus interne des indices doit avoir une longueur de 3.

# data is [[[ 0  1]
#          [ 2  3]
#          [ 4  5]]
#
#         [[ 6  7]
#          [ 8  9]
#          [10 11]]]
data = np.reshape(np.arange(12), [2, 3, 2])
x = tf.constant(data)
result = tf.gather_nd(x, [[0, 0, 0], [1, 2, 1]])

result ressemblera maintenant à ceci: [ 0 11]


Collecter des lignes groupées à partir d'un tenseur de rang 3

Pensons à un tenseur de rang 3 en tant que lot de matrices formées (batch_size, m, n) . Si vous souhaitez collecter la première et la deuxième ligne pour chaque élément du lot, vous pouvez utiliser ceci:

# data is [[[ 0  1]
#          [ 2  3]
#          [ 4  5]]
#
#         [[ 6  7]
#          [ 8  9]
#          [10 11]]]
data = np.reshape(np.arange(12), [2, 3, 2])
x = tf.constant(data)
result = tf.gather_nd(x, [[[0, 0], [0, 1]], [[1, 0], [1, 1]]])

ce qui se traduira par ceci:

[[[0 1]
  [2 3]]

 [[6 7]
  [8 9]]]

Notez comment la forme des indices influence la forme du tenseur de sortie. Si nous aurions utilisé un tenseur rank-2 pour l'argument indices :

result = tf.gather_nd(x, [[0, 0], [0, 1], [1, 0], [1, 1]])

la sortie aurait été

[[0 1]
 [2 3]
 [6 7]
 [8 9]]


Modified text is an extract of the original Stack Overflow Documentation
Sous licence CC BY-SA 3.0
Non affilié à Stack Overflow