Ragged Tensor, der Daten variabler Länge darstellt, die in TensorFlow 2.1 oder höher eingeführt wurden, aber beim Versuch, mit gewöhnlichem Tensor-Kleber zu schreiben, verschiedene Ich bin süchtig danach.
Diesmal ist Indizierung. Versuchen Sie, den Wert von RaggedTensor
abzurufen, indem Sie einen bestimmten Index angeben. Wenn Sie sich daran gewöhnt haben, können Sie komplizierte Operationen ausführen ...
Angenommen, x
wird als RaggedTensor
erstellt, der wie folgt indiziert werden soll.
x = tf.RaggedTensor.from_row_lengths(tf.range(15), tf.range(1, 6))
print(x)
# <tf.RaggedTensor [[0], [1, 2], [3, 4, 5], [6, 7, 8, 9], [10, 11, 12, 13, 14]]>
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | 0 | ||||
Die erste Zeile | 1 | 2 | |||
2. Zeile | 3 | 4 | 5 | ||
3. Zeile | 6 | 7 | 8 | 9 | |
4. Zeile | 10 | 11 | 12 | 13 | 14 |
Die erste Operation besteht darin, eine Zeile abzurufen, die der eines normalen "Tensors" entspricht. Sie können es sich als "numpy.ndarray" vorstellen. Wenn Sie einen Bereich angeben, enthält ** den ersten Index und nicht den letzten Index. ** Wenn Sie ein Python-Benutzer sind, gibt es meines Erachtens kein Problem.
print(x[2])
# tf.Tensor([3 4 5], shape=(3,), dtype=int32)
print(x[1:4])
# <tf.RaggedTensor [[1, 2], [3, 4, 5], [6, 7, 8, 9]]>
Im Gegensatz zu "numpy.ndarray" scheint es jedoch nicht möglich zu sein, Slicing zu verwenden, das diskrete Zeilen angibt.
#Dies kann für ndarray durchgeführt werden
print(x.numpy()[[1, 3]])
# [array([1, 2], dtype=int32) array([6, 7, 8, 9], dtype=int32)]
# Tensor/Nicht verfügbar für Ragged Tensor
print(x[[1, 3]])
# InvalidArgumentError: slice index 3 of dimension 0 out of bounds. [Op:StridedSlice] name: strided_slice/
Bitte gehen Sie stattdessen hierher.
# Tensor/Ausgefallene Indizierung mit Ragged Tensor
print(tf.gather(x, [1, 3], axis=0))
# <tf.RaggedTensor [[1, 2], [6, 7, 8, 9]]>
Das Folgende ist ein Beispiel für das Schneiden mit einem festen Spaltenindex.
Im Gegensatz zu gewöhnlichem Tensor
hängt es von der Zeile ab, ob es ein Element des Index gibt oder nicht, also einfach
print(x[:, 2])
# ValueError: Cannot index into an inner ragged dimension.
Es ist nicht möglich, wie zu tun. Wenn Sie den Bereich angeben
print(x[:, 2:3])
# <tf.RaggedTensor [[], [], [5], [8], [12]]>
Es funktioniert wie. Es ist []
für die Zeile, in der der angegebene Index nicht existiert.
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | 0 | ||||
Die erste Zeile | 1 | 2 | |||
2. Zeile | 3 | 4 | 5 | ||
3. Zeile | 6 | 7 | 8 | 9 | |
4. Zeile | 10 | 11 | 12 | 13 | 14 |
Wenn Sie einen Tensor
haben, der die zweidimensionalen Indizes auflistet, die Sie sammeln möchten, können Sie tf.gather_nd ()
verwenden.
ind = tf.constant([[0, 0], [1, 1], [2, 0], [4, 3]])
#x(0, 0), (1, 1), (2, 0), (4, 3)Ich möchte Elemente sammeln
print(tf.gather_nd(x, ind))
# tf.Tensor([ 0 2 3 13], shape=(4,), dtype=int32)
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | 0 | ||||
Die erste Zeile | 1 | 2 | |||
2. Zeile | 3 | 4 | 5 | ||
3. Zeile | 6 | 7 | 8 | 9 | |
4. Zeile | 10 | 11 | 12 | 13 | 14 |
Andererseits rufe ich ein Element für jede Zeile ab, aber ich denke, es gibt Zeiten, in denen Sie aus verschiedenen Spalten abrufen möchten.
col = tf.constant([0, 0, 2, 1, 2])
#x(0, 0), (1, 0), (2, 2), (3, 1), (4, 2)Ich möchte Elemente sammeln
#Fügen Sie dem Index Zeilennummern hinzu und verwenden Sie dann dieselbe Methode wie zuvor
ind = tf.transpose(tf.stack([tf.range(tf.shape(col)[0]), col]))
print(tf.gather_nd(x, ind))
# tf.Tensor([ 0 1 5 7 12], shape=(5,), dtype=int32)
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | 0 | ||||
Die erste Zeile | 1 | 2 | |||
2. Zeile | 3 | 4 | 5 | ||
3. Zeile | 6 | 7 | 8 | 9 | |
4. Zeile | 10 | 11 | 12 | 13 | 14 |
Aber ich habe das Gefühl, dass es spät sein wird, also habe ich über einen intelligenteren Weg nachgedacht.
print(tf.gather(x.values, x.row_starts() + col))
# tf.Tensor([ 0 1 5 7 12], shape=(5,), dtype=int32)
Das ist in Ordnung.
Der tatsächliche Wert von "x" ist in "Tensor" (nicht "RaggedTensor") enthalten, der jede Linie verbindet (eine Dimension weniger) und durch Zugriff auf "x.values" erhalten werden kann. Ich werde. Es enthält auch Informationen über den Startindex jeder Zeile (x.row_starts ()
), um die Form von x
darzustellen. Daher können Sie den angegebenen Offset zu diesem Index hinzufügen und gegen "x.values" schneiden.
%timeit tf.gather_nd(x, tf.transpose(tf.stack([tf.range(tf.shape(col)[0]), col])))
# 739 µs ± 75.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
%timeit tf.gather(x.values, x.row_starts() + col)
# 124 µs ± 6.47 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
Dieser ist schneller (^_^)
Wenn Sie die Operation hier beherrschen möchten, ist es gut, das offizielle Dokument zu sehen.
Wenden Sie das obige "die Substanz des Wertes ist in dem eindimensionalen" Tensor "" an.
col = tf.ragged.constant([[0], [], [0, 2], [1, 3], [2]])
#x(0, 0), (2, 0), (2, 2), (3, 1), (3, 3), (4, 2)Ich möchte Elemente sammeln
#Holen Sie sich den Startindex jeder Zeile von x
row_starts = tf.cast(x.row_starts(), "int32")
#Rufen Sie die Zeilennummer ab, zu der jede Komponente von col gehört, konvertieren Sie sie in den Startindex bei x und fügen Sie den Offset hinzu
ind_flat = tf.gather(row_starts, col.value_rowids()) + col.values
ret = tf.gather(x.values, ind_flat)
print(ret)
# tf.Tensor([ 0 3 5 7 9 12], shape=(6,), dtype=int32)
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | 0 | ||||
Die erste Zeile | 1 | 2 | |||
2. Zeile | 3 | 4 | 5 | ||
3. Zeile | 6 | 7 | 8 | 9 | |
4. Zeile | 10 | 11 | 12 | 13 | 14 |
Das obige Ergebnis ist ein normaler "Tensor" mit den aufgelisteten Werten, und die Informationen in der ursprünglichen Zeile gehen verloren. Was ist jedoch, wenn Sie die Zeileninformationen speichern möchten?
Sie können einen RaggedTensor
erstellen, indem Sie dem Tensor
Informationen über den Zeilenstartindex geben. Die Länge jeder Zeile sollte mit col
übereinstimmen, damit Sie diesen Startindex von col.value_rowids ()
erhalten können.
print(tf.RaggedTensor.from_value_rowids(ret, col.value_rowids()))
# <tf.RaggedTensor [[0], [], [3, 5], [7, 9], [12]]>
Selbst wenn Daten mit 2 oder mehr Dimensionen in chronologischer Reihenfolge angeordnet sind (3 oder mehr Dimensionen für "RaggedTensor" einschließlich Chargenabmessungen), kann die vorhandene Methode unverändert verwendet werden.
x = tf.RaggedTensor.from_row_lengths(tf.reshape(tf.range(30), (15, 2)), tf.range(1, 6))
print(x)
# <tf.RaggedTensor [[[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]]]>
Die Struktur dieses "x" kann wie folgt interpretiert werden.
Spaltenindex | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
Zeile 0 | [0, 1] | ||||
Die erste Zeile | [2, 3] | [4, 5] | |||
2. Zeile | [6, 7] | [8, 9] | [10, 11] | ||
3. Zeile | [12, 13] | [14, 15] | [16, 17] | [18, 19] | |
4. Zeile | [20, 21] | [22, 23] | [24, 25] | [26, 27] | [28, 29] |
Der Rest ist genau der gleiche wie zuvor. Bitte beachten Sie jedoch, dass der zurückgegebene "Tensor" zweidimensional ist.
ind = tf.constant([[0, 0], [1, 1], [2, 0], [4, 3]])
#x(0, 0), (1, 1), (2, 0), (4, 3)Ich möchte Elemente sammeln
print(tf.gather_nd(x, ind))
# tf.Tensor(
# [[ 0 1]
# [ 4 5]
# [ 6 7]
# [26 27]], shape=(4, 2), dtype=int32)
col = tf.constant([0, 0, 2, 1, 2])
#x(0, 0), (1, 0), (2, 2), (3, 1), (4, 2)Ich möchte Elemente sammeln
print(tf.gather(x.values, x.row_starts() + col))
# tf.Tensor(
# [[ 0 1]
# [ 2 3]
# [10 11]
# [14 15]
# [24 25]], shape=(5, 2), dtype=int32)
col = tf.ragged.constant([[0], [], [0, 2], [1, 3], [2]])
#x(0, 0), (2, 0), (2, 2), (3, 1), (3, 3), (4, 2)Ich möchte Elemente sammeln
#Holen Sie sich den Startindex jeder Zeile von x
row_starts = tf.cast(x.row_starts(), "int32")
#Rufen Sie die Zeilennummer ab, zu der jede Komponente von col gehört, konvertieren Sie sie in den Startindex bei x und fügen Sie den Offset hinzu
ind_flat = tf.gather(row_starts, col.value_rowids()) + col.values
ret = tf.gather(x.values, ind_flat)
print(ret)
# tf.Tensor(
# [[ 0 1]
# [ 6 7]
# [10 11]
# [14 15]
# [18 19]
# [24 25]], shape=(6, 2), dtype=int32)
#Wenn Sie die Informationen der ursprünglichen Zeile speichern möchten
print(tf.RaggedTensor.from_value_rowids(ret, col.value_rowids()))
# <tf.RaggedTensor [[[0, 1]], [], [[6, 7], [10, 11]], [[14, 15], [18, 19]], [[24, 25]]]>
Recommended Posts