tensorflow
Tensorindex
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 varjeinput
-
size
: antal element för varjeinput
, 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 rangP
representerar den tensor vi vill indexera till -
indices
: en Tensor av rangQ
representerar indexen iparams
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]]