2016-12-29 4 views
15

Ich frage mich, was tf.strided_slice() Operator tatsächlich tut.
Die doc sagtWas macht `tf.strided_slice()`?

In erster Ordnung, diese Operation extrahiert ein Stück Größe Ende - beginnen von einem Tensor-Eingang an der durch beginnen angegebene Position zu starten. Das Slice wird fortgesetzt, indem Schritt zum Startindex hinzugefügt wird, bis alle Dimensionen nicht kleiner als end sind. Beachten Sie, dass Komponenten von stride negativ sein können, was eine umgekehrte Schicht verursacht.

Und in der Probe,

# 'input' is [[[1, 1, 1], [2, 2, 2]], 
#    [[3, 3, 3], [4, 4, 4]], 
#    [[5, 5, 5], [6, 6, 6]]] 
tf.slice(input, [1, 0, 0], [2, 1, 3], [1, 1, 1]) ==> [[[3, 3, 3]]] 
tf.slice(input, [1, 0, 0], [2, 2, 3], [1, 1, 1]) ==> [[[3, 3, 3], 
                 [4, 4, 4]]] 
tf.slice(input, [1, 1, 0], [2, -1, 3], [1, -1, 1]) ==>[[[4, 4, 4], 
                 [3, 3, 3]]] 

Also in meinem Verständnis der doc, die erste Probe (tf.slice(input, begin=[1, 0, 0], end=[2, 1, 3], strides=[1, 1, 1])),

  • Größe resultiert, ist end - begin = [1, 1, 3]. Das Beispielergebnis zeigt [[[3, 3, 3,]]], diese Form ist [1, 1, 3], es scheint OK.
  • das erste Element des Ergebnisses ist begin = [1, 0, 0]. Das erste Element des Probenergebnisses ist 3, das ist input[1,0,0], es scheint OK.
  • Das Segment wird fortgesetzt, indem Schritt zum Anfangsindex hinzugefügt wird. So sollte das zweite Element des Ergebnisses input[begin + strides] = input[2, 1, 1] = 6 sein, aber das Beispiel zeigt das zweite Element ist 3.

Was macht strided_slice()?

. (Anmerkung: method names in the samples and the last example is incorrect)

+0

Es fügt nicht "Schritte" direkt zu "beginnen" – martianwars

+0

@martiwars Vielen Dank für Ihre Antwort! Also, wofür wird "schreitet" verwendet? – keisuke

+0

hängen, eine Antwort schreiben :) – martianwars

Antwort

9

Der Fehler in Ihrem Argument ist die Tatsache, dass man direkt die Listen strides und begin Element für Element hinzufügen. Dies wird die Funktion viel weniger nützlich machen. Stattdessen wird die begin Liste um jeweils eine Dimension erhöht, beginnend mit der letzten Dimension.

Lassen Sie uns das erste Beispiel Teil für Teil lösen. begin = [1, 0, 0] und end = [2, 1, 3]. Auch alle strides sind 1. Arbeite dich rückwärts, von der letzten Dimension aus.

Beginnen Sie mit Element [1,0,0]. Jetzt erhöhen Sie die letzte Dimension nur um seine Schrittmenge, geben Sie [1,0,1]. Mach so weiter, bis du das Limit erreicht hast. Etwas wie [1,0,2], [1,0,3] (Ende der Schleife). Beginnen Sie jetzt in Ihrer nächsten Iteration mit dem Erhöhen der vorletzten Dimension und dem Zurücksetzen der letzten Dimension, [1,1,0]. Hier ist die vorletzte Dimension gleich end[1], also bewege dich in die erste Dimension (drittletzte) und setze den Rest auf [2,0,0]. Wieder sind Sie an der Grenze der ersten Dimension, also beenden Sie die Schleife.

Der folgende Code ist eine rekursive Implementierung von dem, was ich oben beschrieben,

# Assume global `begin`, `end` and `stride` 
def iterate(active, dim): 
    if dim == len(begin): 
     # last dimension incremented, work on the new matrix 
     # Note that `active` and `begin` are lists 
     new_matrix[active - begin] = old_matrix[active] 
    else: 
     for i in range(begin[dim], end[dim], stride[dim]): 
      new_active = copy(active) 
      new_active[dim] = i 
      iterate(new_active, dim + 1) 

iterate(begin, 0) 
+2

aber' [1, 1, 0] 'gibt '4' statt '3' zurück? – southdoor

+0

Hallo. Ich verstehe, wie dieser Teil funktioniert: "Erhöhe die letzte Dimension nur um ihren Schrittbetrag", aber wie bekomme ich am Ende [[3, 3, 3]]]? Könnten Sie bitte ein wenig klarer sein? Danke @martiwars –

14

ich ein bisschen mit dieser Methode experimentiert, die mir einige Einsichten gab, die ich denke, von Nutzen sein könnte. Sagen wir, wir haben einen Tensor.

 a = np.array([[[1, 1.2, 1.3], [2, 2.2, 2.3], [7, 7.2, 7.3]], 
         [[3, 3.2, 3.3], [4, 4.2, 4.3], [8, 8.2, 8.3]], 
         [[5, 5.2, 5.3], [6, 6.2, 6.3], [9, 9.2, 9.3]]]) 
                shape = (3,3,3) 

strided_slice() erfordert 4 erforderlichen Argumente input_, begin, end, strides, in denen wir unsere a als input_ Argument geben. Wie bei der Methode tf.slice() ist das Argument begin nullbasiert und der Rest der Argumente formbasiert. Jedoch sind in den Dokumenten begin und end beide nullbasiert.

