Sök…


Introduktion

Olika exempel som visar hur Tensorflow stöder indexering till tensorer, belyser skillnader och likheter med numpy-liknande indexering där det är möjligt.

Extrahera en skiva från en tensor

Se tf.slice(input, begin, size) för detaljerad information.

Argument:

  • input : Tensor
  • begin : startplats för varje input
  • size : antal element för varje input , med -1 inkluderar alla återstående element

Numpy-liknande skivning:

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

Med negativ indexering för att hämta det sista elementet i den tredje dimensionen:

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

Extrahera icke sammanhängande skivor från en tensors första dimension

Generellt ger tf.gather dig tillgång till element i den första dimensionen av en tensor (t.ex. rader 1, 3 och 7 i en 2-dimensionell Tensor). Om du behöver tillgång till någon annan dimension än den första, eller om du inte behöver hela skivan, men t.ex. bara den femte posten i den första, tredje och sjunde raden, är du bättre med att använda tf.gather_nd (se kommande exempel för detta).

tf.gather argument:

  • params : En tensor som du vill extrahera värden från.
  • indices : En tensor som anger de index som pekar på params

Se dokumentationen tf.gather (params, index) för detaljerad information.


Vi vill extrahera 1: a och 4: e raden i en tvådimensionell tensor.

# 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 har form [2, 6] och utskrift av dess värde ger

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

indices kan också bara vara en skalär (men kan inte innehålla negativa index). Exempelvis i ovanstående exempel:

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

skulle skriva ut

[18 19 20 21 22 23]

Observera att indices kan ha vilken form som helst, men elementen som lagras i indices hänvisar alltid endast till den första dimensionen av params . Om du t.ex. vill hämta både den första och den tredje raden och den andra och den fjärde raden samtidigt kan du göra detta:

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

Nu selected kommer att ha form [2, 2, 6] och dess innehåll lyder:

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

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

Du kan använda tf.gather att beräkna en permutation. Exempelvis vänder följande alla rader med params :

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

selected är nu

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

Om du behöver tillgång till någon annan än den första dimensionen kan du tf.transpose det med tf.transpose : T.ex. för att samla kolumner istället för rader i vårt exempel kan du göra detta:

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

selected_t har form [5, 2] och läser:

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

Men tf.transpose är ganska dyrt, så det kan vara bättre att använda tf.gather_nd för detta användningsfall.

Numpy-liknande indexering med tensorer

Detta exempel är baserat på det här inlägget: TensorFlow - numpy-liknande tensorindex .

I Numpy kan du använda matriser för att indexera till en matris. Till exempel för att välja elementen på (1, 2) och (3, 2) i en tvådimensionell matris kan du göra detta:

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

Detta kommer att skriva ut:

[ 8 20]

För att få samma beteende i Tensorflow kan du använda tf.gather_nd , som är en förlängning av tf.gather . Exemplet ovan kan skrivas så här:

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

Detta kommer att skriva ut:

[ 8 20]

tf.stack är motsvarigheten till np.asarray och i detta fall staplar de två indexvektorerna längs den sista dimensionen (som i detta fall är den 1: a) för att producera:

[[1 2]
 [3 2]]

Hur man använder tf.gather_nd

tf.gather_nd är en förlängning av tf.gather i den meningen att det tillåter dig att inte bara få åtkomst till den första dimensionen av en tensor, utan potentiellt alla.

Argument:

  • params : en Tensor av rang P representerar den tensor vi vill indexera till
  • indices : en Tensor av rang Q representerar indexen i params vi vill komma åt

Utgången av funktionen beror på formen av indices . Om den innersta dimensionen av indices har längd P , vi samla enstaka element från params . Om det är mindre än P samlar vi in skivor, precis som med tf.gather men utan begränsningen att vi bara har åtkomst till den första dimensionen.


Samla element från en tensor av rang 2

För att få tillgång till elementet på (1, 2) i en matris kan vi använda:

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

där result bara blir 8 som förväntat. Notera hur detta skiljer sig från tf.gather : samma index som tf.gather(x, [1, 2]) till tf.gather(x, [1, 2]) skulle ha gett den andra och tredje raden från data .

Om du vill hämta mer än ett element samtidigt passerar du bara en lista med indexpar:

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

som kommer att återvända [ 8 27 17]


Samlar rader från en tensor av rang 2

Om du i ovanstående exempel vill samla rader (dvs skivor) istället för element, justerar du indices enligt följande:

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

Detta ger dig den andra och fjärde raden med data , dvs.

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

Samla element från en tensor av rang 3

Konceptet hur man får åtkomst till rank-2-tensorer direkt översätter till högre dimensionella tensorer. Så för att få tillgång till element i en rank-3-tensor måste indices innersta dimension ha längd 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 kommer nu att se ut så här: [ 0 11]


Samlar batchade rader från en tensor i rang 3

Låt oss tänka på en rank-3-tensor som en grupp matriser formade (batch_size, m, n) . Om du vill samla den första och andra raden för varje element i batch kan du använda detta:

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

vilket kommer att resultera i detta:

[[[0 1]
  [2 3]]

 [[6 7]
  [8 9]]]

Notera hur formen av indices påverkar formen på utgångs tensor. Om vi skulle ha använt en rank-2-tensor för indices argument:

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

utgången skulle ha varit

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


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow