Ragged Tensor, der Daten variabler Länge darstellt, die in TensorFlow 2.1 oder höher eingeführt wurden. Wenn Sie jedoch versuchen, mit normalem Tensor-Kleber zu schreiben, gibt es verschiedene Ich bin süchtig danach. Diesmal die Fensterverarbeitungsversion, die wahrscheinlich für die Signalverarbeitung verwendet wird. Ein Rahmen mit einer bestimmten Zeitbreite wird nach und nach verschoben, um eine Wellenform zu extrahieren, die in den Bereich des Rahmens fällt.
Wenn wir uns "x" als Stapel vorstellen, werden wir für jede Datenzeile einen kurzen Abschnitt der Wellenform ausschneiden. Die Länge der Daten variiert.
Hier wird die Rahmenbreite auf 2 gesetzt und die Ausschnittposition um 1 verschoben.
[3, 1, 4, 1]
ist wie [[3, 1], [1, 4], [4, 1]]
.
Für den üblichen "Tensor" gibt es eine praktische Funktion namens tf.signal.frame, aber leider " Es kann nicht für "RaggedTensor" verwendet werden.
x = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])
print(tf.signal.frame(x, 2, 1)) # NG
# ValueError: TypeError: object of type 'RaggedTensor' has no len()
print(tf.signal.frame(x.to_tensor(), 2, 1)) #Es funktioniert, aber es kommen viele zusätzliche Nullen heraus
# tf.Tensor(
# [[[3 1]
# [1 4]
# [4 1]]
#
# [[0 0]
# [0 0]
# [0 0]]
#
# [[5 9]
# [9 2]
# [2 0]]
#
# [[6 0]
# [0 0]
# [0 0]]
#
# [[0 0]
# [0 0]
# [0 0]]], shape=(5, 3, 2), dtype=int32)
Basierend auf "x.values", das die Werte darstellt, die aus der Chargendimension abgeflacht sind, sowie die Länge und den Versatz jeder Zeile, die von "RaggedTensor" erhalten wurden.
print(x.values) #Tensor mit Werten
# tf.Tensor([3 1 4 1 5 9 2 6], shape=(8,), dtype=int32)
print(x.row_starts()) #Startindex (Offset) jeder Zeile in Werten
# tf.Tensor([0 4 4 7 8], shape=(5,), dtype=int64)
print(x.row_lengths()) #Länge jeder Zeile
# tf.Tensor([4 0 3 1 0], shape=(5,), dtype=int64)
Überlegen Sie für jede Zeile von "x", aus welchem Index von "x.values" die Werte entnommen werden sollen (*).
Zunächst einmal, wenn Sie einen RaggedTensor
erstellen, der den ersten Index von (*) hat.
s = x.row_starts()
e = s + x.row_lengths() - 1
r = tf.ragged.range(s, e)
print(r)
# <tf.RaggedTensor [[0, 1, 2], [], [4, 5], [], []]>
Wenn Sie diejenigen kombinieren, die um einen Index erweitert wurden, können Sie außerdem sehen, wo Sie in "x.values" die Werte für das erwartete Ergebnis nach der Fensterverarbeitung bringen sollten. Die Ergebnisse entsprechen dem vorherigen Bulletin (*).
ind = tf.stack([r, r+1], axis=2)
print(ind)
# <tf.RaggedTensor [[[0, 1], [1, 2], [2, 3]], [], [[4, 5], [5, 6]], [], []]>
Danach können Sie tf.gather ()
verwenden, um die Werte von x.values
basierend auf dem in ind
eingegebenen Index abzurufen.
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1], [1, 4], [4, 1]], [], [[5, 9], [9, 2]], [], []]>
Die Art und Weise, "e" und "ind" zu machen, ist etwas anders, aber die allgemeine Idee ist dieselbe. Broadcast wird verwendet, um "ind" zu erstellen. Zu diesem Zweck wird am Ende eine Dimension der Länge 1 als "r [:,:, tf.newaxis]" hinzugefügt.
len_frame = 3
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1, 4], [1, 4, 1]], [], [[5, 9, 2]], [], []]>
Natürlich kann es auch verwendet werden, wenn len_frame = 2
.
Es ist in Ordnung, wenn Sie die Schrittgröße von r
ändern.
len_frame = 2
shift_frame = 2
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e, shift_frame)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[3, 1], [4, 1]], [], [[5, 9]], [], []]>
Sie können auch shift_frame = 1
verwenden.
Beispielsweise werden in Stereo-Audio die L- und R-Werte als Paar gespeichert.
x = tf.ragged.constant([[[3, 2], [1, 7], [4, 1], [1, 8]], [], [[5, 2], [9, 8], [2, 1]], [[6, 8]], []])
Tatsächlich funktioniert es genauso wie zuvor.
len_frame = 2
shift_frame = 1
s = x.row_starts()
e = s + x.row_lengths() + 1 - len_frame
r = tf.ragged.range(s, e, shift_frame)
ind = r[:, :, tf.newaxis] + tf.range(0, len_frame, dtype="int64")
ret = tf.gather(x.values, ind)
print(ret)
# <tf.RaggedTensor [[[[3, 2], [1, 7]], [[1, 7], [4, 1]], [[4, 1], [1, 8]]], [], [[[5, 2], [9, 8]], [[9, 8], [2, 1]]], [], []]>
Die Anzahl der Dimensionen hat so stark zugenommen, dass ich nicht sagen kann, ob es passt, wenn ich es mir nur ansehe, aber es sollte in Ordnung sein ...
Recommended Posts