tensorflow
Индексация тензора
Поиск…
Вступление
Различные примеры, показывающие, как Tensorflow поддерживает индексирование в тензоры, выделяя различия и сходства с индексированием, похожим на numpy, где это возможно.
Извлечь срез из тензора
Подробную информацию см. В документации tf.slice(input, begin, size)
.
Аргументы:
-
input
: тензор -
begin
: начальное местоположение для каждого измеренияinput
-
size
: количество элементов для каждого измеренияinput
, используя-1
включает все остальные элементы
Ненужное нарезка:
# 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])
Используя отрицательную индексацию, чтобы получить последний элемент в третьем измерении:
# 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])
Извлечь непересекающиеся срезы из первого измерения тензора
Обычно tf.gather
дает вам доступ к элементам в первом измерении тензора (например, строки 1, 3 и 7 в двумерном тензоре). Если вам нужен доступ к любому другому измерению, кроме первого, или если вам не нужен весь фрагмент, но, например, только пятая запись в первой, третьей и седьмой строке, вам лучше использовать tf.gather_nd
(см. пример для этого).
tf.gather
аргументы:
-
params
: тензор, из которого вы хотите извлечь значения. -
indices
: тензор, определяющий индексы, указывающие наparams
Подробную информацию см. В документации tf.gather (параметры, индексы) .
Мы хотим извлечь 1-ю и 4-ю строки в 2-мерном тензоре.
# 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
имеет форму [2, 6]
и печать его значения дает
[[ 0 1 2 3 4 5]
[18 19 20 21 22 23]]
indices
также могут быть просто скалярными (но не могут содержать отрицательных индексов). Например, в приведенном выше примере:
tf.gather(params, tf.constant(3))
будет печатать
[18 19 20 21 22 23]
Обратите внимание, что indices
могут иметь любую форму, но элементы, хранящиеся в indices
всегда относятся только к первому размеру params
. Например , если вы хотите получить как 1 - й и 3 - й строки и 2 - й и 4 - й ряд , в то же время, вы можете сделать это:
indices = tf.constant([[0, 2], [1, 3]])
selected = tf.gather(params, indices)
Теперь selected
будет иметь форму [2, 2, 6]
и его содержимое будет выглядеть следующим образом:
[[[ 0 1 2 3 4 5]
[12 13 14 15 16 17]]
[[ 6 7 8 9 10 11]
[18 19 20 21 22 23]]]
Вы можете использовать tf.gather
для вычисления перестановки. Например, следующие обратные строки всех params
:
indices = tf.constant(list(range(4, -1, -1)))
selected = tf.gather(params, indices)
selected
сейчас
[[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]]
Если вам нужен доступ к любому другому, кроме первого измерения, вы можете обойти это с помощью tf.transpose
: например, для сбора столбцов вместо строк в нашем примере вы можете сделать это:
indices = tf.constant([0, 2])
selected = tf.gather(tf.transpose(params, [1, 0]), indices)
selected_t = tf.transpose(selected, [1, 0])
selected_t
имеет форму [5, 2]
и гласит:
[[ 0 2]
[ 6 8]
[12 14]
[18 20]
[24 26]]
Однако tf.transpose
довольно дорогостоящий, поэтому было бы лучше использовать tf.gather_nd
для этого tf.gather_nd
использования.
Подобно индексированию по типу с использованием тензоров
Этот пример основан на этом сообщении: TensorFlow - индексирование тензоподобного тензора .
В Numpy вы можете использовать массивы для индексации в массив. Например, чтобы выбрать элементы в (1, 2)
и (3, 2)
в двумерном массиве, вы можете сделать это:
# 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)
Это напечатает:
[ 8 20]
Чтобы получить такое же поведение в Tensorflow, вы можете использовать tf.gather_nd
, который является расширением tf.gather
. Вышеприведенный пример можно записать следующим образом:
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))
Это напечатает:
[ 8 20]
tf.stack
является эквивалентом np.asarray
и в этом случае складывает два индексных вектора вдоль последнего измерения (который в этом случае является np.asarray
) для создания:
[[1 2]
[3 2]]
Как использовать tf.gather_nd
tf.gather_nd
является расширением tf.gather
в том смысле, что позволяет не только получить доступ к 1-му измерению тензора, но и потенциально все из них.
Аргументы:
-
params
: Тензор рангаP
представляющий тензор, который мы хотим индексировать в -
indices
: Тензор рангаQ
представляющий индексы вparams
мы хотим получить
Выход функции зависит от формы indices
. Если самая внутренняя размерность indices
имеет длину P
, мы собираем отдельные элементы из params
. Если он меньше, чем P
, мы собираем срезы, как и с tf.gather
но без ограничений, которые мы можем получить только в первом измерении.
Сбор элементов из тензора ранга 2
Чтобы получить доступ к элементу в (1, 2)
в матрице, мы можем использовать:
# 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])
где result
будет равен 8
как ожидалось. Обратите внимание на то, как это отличается от tf.gather
: те же индексы, переданные в tf.gather(x, [1, 2])
были бы указаны как 2-я и 3-я строки из data
.
Если вы хотите получить более одного элемента одновременно, просто передайте список пар индексов:
result = tf.gather_nd(x, [[1, 2], [4, 3], [2, 5]])
который вернется [ 8 27 17]
Сбор строк из тензора ранга 2
Если в приведенном выше примере вы хотите собирать строки (то есть срезы) вместо элементов, отрегулируйте параметр indices
следующим образом:
data = np.reshape(np.arange(30), [5, 6])
x = tf.constant(data)
result = tf.gather_nd(x, [[1], [3]])
Это даст вам 2-й и 4-й строки data
, т. Е.
[[ 6 7 8 9 10 11]
[18 19 20 21 22 23]]
Сбор элементов из тензора ранга 3
Концепция доступа к тензорам ранга-2 напрямую переводится в тензоры с более высокой размерностью. Итак, чтобы получить доступ к элементам в тензоре ранга 3, самое внутреннее измерение indices
должно иметь длину 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
будет выглядеть следующим образом: [ 0 11]
Сбор собранных строк из тензора 3-го ранга
Давайте рассмотрим тензор ранга 3 в виде партии матриц (batch_size, m, n)
. Если вы хотите собрать первую и вторую строки для каждого элемента в пакете, вы можете использовать это:
# 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]]])
что приведет к следующему:
[[[0 1]
[2 3]]
[[6 7]
[8 9]]]
Обратите внимание, как форма indices
влияет на форму выходного тензора. Если бы мы использовали тензор ранга-2 для аргумента indices
:
result = tf.gather_nd(x, [[0, 0], [0, 1], [1, 0], [1, 1]])
выход был бы
[[0 1]
[2 3]
[6 7]
[8 9]]