Поиск…


Вступление

Различные примеры, показывающие, как 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]]


Modified text is an extract of the original Stack Overflow Documentation
Лицензировано согласно CC BY-SA 3.0
Не связан с Stack Overflow