Szukaj…


Wprowadzenie

Różne przykłady pokazujące, w jaki sposób Tensorflow obsługuje indeksowanie do tensorów, podkreślając różnice i podobieństwa do indeksowania numerycznego, tam gdzie to możliwe.

Wyodrębnij plasterek z tensora

Szczegółowe informacje można znaleźć w dokumentacji tf.slice(input, begin, size) .

Argumenty:

  • input : Tensor
  • begin : lokalizację początkową dla każdego wymiaru input
  • size : liczba elementów dla każdego wymiaru input , użycie -1 obejmuje wszystkie pozostałe elementy

Krojenie numeryczne:

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

Używając indeksowania ujemnego, aby pobrać ostatni element z trzeciego wymiaru:

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

Wyciąg nieciągłe plastry z pierwszego wymiaru tensora

Ogólnie tf.gather daje dostęp do elementów w pierwszym wymiarze tensora (np. Rzędy 1, 3 i 7 w 2-wymiarowym tensorze). Jeśli potrzebujesz dostępu do innego wymiaru niż pierwszy lub nie potrzebujesz całego wycinka, ale np. Tylko piątego wpisu w 1., 3. i 7. rzędzie, lepiej jest użyć tf.gather_nd (patrz nadchodzące przykład tego).

argumenty tf.gather :

  • params : tensor, z którego chcesz wyodrębnić wartości.
  • indices : tensora określając wskaźniki wskazujące na params

Szczegółowe informacje można znaleźć w dokumentacji tf.gather (parametry, indeksy) .


Chcemy wyodrębnić 1 i 4 rząd w 2-wymiarowym tensorze.

# 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 ma kształt [2, 6] a wydrukowanie jego wartości daje

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

indices mogą być również skalarne (ale nie mogą zawierać indeksów ujemnych). Np. W powyższym przykładzie:

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

wydrukuje

[18 19 20 21 22 23]

Należy pamiętać, że indices mogą mieć dowolny kształt, ale elementy przechowywane w indices zawsze odnoszą się tylko do pierwszego wymiaru params . Np. Jeśli chcesz pobrać jednocześnie pierwszy i trzeci rząd oraz drugi i czwarty rząd w tym samym czasie, możesz to zrobić:

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

Teraz selected będą miały kształt [2, 2, 6] a ich treść brzmi:

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

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

Możesz użyć tf.gather do obliczenia permutacji. Np dodaje odwraca wszystkie wiersze params :

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

selected jest teraz

[[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]]

Jeśli potrzebujesz dostępu do innego niż pierwszy wymiar, możesz obejść ten tf.transpose za pomocą tf.transpose : Np. Aby zebrać kolumny zamiast wierszy w naszym przykładzie, możesz to zrobić:

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

selected_t ma kształt [5, 2] i czyta:

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

Jednak tf.transpose jest dość drogi, więc może być lepiej użyć tf.gather_nd dla tego przypadku użycia.

Indeksowanie numeryczne za pomocą tensorów

Ten przykład jest oparty na tym poście: TensorFlow - indeksowanie tensorowe typu numpy .

W Numpy możesz używać tablic do indeksowania w tablicę. Np. Aby wybrać elementy w (1, 2) i (3, 2) w tablicy dwuwymiarowej, możesz to zrobić:

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

Spowoduje to wydrukowanie:

[ 8 20]

Aby uzyskać takie samo zachowanie w Tensorflow, możesz użyć tf.gather_nd , który jest rozszerzeniem tf.gather . Powyższy przykład można zapisać w następujący sposób:

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

Spowoduje to wydrukowanie:

[ 8 20]

tf.stack jest odpowiednikiem np.asarray iw tym przypadku układa dwa wektory indeksowe wzdłuż ostatniego wymiaru (który w tym przypadku jest 1.), aby uzyskać:

[[1 2]
 [3 2]]

Jak korzystać z tf.gather_nd

tf.gather_nd jest rozszerzeniem tf.gather w tym sensie, że umożliwia dostęp nie tylko do pierwszego wymiaru tensora, ale potencjalnie do wszystkich.

Argumenty:

  • params : tensor rangi P reprezentujący tensor, w którym chcemy się indeksować
  • indices : tensora od rangi Q reprezentujących indeksy w params chcemy dostępem

Wynik funkcji zależy od kształtu indices . Jeśli najgłębsza wymiar indices ma długość P , jesteśmy zbieranie pojedynczych elementów z params . Jeśli jest mniejszy niż P , zbieramy plasterki, tak jak w przypadku tf.gather ale bez ograniczenia, że możemy uzyskać dostęp tylko do pierwszego wymiaru.


Zbieranie elementów z tensora rangi 2

Aby uzyskać dostęp do elementu w (1, 2) w macierzy, możemy użyć:

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

gdzie result będzie tylko 8 zgodnie z oczekiwaniami. Zauważ, że różni się to od tf.gather : te same wskaźniki przekazane do tf.gather(x, [1, 2]) dałoby jako drugi i trzeci wiersz data .

Jeśli chcesz pobrać więcej niż jeden element w tym samym czasie, po prostu przekaż listę par indeksów:

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

który zwróci [ 8 27 17]


Zbieranie rzędów z tensora rangi 2

Jeśli w powyższym przykładzie chcesz zbierać wiersze (tj. Plasterki) zamiast elementów, dostosuj parametr indices w następujący sposób:

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

To da ci drugi i czwarty rząd data , tj

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

Zbieranie elementów z tensora rangi 3

Koncepcja dostępu do tensorów rangi 2 przekłada się bezpośrednio na tensory wyższego wymiaru. Tak więc, aby uzyskać dostęp do elementów w tensorze rangi 3, najbardziej wewnętrzny wymiar indices musi mieć długość 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 będzie teraz wyglądał następująco: [ 0 11]


Zbieranie rzędów z tensora o randze 3

Pomyślmy o (batch_size, m, n) rangi 3 jako partii macierzy w kształcie (batch_size, m, n) . Jeśli chcesz zebrać pierwszy i drugi wiersz dla każdego elementu w partii, możesz użyć tego:

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

co spowoduje:

[[[0 1]
  [2 3]]

 [[6 7]
  [8 9]]]

Zwróć uwagę, jak kształt indices wpływa na kształt tensora wyjściowego. Gdybyśmy użyli tensora rangi 2 dla argumentu indices :

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

wynik byłby

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


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow