tensorflow
Indicizzazione del tensore
Ricerca…
introduzione
Vari esempi mostrano come Tensorflow supporti l'indicizzazione nei tensori, evidenziando le differenze e le somiglianze con l'indicizzazione simile a numpy, ove possibile.
Estrai una fetta da un tensore
Fare riferimento alla documentazione di tf.slice(input, begin, size)
per informazioni dettagliate.
Argomenti:
-
input
: Tensore -
begin
: posizione iniziale per ogni dimensione diinput
-
size
: numero di elementi per ogni dimensione diinput
, utilizzando-1
include tutti gli elementi rimanenti
Affettatura simile a Numpy:
# 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])
Utilizzando l'indicizzazione negativa, per recuperare l'ultimo elemento nella terza dimensione:
# 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])
Estrai sezioni non contigue dalla prima dimensione di un tensore
Generalmente tf.gather
ti dà accesso agli elementi nella prima dimensione di un tensore (es. Righe 1, 3 e 7 in un tensore bidimensionale). Se hai bisogno di accedere a qualsiasi altra dimensione rispetto alla prima, o se non hai bisogno dell'intera fetta, ma ad esempio solo la quinta voce nella 1a, 3a e 7a riga, stai meglio usando tf.gather_nd
(vedi prossimo esempio per questo).
tf.gather
argomenti:
-
params
: un tensore da cui estrarre i valori. -
indices
: un tensore che specifica gli indici che puntano inparams
Fare riferimento alla documentazione di tf.gather (parametri, indici) per informazioni dettagliate.
Vogliamo estrarre la prima e la quarta fila in un tensore bidimensionale.
# 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
ha forma [2, 6]
e ne dà il valore
[[ 0 1 2 3 4 5]
[18 19 20 21 22 23]]
indices
possono anche essere solo scalari (ma non possono contenere indici negativi). Ad esempio nell'esempio precedente:
tf.gather(params, tf.constant(3))
stamperebbe
[18 19 20 21 22 23]
Nota che gli indices
possono avere qualsiasi forma, ma gli elementi memorizzati negli indices
si riferiscono sempre solo alla prima dimensione dei params
. Ad esempio, se vuoi recuperare sia la 1a e 3a riga e la 2a e 4a riga contemporaneamente, puoi farlo:
indices = tf.constant([[0, 2], [1, 3]])
selected = tf.gather(params, indices)
Ora selected
avrà forma [2, 2, 6]
e il suo contenuto recita:
[[[ 0 1 2 3 4 5]
[12 13 14 15 16 17]]
[[ 6 7 8 9 10 11]
[18 19 20 21 22 23]]]
Puoi usare tf.gather
per calcolare una permutazione. Ad esempio il seguente inverte tutte le righe di params
:
indices = tf.constant(list(range(4, -1, -1)))
selected = tf.gather(params, indices)
selected
è ora
[[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]]
Se hai bisogno di accedere a una diversa dalla prima dimensione, puoi ovviare a ciò usando tf.transpose
: Eg per raccogliere colonne invece di righe nel nostro esempio, potresti fare questo:
indices = tf.constant([0, 2])
selected = tf.gather(tf.transpose(params, [1, 0]), indices)
selected_t = tf.transpose(selected, [1, 0])
selected_t
è di forma [5, 2]
e legge:
[[ 0 2]
[ 6 8]
[12 14]
[18 20]
[24 26]]
Tuttavia, tf.transpose
è piuttosto costoso, quindi potrebbe essere meglio usare tf.gather_nd
per questo caso d'uso.
Indicizzazione di Numpy usando tensori
Questo esempio si basa su questo post: TensorFlow - indicizzazione del tensore simile a numpy .
In Numpy puoi usare gli array per indicizzare in un array. Ad esempio, per selezionare gli elementi in (1, 2)
e (3, 2)
in una matrice bidimensionale, puoi farlo:
# 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)
Questo stamperà:
[ 8 20]
Per ottenere lo stesso comportamento in Tensorflow, è possibile utilizzare tf.gather_nd
, che è un'estensione di tf.gather
. L'esempio sopra può essere scritto così:
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))
Questo stamperà:
[ 8 20]
tf.stack
è l'equivalente di np.asarray
e in questo caso impila i due vettori di indice lungo l'ultima dimensione (che in questo caso è il primo) per produrre:
[[1 2]
[3 2]]
Come usare tf.gather_nd
tf.gather_nd
è un'estensione di tf.gather
nel senso che ti consente non solo di accedere alla 1a dimensione di un tensore, ma potenzialmente a tutti loro.
Argomenti:
-
params
: un Tensore di rangoP
rappresenta il tensore in cui vogliamo indicizzare -
indices
: un Tensore di rangoQ
rappresenta gli indici inparams
cui vogliamo accedere
L'output della funzione dipende dalla forma degli indices
. Se la dimensione più interna degli indices
ha lunghezza P
, stiamo raccogliendo singoli elementi dai params
. Se è inferiore a P
, stiamo raccogliendo fette, proprio come con tf.gather
ma senza la restrizione che possiamo accedere solo alla prima dimensione.
Raccolta di elementi da un tensore di rango 2
Per accedere all'elemento in (1, 2)
in una matrice, possiamo usare:
# 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])
dove il result
sarà solo 8
come previsto. Nota come questo è diverso da tf.gather
: gli stessi indici passati a tf.gather(x, [1, 2])
avrebbero dato come seconda e terza riga dai data
.
Se vuoi recuperare più di un elemento allo stesso tempo, passa semplicemente un elenco di coppie di indici:
result = tf.gather_nd(x, [[1, 2], [4, 3], [2, 5]])
che ritornerà [ 8 27 17]
Raccolta di righe da un tensore di rango 2
Se nell'esempio precedente desideri raccogliere righe (ad es. Fette) anziché elementi, regola i parametri degli indices
come segue:
data = np.reshape(np.arange(30), [5, 6])
x = tf.constant(data)
result = tf.gather_nd(x, [[1], [3]])
Questo ti darà la 2a e 4a riga di data
, es
[[ 6 7 8 9 10 11]
[18 19 20 21 22 23]]
Raccolta di elementi da un tensore di rango 3
Il concetto di come accedere ai tensori di Rank-2 si traduce direttamente in tensioni dimensionali superiori. Quindi, per accedere agli elementi in un tensore di grado 3, la dimensione più interna degli indices
deve avere lunghezza 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
sarà ora simile a questo: [ 0 11]
Raccolta di righe in batch da un tensore di rango 3
Pensiamo a un tensore di rango 3 come una serie di matrici a forma (batch_size, m, n)
. Se si desidera raccogliere la prima e la seconda riga per ogni elemento del batch, è possibile utilizzare questo:
# 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]]])
che si tradurrà in questo:
[[[0 1]
[2 3]]
[[6 7]
[8 9]]]
Nota come la forma degli indices
influenza la forma del tensore di uscita. Se avessimo usato un tensore di grado 2 per l'argomento degli indices
:
result = tf.gather_nd(x, [[0, 0], [0, 1], [1, 0], [1, 1]])
l'uscita sarebbe stata
[[0 1]
[2 3]
[6 7]
[8 9]]