tensorflow
Indexation de tenseurs
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 lesparams
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 rangP
représentant le tenseur dans lequel on veut indexer -
indices
: un Tenseur de rangQ
représentant les indices dans lesparams
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]]