tensorflow
Indeksowanie tensorów
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 wymiaruinput
-
size
: liczba elementów dla każdego wymiaruinput
, 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 naparams
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 rangiP
reprezentujący tensor, w którym chcemy się indeksować -
indices
: tensora od rangiQ
reprezentujących indeksy wparams
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]]