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 di input
  • size : numero di elementi per ogni dimensione di input , 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 in params

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 rango P rappresenta il tensore in cui vogliamo indicizzare
  • indices : un Tensore di rango Q rappresenta gli indici in params 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]]


Modified text is an extract of the original Stack Overflow Documentation
Autorizzato sotto CC BY-SA 3.0
Non affiliato con Stack Overflow