Die Funktionalität der Methode ist ganz einfach:
Es funktioniert wie über eine Schleife iteriert, wo begin die Position des Elements in der Tensor ist, von wo aus der Schleife initiiert und end ist, wo es aufhört.

tf.strided_slice(a, [0, 0, 0], [3, 3, 3], [1, 1, 1]) 

    output = the tensor itself 

    tf.strided_slice(a, [0, 0, 0], [3, 3, 3], [2, 2, 2]) 

    output = [[[ 1. 1.3] 
       [ 7. 7.3]] 

       [[ 5. 5.3] 
       [ 9. 9.3]]] 

strides sind gleiche Schritte, über die die Schleife iteriert, hier der [2,2,2] Verfahren Werte ab (0,0,0) zu erzeugen, macht (0,0,2), (0,2,0), (0,2,2), (2,0,0), (2,0,2) ..... im a Tensor.

tf.strided_slice(input3, [1, 1, 0], [2, -1, 3], [1, 1, 1]) 

wird eine Ausgabe ähnlich tf.strided_slice(input3, [1, 1, 0], [2, 2, 3], [1, 1, 1]) als Tensor produzieren ashape = (3,3,3) hat.

+0

das ist 'wirklich hilfreich! –

7

Die Konzeptualisierung, die mir wirklich geholfen hat zu verstehen, war, dass diese Funktion das Indizierungsverhalten von numpy Arrays emuliert.

Wenn Sie mit numpy Arrays vertraut sind, wissen Sie, dass Sie Slices über input[start1:end1:step1, start2:end2:step2, ... startN:endN:stepN] erstellen können. Im Grunde eine sehr prägnante Art zu schreiben for Schleifen, um bestimmte Elemente des Arrays zu erhalten.

(Wenn Sie vertraut mit Python Indizierung sind, wissen Sie, dass Sie eine Array-Slice über input[start:end:step] greifen kann. Numpy Arrays, die verschachtelt werden können, die Verwendung des oben Tupel von Slice Objekte.)

Well , strided_slice erlaubt Ihnen nur, diese ausgefallene Indizierung ohne den syntaktischen Zucker zu machen. Das numpy Beispiel von oben nur wird

# input[start1:end1:step1, start2:end2:step2, ... startN:endN:stepN] 
tf.strided_slice(input, [start1, start2, ..., startN], 
    [end1, end2, ..., endN], [step1, step2, ..., stepN]) 

Die Dokumentation ein wenig verwirrend darüber in dem Sinne, dass:

a) begin - end ist nicht unbedingt die Form des Rückgabewertes:

Die Dokumentation behauptet anders, aber das ist nur wahr, wenn Ihre Schritte alle Einsen sind. Beispiele:

rank1 = tf.constant(list(range(10))) 
# The below op is basically: 
# rank1[1:10:2] => [1, 3, 5, 7, 9] 
tf.strided_slice(rank1, [1], [10], [2]) 

# [10,10] grid of the numbers from 0 to 99 
rank2 = tf.constant([[i+j*10 for i in range(10)] for j in range(10)]) 
# The below op is basically: 
# rank2[3:7:1, 5:10:2] => numbers 30 - 69, ending in 5, 7, or 9 
sliced = tf.strided_slice(rank2, [3, 5], [7, 10], [1, 2]) 
# The below op is basically: 
# rank2[3:7:1] => numbers 30 - 69 
sliced = tf.strided_slice(rank2, [3], [7], [1]) 

b) heißt es, dass "begin, end und strides werden alle Länge n sein, wobei n im allgemeinen nicht die gleiche Dimensionalität wie input"

Es klingt wie Dimensionalität bedeutet Rang hier - aber inputmuss ein Tensor von mindestens Rang-n sein; es kann nicht niedriger sein (siehe Rang-2-Beispiel oben).

N.B. Ich habe nichts gesagt/nicht wirklich das Maskierungsmerkmal erforscht, aber das scheint über den Rahmen der Frage hinauszugehen.

1

tf.strided_slice() wird verwendet, um eine stille Slicing-Funktion für eine Tensorvariable auszuführen. Es hat 4 Parameter im Allgemeinen: Eingabe, Begin, Ende, Schritt. Das Slice wird durch Hinzufügen von Schritt zum Index beginnen, bis alle Dimensionen nicht kleiner als das Ende sind. Für die Ex: Lassen Sie uns einen Tensor Konstante "Probe" von Dimensionen benannt nehmen: [3,2,3]

import tensorflow as tf 

sample = tf.constant(
    [[[11, 12, 13], [21, 22, 23]], 
    [[31, 32, 33], [41, 42, 43]], 
    [[51, 52, 53], [61, 62, 63]]]) 

slice = tf.strided_slice(sample, begin=[0,0,0], end=[3,2,3], strides=[2,2,2]) 

with tf.Session() as sess: 
    print(sess.run(slice)) 

Nun wird der Ausgang sein:

[[[11 13]] 

[[51 53]]] 

Dies liegt daran, das Schreiten beginnt von [0,0,0] und geht an [2,1,2] alle nicht existierende Daten wie Verwerfen:

[[0,0,0], [0,0,2], [0,2,0], [0,2,2], 
[2,0,0], [2,0,2], [2,2,0], [2,2,2]] 

Wenn Sie [1,1,1] verwenden, wie Fortschritte dann wird einfach Drucke alle Werte aus.