Diese Seite wurde von der Cloud Translation API übersetzt.
Switch to English

Zackige Tensoren

Ansicht auf TensorFlow.org In Google Colab ausführen Quelle auf GitHub anzeigen Notizbuch herunterladen

Konfiguration

 import math
import tensorflow as tf
 

Überblick

Ihre Daten kommen in vielen Formen vor; Ihre Tensoren sollten auch. Zackige Tensoren sind das TensorFlow-Äquivalent zu verschachtelten Listen variabler Länge. Sie erleichtern das Speichern und Verarbeiten von Daten mit ungleichmäßigen Formen, einschließlich:

  • Funktionen mit variabler Länge, z. B. die Anzahl der Schauspieler in einem Film.
  • Stapel von sequentiellen Eingaben variabler Länge, z. B. Sätze oder Videoclips.
  • Hierarchische Eingaben, z. B. Textdokumente, die in Abschnitte, Absätze, Sätze und Wörter unterteilt sind.
  • Einzelne Felder in strukturierten Eingaben, z. B. Protokollpuffer.

Was kann man mit einem zerlumpten Tensor machen?

Ragged Tensoren werden von mehr als hundert TensorFlow-Operationen unterstützt, einschließlich mathematischer Operationen (wie tf.add und tf.reduce_mean ), Array-Operationen (wie tf.concat und tf.tile ) und String-Manipulationsoperationen (wie tf.substr ), Kontrollflussoperationen (wie tf.while_loop und tf.map_fn ) und viele andere:

 digits = tf.ragged.constant([[3, 1, 4, 1], [], [5, 9, 2], [6], []])
words = tf.ragged.constant([["So", "long"], ["thanks", "for", "all", "the", "fish"]])
print(tf.add(digits, 3))
print(tf.reduce_mean(digits, axis=1))
print(tf.concat([digits, [[5, 3]]], axis=0))
print(tf.tile(digits, [1, 2]))
print(tf.strings.substr(words, 0, 2))
print(tf.map_fn(tf.math.square, digits))
 
<tf.RaggedTensor [[6, 4, 7, 4], [], [8, 12, 5], [9], []]>
tf.Tensor([2.25              nan 5.33333333 6.                nan], shape=(5,), dtype=float64)
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9, 2], [6], [], [5, 3]]>
<tf.RaggedTensor [[3, 1, 4, 1, 3, 1, 4, 1], [], [5, 9, 2, 5, 9, 2], [6, 6], []]>
<tf.RaggedTensor [[b'So', b'lo'], [b'th', b'fo', b'al', b'th', b'fi']]>
<tf.RaggedTensor [[9, 1, 16, 1], [], [25, 81, 4], [36], []]>

Es gibt auch eine Reihe von Methoden und Operationen, die für zerlumpte Tensoren spezifisch sind, einschließlich Factory-Methoden, Konvertierungsmethoden und Wertzuordnungsoperationen. Eine Liste der unterstützten tf.ragged Dokumentation zum tf.ragged Paket .

Ragged Tensoren werden von vielen TensorFlow-APIs unterstützt, einschließlich Keras , Datasets , tf.function , SavedModels und tf.Example . Weitere Informationen finden Sie im folgenden Abschnitt zu TensorFlow-APIs .

Wie bei normalen Tensoren können Sie die Python-Indizierung verwenden, um auf bestimmte Segmente eines zerlumpten Tensors zuzugreifen. Weitere Informationen finden Sie im folgenden Abschnitt zur Indizierung .

 print(digits[0])       # First row
 
tf.Tensor([3 1 4 1], shape=(4,), dtype=int32)

 print(digits[:, :2])   # First two values in each row.
 
<tf.RaggedTensor [[3, 1], [], [5, 9], [6], []]>

 print(digits[:, -2:])  # Last two values in each row.
 
<tf.RaggedTensor [[4, 1], [], [9, 2], [6], []]>

Und genau wie bei normalen Tensoren können Sie Python-Arithmetik- und Vergleichsoperatoren verwenden, um elementweise Operationen auszuführen. Weitere Informationen finden Sie im folgenden Abschnitt über überladene Operatoren .

 print(digits + 3)
 
<tf.RaggedTensor [[6, 4, 7, 4], [], [8, 12, 5], [9], []]>

 print(digits + tf.ragged.constant([[1, 2, 3, 4], [], [5, 6, 7], [8], []]))
 
<tf.RaggedTensor [[4, 3, 7, 5], [], [10, 15, 9], [14], []]>

Wenn Sie eine elementweise Transformation zu den Werten eines RaggedTensor , können Sie tf.ragged.map_flat_values , das eine Funktion plus ein oder mehrere Argumente verwendet und die Funktion zum Transformieren der Werte des RaggedTensor .

 times_two_plus_one = lambda x: x * 2 + 1
print(tf.ragged.map_flat_values(times_two_plus_one, digits))
 
<tf.RaggedTensor [[7, 3, 9, 3], [], [11, 19, 5], [13], []]>

Ragged Tensoren können in verschachtelte Python- list und Numpy- array konvertiert werden:

 digits.to_list()
 
[[3, 1, 4, 1], [], [5, 9, 2], [6], []]
 digits.numpy()
 
array([array([3, 1, 4, 1], dtype=int32), array([], dtype=int32),
       array([5, 9, 2], dtype=int32), array([6], dtype=int32),
       array([], dtype=int32)], dtype=object)

Aufbau eines zerlumpten Tensors

Der einfachste Weg, einen zerlumpten Tensor zu tf.ragged.constant , ist die Verwendung von tf.ragged.constant , mit der der RaggedTensor , der einer bestimmten verschachtelten Python- list oder einem bestimmten numpy- array :

 sentences = tf.ragged.constant([
    ["Let's", "build", "some", "ragged", "tensors", "!"],
    ["We", "can", "use", "tf.ragged.constant", "."]])
print(sentences)
 
<tf.RaggedTensor [[b"Let's", b'build', b'some', b'ragged', b'tensors', b'!'], [b'We', b'can', b'use', b'tf.ragged.constant', b'.']]>

 paragraphs = tf.ragged.constant([
    [['I', 'have', 'a', 'cat'], ['His', 'name', 'is', 'Mat']],
    [['Do', 'you', 'want', 'to', 'come', 'visit'], ["I'm", 'free', 'tomorrow']],
])
print(paragraphs)
 
<tf.RaggedTensor [[[b'I', b'have', b'a', b'cat'], [b'His', b'name', b'is', b'Mat']], [[b'Do', b'you', b'want', b'to', b'come', b'visit'], [b"I'm", b'free', b'tomorrow']]]>

Ragged Tensoren können auch durch Paarung flache Werte Tensoren mit Zeilen Partitionieren Tensoren der angibt , wie die Werte , konstruiert werden sollte in Reihen unterteilt werden, Fabrikclass Verwendung wie tf.RaggedTensor.from_value_rowids , tf.RaggedTensor.from_row_lengths und tf.RaggedTensor.from_row_splits .

tf.RaggedTensor.from_value_rowids

Wenn Sie wissen, zu welcher Zeile jeder Wert gehört, können Sie einen RaggedTensor mithilfe eines value_rowids RaggedTensor value_rowids :

value_rowids

 print(tf.RaggedTensor.from_value_rowids(
    values=[3, 1, 4, 1, 5, 9, 2],
    value_rowids=[0, 0, 0, 0, 2, 2, 3]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

tf.RaggedTensor.from_row_lengths

Wenn Sie wissen, wie lang jede Zeile ist, können Sie einen row_lengths :

Zeilenlängen

 print(tf.RaggedTensor.from_row_lengths(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_lengths=[4, 0, 2, 1]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

tf.RaggedTensor.from_row_splits

Wenn Sie den Index kennen, in dem jede Zeile beginnt und endet, können Sie einen row_splits :

row_splits

 print(tf.RaggedTensor.from_row_splits(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_splits=[0, 4, 4, 6, 7]))
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

Eine vollständige Liste der Factory-Methoden finden Sie in der Dokumentation zur tf.RaggedTensor Klasse.

Was Sie in einem zerlumpten Tensor aufbewahren können

Wie bei normaler Tensor s, die Werte in einer RaggedTensor müssen alle die gleiche Art; und die Werte müssen alle dieselbe Verschachtelungstiefe haben ( Rang des Tensors):

 print(tf.ragged.constant([["Hi"], ["How", "are", "you"]]))  # ok: type=string, rank=2
 
<tf.RaggedTensor [[b'Hi'], [b'How', b'are', b'you']]>

 print(tf.ragged.constant([[[1, 2], [3]], [[4, 5]]]))        # ok: type=int32, rank=3
 
<tf.RaggedTensor [[[1, 2], [3]], [[4, 5]]]>

 try:
  tf.ragged.constant([["one", "two"], [3, 4]])              # bad: multiple types
except ValueError as exception:
  print(exception)
 
Can't convert Python sequence with mixed types to Tensor.

 try:
  tf.ragged.constant(["A", ["B", "C"]])                     # bad: multiple nesting depths
except ValueError as exception:
  print(exception)
 
all scalar values must have the same nesting depth

Beispiel Anwendungsfall

Das folgende Beispiel zeigt, wie RaggedTensor verwendet werden können, um Unigramm- und Bigram-Einbettungen für einen Stapel von Abfragen variabler Länge zu erstellen und zu kombinieren, wobei spezielle Markierungen für den Anfang und das Ende jedes Satzes verwendet werden. Weitere Informationen zu den in diesem Beispiel verwendeten tf.ragged Dokumentation zum Paket tf.ragged .

 queries = tf.ragged.constant([['Who', 'is', 'Dan', 'Smith'],
                              ['Pause'],
                              ['Will', 'it', 'rain', 'later', 'today']])

# Create an embedding table.
num_buckets = 1024
embedding_size = 4
embedding_table = tf.Variable(
    tf.random.truncated_normal([num_buckets, embedding_size],
                       stddev=1.0 / math.sqrt(embedding_size)))

# Look up the embedding for each word.
word_buckets = tf.strings.to_hash_bucket_fast(queries, num_buckets)
word_embeddings = tf.nn.embedding_lookup(embedding_table, word_buckets)     # ①

# Add markers to the beginning and end of each sentence.
marker = tf.fill([queries.nrows(), 1], '#')
padded = tf.concat([marker, queries, marker], axis=1)                       # ②

# Build word bigrams & look up embeddings.
bigrams = tf.strings.join([padded[:, :-1], padded[:, 1:]], separator='+')   # ③

bigram_buckets = tf.strings.to_hash_bucket_fast(bigrams, num_buckets)
bigram_embeddings = tf.nn.embedding_lookup(embedding_table, bigram_buckets) # ④

# Find the average embedding for each sentence
all_embeddings = tf.concat([word_embeddings, bigram_embeddings], axis=1)    # ⑤
avg_embedding = tf.reduce_mean(all_embeddings, axis=1)                      # ⑥
print(avg_embedding)
 
tf.Tensor(
[[ 0.16960017  0.2668903  -0.00337404 -0.11874141]
 [-0.23676081 -0.09729008 -0.16816251  0.11000428]
 [ 0.13829643 -0.02088889  0.02651778  0.02251156]], shape=(3, 4), dtype=float32)

ragged_example

Zackige und gleichmäßige Abmessungen

Eine ausgefranste Dimension ist eine Dimension, deren Scheiben unterschiedliche Längen haben können. Zum Beispiel ist die innere (Spalten-) Dimension von rt=[[3, 1, 4, 1], [], [5, 9, 2], [6], []] unregelmäßig, da die Spaltenschnitte ( rt[0, :] , ..., rt[4, :] ) haben unterschiedliche Längen. Dimensionen, deren Scheiben alle die gleiche Länge haben, werden als einheitliche Dimensionen bezeichnet .

Die äußerste Abmessung eines zerlumpten Tensors ist immer gleichmäßig, da er aus einer einzelnen Schicht besteht (und daher keine Möglichkeit für unterschiedliche Schichtlängen besteht). Die verbleibenden Abmessungen können entweder zackig oder gleichmäßig sein. Beispielsweise können wir die [num_sentences, (num_words), embedding_size] für jedes Wort in einer Reihe von Sätzen unter Verwendung eines zerlumpten Tensors mit der Form [num_sentences, (num_words), embedding_size] , wobei die Klammern um (num_words) angeben, dass die Dimension (num_words) ist.

sent_word_embed

Zackige Tensoren können mehrere zackige Abmessungen haben. Zum Beispiel könnten wir einen Stapel strukturierter Textdokumente unter Verwendung eines Tensors mit der Form [num_documents, (num_paragraphs), (num_sentences), (num_words)] (wobei wiederum Klammern verwendet werden, um unregelmäßige Dimensionen anzuzeigen).

Wie bei tf.Tensor ist der Rang eines zerlumpten Tensors die Gesamtzahl der Dimensionen (einschließlich sowohl zerlumpter als auch gleichmäßiger Dimensionen). Ein potenziell zerlumpter Tensor ist ein Wert, der entweder ein tf.Tensor oder ein tf.RaggedTensor .

Bei der Beschreibung der Form eines RaggedTensors werden unregelmäßige Abmessungen herkömmlicherweise angegeben, indem sie in Klammern eingeschlossen werden. Wie wir oben gesehen haben, kann die Form eines 3-D-RaggedTensors, der Worteinbettungen für jedes Wort in einer Reihe von Sätzen [num_sentences, (num_words), embedding_size] beispielsweise als [num_sentences, (num_words), embedding_size] .

Das Attribut RaggedTensor.shape gibt eine tf.TensorShape für einen zerlumpten Tensor zurück, wobei ausgefranste Dimensionen die Größe None :

 tf.ragged.constant([["Hi"], ["How", "are", "you"]]).shape
 
TensorShape([2, None])

Die Methode tf.RaggedTensor.bounding_shape kann verwendet werden, um eine enge Begrenzungsform für einen bestimmten RaggedTensor :

 print(tf.ragged.constant([["Hi"], ["How", "are", "you"]]).bounding_shape())
 
tf.Tensor([2 3], shape=(2,), dtype=int64)

Zackig gegen spärlich

Ein zerlumpter Tensor sollte nicht als eine Art spärlicher Tensor angesehen werden. Insbesondere spärliche Tensoren sind effiziente Codierungen für tf.Tensor , die dieselben Daten in einem kompakten Format modellieren. Der zerlumpte Tensor ist jedoch eine Erweiterung von tf.Tensor , der eine erweiterte Datenklasse modelliert. Dieser Unterschied ist entscheidend für die Definition von Operationen:

  • Das Anwenden einer Operation auf einen spärlichen oder dichten Tensor sollte immer das gleiche Ergebnis liefern.
  • Das Anwenden einer Operation auf einen zerlumpten oder spärlichen Tensor kann zu unterschiedlichen Ergebnissen führen.

Betrachten Sie als anschauliches Beispiel, wie Array-Operationen wie concat , stack und tile für zerlumpte oder spärliche Tensoren definiert sind. Verkettete zerlumpte Tensoren verbinden jede Reihe zu einer einzigen Reihe mit der kombinierten Länge:

ragged_concat

 ragged_x = tf.ragged.constant([["John"], ["a", "big", "dog"], ["my", "cat"]])
ragged_y = tf.ragged.constant([["fell", "asleep"], ["barked"], ["is", "fuzzy"]])
print(tf.concat([ragged_x, ragged_y], axis=1))
 
<tf.RaggedTensor [[b'John', b'fell', b'asleep'], [b'a', b'big', b'dog', b'barked'], [b'my', b'cat', b'is', b'fuzzy']]>

Das Verketten von spärlichen Tensoren entspricht jedoch dem Verketten der entsprechenden dichten Tensoren, wie im folgenden Beispiel dargestellt (wobei Ø auf fehlende Werte hinweist):

sparse_concat

 sparse_x = ragged_x.to_sparse()
sparse_y = ragged_y.to_sparse()
sparse_result = tf.sparse.concat(sp_inputs=[sparse_x, sparse_y], axis=1)
print(tf.sparse.to_dense(sparse_result, ''))
 
tf.Tensor(
[[b'John' b'' b'' b'fell' b'asleep']
 [b'a' b'big' b'dog' b'barked' b'']
 [b'my' b'cat' b'' b'is' b'fuzzy']], shape=(3, 5), dtype=string)

Als weiteres Beispiel dafür, warum diese Unterscheidung wichtig ist, betrachten Sie die Definition des „Mittelwerts jeder Zeile“ für eine tf.reduce_mean wie tf.reduce_mean . Bei einem zerlumpten Tensor ist der Mittelwert für eine Zeile die Summe der Zeilenwerte geteilt durch die Zeilenbreite. Bei einem spärlichen Tensor ist der Mittelwert für eine Zeile die Summe der Zeilenwerte geteilt durch die Gesamtbreite des spärlichen Tensors (die größer oder gleich der Breite der längsten Zeile ist).

TensorFlow-APIs

Keras

tf.keras ist die High-Level-API von TensorFlow zum Erstellen und Trainieren von Deep-Learning-Modellen. Ragged Tensoren können als Eingaben an ein Keras-Modell übergeben werden, indem ragged=True für tf.keras.Input oder tf.keras.layers.InputLayer . Unregelmäßige Tensoren können auch zwischen Keras-Ebenen übertragen und von Keras-Modellen zurückgegeben werden. Das folgende Beispiel zeigt ein Spielzeug-LSTM-Modell, das mit zerlumpten Tensoren trainiert wird.

 # Task: predict whether each sentence is a question or not.
sentences = tf.constant(
    ['What makes you think she is a witch?',
     'She turned me into a newt.',
     'A newt?',
     'Well, I got better.'])
is_question = tf.constant([True, False, True, False])

# Preprocess the input strings.
hash_buckets = 1000
words = tf.strings.split(sentences, ' ')
hashed_words = tf.strings.to_hash_bucket_fast(words, hash_buckets)

# Build the Keras model.
keras_model = tf.keras.Sequential([
    tf.keras.layers.Input(shape=[None], dtype=tf.int64, ragged=True),
    tf.keras.layers.Embedding(hash_buckets, 16),
    tf.keras.layers.LSTM(32, use_bias=False),
    tf.keras.layers.Dense(32),
    tf.keras.layers.Activation(tf.nn.relu),
    tf.keras.layers.Dense(1)
])

keras_model.compile(loss='binary_crossentropy', optimizer='rmsprop')
keras_model.fit(hashed_words, is_question, epochs=5)
print(keras_model.predict(hashed_words))
 
WARNING:tensorflow:Layer lstm will not use cuDNN kernel since it doesn't meet the cuDNN kernel criteria. It will use generic GPU kernel as fallback when running on GPU
Epoch 1/5

/tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/framework/indexed_slices.py:432: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.
  "Converting sparse IndexedSlices to a dense Tensor of unknown shape. "

1/1 [==============================] - 0s 1ms/step - loss: 5.2951
Epoch 2/5
1/1 [==============================] - 0s 943us/step - loss: 2.2362
Epoch 3/5
1/1 [==============================] - 0s 879us/step - loss: 1.8742
Epoch 4/5
1/1 [==============================] - 0s 809us/step - loss: 1.7786
Epoch 5/5
1/1 [==============================] - 0s 869us/step - loss: 1.7076
[[0.04364644]
 [0.01928963]
 [0.03224095]
 [0.01768562]]

Beispiel

Beispiel ist eine Standard- Protobuf- Codierung für TensorFlow-Daten. Mit tf.Example codierte Daten tf.Example häufig Features variabler Länge. Der folgende Code definiert beispielsweise einen Stapel von vier tf.Example mit unterschiedlichen Funktionslängen:

 import google.protobuf.text_format as pbtext

def build_tf_example(s):
  return pbtext.Merge(s, tf.train.Example()).SerializeToString()

example_batch = [
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["red", "blue"]} } }
      feature {key: "lengths" value {int64_list {value: [7]} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["orange"]} } }
      feature {key: "lengths" value {int64_list {value: []} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["black", "yellow"]} } }
      feature {key: "lengths" value {int64_list {value: [1, 3]} } } }'''),
  build_tf_example(r'''
    features {
      feature {key: "colors" value {bytes_list {value: ["green"]} } }
      feature {key: "lengths" value {int64_list {value: [3, 5, 2]} } } }''')]
 

Wir können diese codierten Daten mit tf.io.parse_example , das einen Tensor aus serialisierten Zeichenfolgen und ein Feature-Spezifikationswörterbuch verwendet und ein Wörterbuch zurückgibt, das Feature-Namen an Tensoren abbildet. Um die Features variabler Länge in tf.io.RaggedFeature Tensoren tf.io.RaggedFeature , verwenden wir einfach tf.io.RaggedFeature im Feature-Spezifikationswörterbuch:

 feature_specification = {
    'colors': tf.io.RaggedFeature(tf.string),
    'lengths': tf.io.RaggedFeature(tf.int64),
}
feature_tensors = tf.io.parse_example(example_batch, feature_specification)
for name, value in feature_tensors.items():
  print("{}={}".format(name, value))
 
colors=<tf.RaggedTensor [[b'red', b'blue'], [b'orange'], [b'black', b'yellow'], [b'green']]>
lengths=<tf.RaggedTensor [[7], [], [1, 3], [3, 5, 2]]>

tf.io.RaggedFeature kann auch zum Lesen von Features mit mehreren unregelmäßigen Dimensionen verwendet werden. Einzelheiten finden Sie in der API-Dokumentation .

Datensätze

tf.data ist eine API, mit der Sie komplexe Eingabe-Pipelines aus einfachen, wiederverwendbaren Teilen erstellen können. Die Kerndatenstruktur ist tf.data.Dataset , die eine Folge von Elementen darstellt, in denen jedes Element aus einer oder mehreren Komponenten besteht.

 # Helper function used to print datasets in the examples below.
def print_dictionary_dataset(dataset):
  for i, element in enumerate(dataset):
    print("Element {}:".format(i))
    for (feature_name, feature_value) in element.items():
      print('{:>14} = {}'.format(feature_name, feature_value))
 

Erstellen von Datensätzen mit zerlumpten Tensoren

Datensätze können aus zerlumpten Tensoren mit denselben Methoden erstellt werden, mit denen sie aus tf.Tensor oder Numpy- array , z. B. Dataset.from_tensor_slices :

 dataset = tf.data.Dataset.from_tensor_slices(feature_tensors)
print_dictionary_dataset(dataset)
 
Element 0:
        colors = [b'red' b'blue']
       lengths = [7]
Element 1:
        colors = [b'orange']
       lengths = []
Element 2:
        colors = [b'black' b'yellow']
       lengths = [1 3]
Element 3:
        colors = [b'green']
       lengths = [3 5 2]

Datensätze mit zerlumpten Tensoren stapeln und entpacken

Datensätze mit ausgefransten Tensoren können mithilfe der Dataset.batch Methode gestapelt werden (wobei n aufeinanderfolgende Elemente zu einem einzigen Element Dataset.batch werden).

 batched_dataset = dataset.batch(2)
print_dictionary_dataset(batched_dataset)
 
Element 0:
        colors = <tf.RaggedTensor [[b'red', b'blue'], [b'orange']]>
       lengths = <tf.RaggedTensor [[7], []]>
Element 1:
        colors = <tf.RaggedTensor [[b'black', b'yellow'], [b'green']]>
       lengths = <tf.RaggedTensor [[1, 3], [3, 5, 2]]>

Umgekehrt kann ein gestapeltes Dataset mithilfe von Dataset.unbatch in ein flaches Dataset Dataset.unbatch .

 unbatched_dataset = batched_dataset.unbatch()
print_dictionary_dataset(unbatched_dataset)
 
Element 0:
        colors = [b'red' b'blue']
       lengths = [7]
Element 1:
        colors = [b'orange']
       lengths = []
Element 2:
        colors = [b'black' b'yellow']
       lengths = [1 3]
Element 3:
        colors = [b'green']
       lengths = [3 5 2]

Batching-Datensätze mit nicht zerlumpten Tensoren variabler Länge

Wenn Sie einen Datensatz haben, der nicht zerlumpte Tensoren enthält und die dense_to_ragged_batch zwischen den Elementen variieren, können Sie diese nicht zerlumpten Tensoren in zerlumpte Tensoren dense_to_ragged_batch , indem Sie die Transformation dense_to_ragged_batch anwenden:

 non_ragged_dataset = tf.data.Dataset.from_tensor_slices([1, 5, 3, 2, 8])
non_ragged_dataset = non_ragged_dataset.map(tf.range)
batched_non_ragged_dataset = non_ragged_dataset.apply(
    tf.data.experimental.dense_to_ragged_batch(2))
for element in batched_non_ragged_dataset:
  print(element)
 
<tf.RaggedTensor [[0], [0, 1, 2, 3, 4]]>
<tf.RaggedTensor [[0, 1, 2], [0, 1]]>
<tf.RaggedTensor [[0, 1, 2, 3, 4, 5, 6, 7]]>

Datensätze mit zerlumpten Tensoren transformieren

Ragged Tensoren in Datasets können auch mit Dataset.map erstellt oder transformiert werden.

 def transform_lengths(features):
  return {
      'mean_length': tf.math.reduce_mean(features['lengths']),
      'length_ranges': tf.ragged.range(features['lengths'])}
transformed_dataset = dataset.map(transform_lengths)
print_dictionary_dataset(transformed_dataset)
 
Element 0:
   mean_length = 7
 length_ranges = <tf.RaggedTensor [[0, 1, 2, 3, 4, 5, 6]]>
Element 1:
   mean_length = 0
 length_ranges = <tf.RaggedTensor []>
Element 2:
   mean_length = 2
 length_ranges = <tf.RaggedTensor [[0], [0, 1, 2]]>
Element 3:
   mean_length = 3
 length_ranges = <tf.RaggedTensor [[0, 1, 2], [0, 1, 2, 3, 4], [0, 1]]>

Funktion

tf.function ist ein Dekorator, der TensorFlow-Diagramme für Python-Funktionen vorberechnet, wodurch die Leistung Ihres TensorFlow-Codes erheblich verbessert werden kann. Ragged Tensoren können transparent mit @tf.function dekorierten Funktionen verwendet werden. Die folgende Funktion funktioniert beispielsweise sowohl mit zerlumpten als auch mit nicht zerlumpten Tensoren:

 @tf.function
def make_palindrome(x, axis):
  return tf.concat([x, tf.reverse(x, [axis])], axis)
 
 make_palindrome(tf.constant([[1, 2], [3, 4], [5, 6]]), axis=1)
 
<tf.Tensor: shape=(3, 4), dtype=int32, numpy=
array([[1, 2, 2, 1],
       [3, 4, 4, 3],
       [5, 6, 6, 5]], dtype=int32)>
 make_palindrome(tf.ragged.constant([[1, 2], [3], [4, 5, 6]]), axis=1)
 
<tf.RaggedTensor [[1, 2, 2, 1], [3, 3], [4, 5, 6, 6, 5, 4]]>

Wenn Sie die input_signature für die tf.function tf.RaggedTensorSpec . explizit angeben tf.function , können Sie dies mit tf.RaggedTensorSpec tun.

 @tf.function(
    input_signature=[tf.RaggedTensorSpec(shape=[None, None], dtype=tf.int32)])
def max_and_min(rt):
  return (tf.math.reduce_max(rt, axis=-1), tf.math.reduce_min(rt, axis=-1))

max_and_min(tf.ragged.constant([[1, 2], [3], [4, 5, 6]]))
 
(<tf.Tensor: shape=(3,), dtype=int32, numpy=array([2, 3, 6], dtype=int32)>,
 <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 3, 4], dtype=int32)>)

Konkrete Funktionen

Konkrete Funktionen kapseln einzelne verfolgte Graphen, die von tf.function . Ab TensorFlow 2.3 (und in tf-nightly ) können zerlumpte Tensoren transparent mit konkreten Funktionen verwendet werden.

 # Preferred way to use ragged tensors with concrete functions (TF 2.3+):
try:
  @tf.function
  def increment(x):
    return x + 1

  rt = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
  cf = increment.get_concrete_function(rt)
  print(cf(rt))
except Exception as e:
  print(f"Not supported before TF 2.3: {type(e)}: {e}")
 
<tf.RaggedTensor [[2, 3], [4], [5, 6, 7]]>

Wenn Sie vor TensorFlow 2.3 zerlumpte Tensoren mit konkreten Funktionen verwenden müssen, empfehlen wir, zerlumpte Tensoren in ihre Komponenten ( values und row_splits ) zu row_splits und als separate Argumente zu übergeben.

 # Backwards-compatible way to use ragged tensors with concrete functions:
@tf.function
def decomposed_ragged_increment(x_values, x_splits):
  x = tf.RaggedTensor.from_row_splits(x_values, x_splits)
  return x + 1

rt = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
cf = decomposed_ragged_increment.get_concrete_function(rt.values, rt.row_splits)
print(cf(rt.values, rt.row_splits))
 
<tf.RaggedTensor [[2, 3], [4], [5, 6, 7]]>

Gespeicherte Modelle

Ein SavedModel ist ein serialisiertes TensorFlow-Programm, das sowohl Gewichte als auch Berechnungen enthält. Es kann aus einem Keras-Modell oder einem benutzerdefinierten Modell erstellt werden. In beiden Fällen können zerlumpte Tensoren transparent mit den von einem SavedModel definierten Funktionen und Methoden verwendet werden.

Beispiel: Speichern eines Keras-Modells

 import tempfile

keras_module_path = tempfile.mkdtemp()
tf.saved_model.save(keras_model, keras_module_path)
imported_model = tf.saved_model.load(keras_module_path)
imported_model(hashed_words)
 
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Model.state_updates (from tensorflow.python.keras.engine.training) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
WARNING:tensorflow:From /tmpfs/src/tf_docs_env/lib/python3.6/site-packages/tensorflow/python/training/tracking/tracking.py:111: Layer.updates (from tensorflow.python.keras.engine.base_layer) is deprecated and will be removed in a future version.
Instructions for updating:
This property should not be used in TensorFlow 2.0, as updates are applied automatically.
INFO:tensorflow:Assets written to: /tmp/tmpiwzx2cd0/assets

<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[0.04364644],
       [0.01928963],
       [0.03224095],
       [0.01768562]], dtype=float32)>

Beispiel: Speichern eines benutzerdefinierten Modells

 class CustomModule(tf.Module):
  def __init__(self, variable_value):
    super(CustomModule, self).__init__()
    self.v = tf.Variable(variable_value)

  @tf.function
  def grow(self, x):
    return x * self.v

module = CustomModule(100.0)

# Before saving a custom model, we must ensure that concrete functions are
# built for each input signature that we will need.
module.grow.get_concrete_function(tf.RaggedTensorSpec(shape=[None, None],
                                                      dtype=tf.float32))

custom_module_path = tempfile.mkdtemp()
tf.saved_model.save(module, custom_module_path)
imported_model = tf.saved_model.load(custom_module_path)
imported_model.grow(tf.ragged.constant([[1.0, 4.0, 3.0], [2.0]]))
 
INFO:tensorflow:Assets written to: /tmp/tmpvq6pr2f2/assets

<tf.RaggedTensor [[100.0, 400.0, 300.0], [200.0]]>

Überladene Bediener

Die RaggedTensor Klasse überlastet die Standard-Python-Arithmetik- und Vergleichsoperatoren und erleichtert so die Durchführung grundlegender elementweiser Berechnungen:

 x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
y = tf.ragged.constant([[1, 1], [2], [3, 3, 3]])
print(x + y)
 
<tf.RaggedTensor [[2, 3], [5], [7, 8, 9]]>

Da die überladenen Operatoren elementweise Berechnungen durchführen, müssen die Eingaben für alle Binäroperationen dieselbe Form haben oder in dieselbe Form gesendet werden können. Im einfachsten Broadcast-Fall wird ein einzelner Skalar elementweise mit jedem Wert in einem zerlumpten Tensor kombiniert:

 x = tf.ragged.constant([[1, 2], [3], [4, 5, 6]])
print(x + 3)
 
<tf.RaggedTensor [[4, 5], [6], [7, 8, 9]]>

Weitere Informationen zu fortgeschritteneren Fällen finden Sie im Abschnitt über Rundfunk .

Ragged Tensoren überlasten den gleichen Satz von Operatoren wie normale Tensor s: die unäre Operatoren - , ~ , und abs() ; und die binären Operatoren + , - , * , / , // , % , ** , & , | , ^ , == , < , <= , > und >= .

Indizierung

Ragged Tensoren unterstützen die Indizierung im Python-Stil, einschließlich mehrdimensionaler Indizierung und Slicing. Die folgenden Beispiele zeigen eine gezackte Tensorindizierung mit einem 2-D- und einem 3-D-zerlumpten Tensor.

Indizierungsbeispiele: 2D-zerlumpter Tensor

 queries = tf.ragged.constant(
    [['Who', 'is', 'George', 'Washington'],
     ['What', 'is', 'the', 'weather', 'tomorrow'],
     ['Goodnight']])
 
 print(queries[1])                   # A single query
 
tf.Tensor([b'What' b'is' b'the' b'weather' b'tomorrow'], shape=(5,), dtype=string)

 print(queries[1, 2])                # A single word
 
tf.Tensor(b'the', shape=(), dtype=string)

 print(queries[1:])                  # Everything but the first row
 
<tf.RaggedTensor [[b'What', b'is', b'the', b'weather', b'tomorrow'], [b'Goodnight']]>

 print(queries[:, :3])               # The first 3 words of each query
 
<tf.RaggedTensor [[b'Who', b'is', b'George'], [b'What', b'is', b'the'], [b'Goodnight']]>

 print(queries[:, -2:])              # The last 2 words of each query
 
<tf.RaggedTensor [[b'George', b'Washington'], [b'weather', b'tomorrow'], [b'Goodnight']]>

Indizierungsbeispiele 3D-zerlumpter Tensor

 rt = tf.ragged.constant([[[1, 2, 3], [4]],
                         [[5], [], [6]],
                         [[7]],
                         [[8, 9], [10]]])
 
 print(rt[1])                        # Second row (2-D RaggedTensor)
 
<tf.RaggedTensor [[5], [], [6]]>

 print(rt[3, 0])                     # First element of fourth row (1-D Tensor)
 
tf.Tensor([8 9], shape=(2,), dtype=int32)

 print(rt[:, 1:3])                   # Items 1-3 of each row (3-D RaggedTensor)
 
<tf.RaggedTensor [[[4]], [[], [6]], [], [[10]]]>

 print(rt[:, -1:])                   # Last item of each row (3-D RaggedTensor)
 
<tf.RaggedTensor [[[4]], [[6]], [[7]], [[10]]]>

RaggedTensor unterstützt das mehrdimensionale Indizieren und Schneiden mit einer Einschränkung: Das Indizieren in eine zerlumpte Dimension ist nicht zulässig. Dieser Fall ist problematisch, da der angegebene Wert in einigen Zeilen vorhanden sein kann, in anderen jedoch nicht. In solchen Fällen ist es nicht offensichtlich, ob wir (1) einen IndexError ; (2) einen Standardwert verwenden; oder (3) diesen Wert überspringen und einen Tensor mit weniger Zeilen zurückgeben, als wir begonnen haben. Nach den Leitprinzipien von Python ("Verweigern Sie angesichts von Zweideutigkeiten die Versuchung zu raten") verbieten wir diese Operation derzeit.

Tensortypkonvertierung

Die RaggedTensor Klasse definiert Methoden, mit denen zwischen RaggedTensor und tf.Tensor oder tf.SparseTensors :

 ragged_sentences = tf.ragged.constant([
    ['Hi'], ['Welcome', 'to', 'the', 'fair'], ['Have', 'fun']])
 
 # RaggedTensor -> Tensor
print(ragged_sentences.to_tensor(default_value='', shape=[None, 10]))
 
tf.Tensor(
[[b'Hi' b'' b'' b'' b'' b'' b'' b'' b'' b'']
 [b'Welcome' b'to' b'the' b'fair' b'' b'' b'' b'' b'' b'']
 [b'Have' b'fun' b'' b'' b'' b'' b'' b'' b'' b'']], shape=(3, 10), dtype=string)

 # Tensor -> RaggedTensor
x = [[1, 3, -1, -1], [2, -1, -1, -1], [4, 5, 8, 9]]
print(tf.RaggedTensor.from_tensor(x, padding=-1))
 
<tf.RaggedTensor [[1, 3], [2], [4, 5, 8, 9]]>

 #RaggedTensor -> SparseTensor
print(ragged_sentences.to_sparse())
 
SparseTensor(indices=tf.Tensor(
[[0 0]
 [1 0]
 [1 1]
 [1 2]
 [1 3]
 [2 0]
 [2 1]], shape=(7, 2), dtype=int64), values=tf.Tensor([b'Hi' b'Welcome' b'to' b'the' b'fair' b'Have' b'fun'], shape=(7,), dtype=string), dense_shape=tf.Tensor([3 4], shape=(2,), dtype=int64))

 # SparseTensor -> RaggedTensor
st = tf.SparseTensor(indices=[[0, 0], [2, 0], [2, 1]],
                     values=['a', 'b', 'c'],
                     dense_shape=[3, 3])
print(tf.RaggedTensor.from_sparse(st))
 
<tf.RaggedTensor [[b'a'], [], [b'b', b'c']]>

Bewertung zerlumpter Tensoren

Um auf die Werte in einem zerlumpten Tensor zuzugreifen, können Sie:

  1. Verwenden Sie tf.RaggedTensor.to_list() , um den zerlumpten Tensor in eine verschachtelte Python-Liste zu konvertieren.
  2. Verwenden Sie tf.RaggedTensor.numpy() , um den zerlumpten Tensor in ein Numpy-Array zu konvertieren, dessen Werte verschachtelte Numpy-Arrays sind.
  3. Zerlegen Sie den zerlumpten Tensor mithilfe der Eigenschaften tf.RaggedTensor.values und tf.RaggedTensor.row_splits oder zeilenparitionierender Methoden wie tf.RaggedTensor.row_lengths() und tf.RaggedTensor.value_rowids() in seine Komponenten.
  4. Verwenden Sie die Python-Indizierung, um Werte aus dem unregelmäßigen Tensor auszuwählen.
 rt = tf.ragged.constant([[1, 2], [3, 4, 5], [6], [], [7]])
print("python list:", rt.to_list())
print("numpy array:", rt.numpy())
print("values:", rt.values.numpy())
print("splits:", rt.row_splits.numpy())
print("indexed value:", rt[1].numpy())
 
python list: [[1, 2], [3, 4, 5], [6], [], [7]]
numpy array: [array([1, 2], dtype=int32) array([3, 4, 5], dtype=int32)
 array([6], dtype=int32) array([], dtype=int32) array([7], dtype=int32)]
values: [1 2 3 4 5 6 7]
splits: [0 2 5 6 6 7]
indexed value: [3 4 5]

Rundfunk

Beim Rundfunk werden Tensoren mit unterschiedlichen Formen für elementweise Operationen kompatibel gemacht. Weitere Hintergrundinformationen zum Rundfunk finden Sie unter:

Die grundlegenden Schritte zum Senden von zwei Eingängen x und y mit kompatiblen Formen sind:

  1. Wenn x und y nicht die gleiche Anzahl von Dimensionen haben, fügen Sie äußere Dimensionen (mit Größe 1) hinzu, bis sie dies tun.

  2. Für jede Dimension, in der x und y unterschiedliche Größen haben:

    • Wenn x oder y in Dimension d die Größe 1 haben, wiederholen Sie die Werte in Dimension d , um sie an die Größe der anderen Eingabe anzupassen.

    • Andernfalls lösen Sie eine Ausnahme aus ( x und y sind nicht sendungskompatibel).

Wenn die Größe eines Tensors in einer einheitlichen Dimension eine einzelne Zahl ist (die Größe der Scheiben in dieser Dimension); und die Größe eines Tensors in einer unregelmäßigen Dimension ist eine Liste von Schnittlängen (für alle Schichten in dieser Dimension).

Sendebeispiele

 # x       (2D ragged):  2 x (num_rows)
# y       (scalar)
# result  (2D ragged):  2 x (num_rows)
x = tf.ragged.constant([[1, 2], [3]])
y = 3
print(x + y)
 
<tf.RaggedTensor [[4, 5], [6]]>

 # x         (2d ragged):  3 x (num_rows)
# y         (2d tensor):  3 x          1
# Result    (2d ragged):  3 x (num_rows)
x = tf.ragged.constant(
   [[10, 87, 12],
    [19, 53],
    [12, 32]])
y = [[1000], [2000], [3000]]
print(x + y)
 
<tf.RaggedTensor [[1010, 1087, 1012], [2019, 2053], [3012, 3032]]>

 # x      (3d ragged):  2 x (r1) x 2
# y      (2d ragged):         1 x 1
# Result (3d ragged):  2 x (r1) x 2
x = tf.ragged.constant(
    [[[1, 2], [3, 4], [5, 6]],
     [[7, 8]]],
    ragged_rank=1)
y = tf.constant([[10]])
print(x + y)
 
<tf.RaggedTensor [[[11, 12], [13, 14], [15, 16]], [[17, 18]]]>

 # x      (3d ragged):  2 x (r1) x (r2) x 1
# y      (1d tensor):                    3
# Result (3d ragged):  2 x (r1) x (r2) x 3
x = tf.ragged.constant(
    [
        [
            [[1], [2]],
            [],
            [[3]],
            [[4]],
        ],
        [
            [[5], [6]],
            [[7]]
        ]
    ],
    ragged_rank=2)
y = tf.constant([10, 20, 30])
print(x + y)
 
<tf.RaggedTensor [[[[11, 21, 31], [12, 22, 32]], [], [[13, 23, 33]], [[14, 24, 34]]], [[[15, 25, 35], [16, 26, 36]], [[17, 27, 37]]]]>

Hier sind einige Beispiele für Formen, die nicht gesendet werden:

 # x      (2d ragged): 3 x (r1)
# y      (2d tensor): 3 x    4  # trailing dimensions do not match
x = tf.ragged.constant([[1, 2], [3, 4, 5, 6], [7]])
y = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
1
b'lengths='
4
b'dim_size='
2, 4, 1

 # x      (2d ragged): 3 x (r1)
# y      (2d ragged): 3 x (r2)  # ragged dimensions do not match.
x = tf.ragged.constant([[1, 2, 3], [4], [5, 6]])
y = tf.ragged.constant([[10, 20], [30, 40], [50]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
1
b'lengths='
2, 2, 1
b'dim_size='
3, 1, 2

 # x      (3d ragged): 3 x (r1) x 2
# y      (3d ragged): 3 x (r1) x 3  # trailing dimensions do not match
x = tf.ragged.constant([[[1, 2], [3, 4], [5, 6]],
                        [[7, 8], [9, 10]]])
y = tf.ragged.constant([[[1, 2, 0], [3, 4, 0], [5, 6, 0]],
                        [[7, 8, 0], [9, 10, 0]]])
try:
  x + y
except tf.errors.InvalidArgumentError as exception:
  print(exception)
 
Expected 'tf.Tensor(False, shape=(), dtype=bool)' to be true. Summarized data: b'Unable to broadcast: dimension size mismatch in dimension'
2
b'lengths='
3, 3, 3, 3, 3
b'dim_size='
2, 2, 2, 2, 2

RaggedTensor-Codierung

Ragged-Tensoren werden mit der RaggedTensor Klasse codiert. Intern besteht jeder RaggedTensor aus:

  • A values Tensor, der die Zeilen variabler Länge in eine abgeflachte Liste verkettet.
  • Eine row_partition , die angibt, wie diese abgeflachten Werte in Zeilen unterteilt werden.

ragged_encoding_2

Die row_partition kann mit vier verschiedenen Codierungen gespeichert werden:

  • row_splits ist ein ganzzahliger Vektor, der die Teilungspunkte zwischen Zeilen angibt.
  • value_rowids ist ein ganzzahliger Vektor, der den Zeilenindex für jeden Wert angibt.
  • row_lengths ist ein ganzzahliger Vektor, der die Länge jeder Zeile angibt.
  • uniform_row_length ist ein ganzzahliger Skalar, der eine einzelne Länge für alle Zeilen angibt.

partition_encodings

Ein ganze Zahl skalare nrows kann auch in der enthalten seine row_partition Codierung für leere nachlauf Reihen mit berücksichtigen value_rowids oder leeren Zeilen mit uniform_row_length .

 rt = tf.RaggedTensor.from_row_splits(
    values=[3, 1, 4, 1, 5, 9, 2],
    row_splits=[0, 4, 4, 6, 7])
print(rt)
 
<tf.RaggedTensor [[3, 1, 4, 1], [], [5, 9], [2]]>

Die Auswahl der für Zeilenpartitionen zu verwendenden Codierung wird intern von unregelmäßigen Tensoren verwaltet, um die Effizienz in einigen Kontexten zu verbessern. Insbesondere sind einige der Vor- und Nachteile der verschiedenen Zeilenaufteilungsschemata:

  • Effiziente Indizierung : Die row_splits Codierung ermöglicht eine row_splits Indizierung und Aufteilung in zerlumpte Tensoren.

  • Effiziente Verkettung : Die Codierung von row_lengths ist effizienter, wenn zerlumpte Tensoren verkettet werden, da sich die Zeilenlängen nicht ändern, wenn zwei Tensoren miteinander verkettet werden.

  • Kleine Codierungsgröße : Die Codierung value_rowids ist effizienter, wenn zerlumpte Tensoren mit einer großen Anzahl leerer Zeilen gespeichert werden, da die Größe des Tensors nur von der Gesamtzahl der Werte abhängt. Andererseits sind die Codierungen row_splits und row_lengths effizienter, wenn zerlumpte Tensoren mit längeren Zeilen gespeichert werden, da sie nur einen Skalarwert für jede Zeile benötigen.

  • Kompatibilität : Das Schema value_rowids entspricht dem Segmentierungsformat , das von Operationen wie tf.segment_sum . Das Schema row_limits entspricht dem Format, das von tf.sequence_mask wie tf.sequence_mask .

  • Einheitliche Abmessungen : Wie unten erläutert, wird die Codierung " uniform_row_length verwendet, um zerlumpte Tensoren mit einheitlichen Abmessungen zu codieren.

Mehrere ausgefranste Abmessungen

Ein ragged Tensor mit mehreren ragged Dimensionen unter Verwendung eines verschachtelten codierten RaggedTensor für die values Tensors. Jeder verschachtelte RaggedTensor fügt eine einzelne RaggedTensor Dimension hinzu.

ragged_rank_2

 rt = tf.RaggedTensor.from_row_splits(
    values=tf.RaggedTensor.from_row_splits(
        values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
        row_splits=[0, 3, 3, 5, 9, 10]),
    row_splits=[0, 1, 1, 5])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
 
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>
Shape: (3, None, None)
Number of partitioned dimensions: 2

Die Factory-Funktion tf.RaggedTensor.from_nested_row_splits kann verwendet werden, um einen RaggedTensor mit mehreren zerlumpten Dimensionen direkt zu erstellen, indem eine Liste von row_splits Tensoren row_splits :

 rt = tf.RaggedTensor.from_nested_row_splits(
    flat_values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
    nested_row_splits=([0, 1, 1, 5], [0, 3, 3, 5, 9, 10]))
print(rt)
 
<tf.RaggedTensor [[[10, 11, 12]], [], [[], [13, 14], [15, 16, 17, 18], [19]]]>

Unregelmäßiger Rang und flache Werte

Der unregelmäßige Rang eines zerlumpten Tensors gibt an, wie oft der zugrunde liegende values Tensor partitioniert wurde (dh die Verschachtelungstiefe von RaggedTensor Objekten). Der Tensor für die innersten values wird als flat_values ​​bezeichnet . Im folgenden Beispiel conversations hat ragged_rank = 3, und seine flat_values ist ein 1D - Tensor mit 24 Saiten:

 # shape = [batch, (paragraph), (sentence), (word)]
conversations = tf.ragged.constant(
    [[[["I", "like", "ragged", "tensors."]],
      [["Oh", "yeah?"], ["What", "can", "you", "use", "them", "for?"]],
      [["Processing", "variable", "length", "data!"]]],
     [[["I", "like", "cheese."], ["Do", "you?"]],
      [["Yes."], ["I", "do."]]]])
conversations.shape
 
TensorShape([2, None, None, None])
 assert conversations.ragged_rank == len(conversations.nested_row_splits)
conversations.ragged_rank  # Number of partitioned dimensions.
 
3
 conversations.flat_values.numpy()
 
array([b'I', b'like', b'ragged', b'tensors.', b'Oh', b'yeah?', b'What',
       b'can', b'you', b'use', b'them', b'for?', b'Processing',
       b'variable', b'length', b'data!', b'I', b'like', b'cheese.', b'Do',
       b'you?', b'Yes.', b'I', b'do.'], dtype=object)

Einheitliche Innenmaße

Zackige Tensoren mit einheitlichen tf.Tensor werden unter Verwendung eines mehrdimensionalen tf.Tensor für die flat_values ​​(dh die innersten values ) codiert.

uniform_inner

 rt = tf.RaggedTensor.from_row_splits(
    values=[[1, 3], [0, 0], [1, 3], [5, 3], [3, 3], [1, 2]],
    row_splits=[0, 3, 4, 6])
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
print("Flat values shape: {}".format(rt.flat_values.shape))
print("Flat values:\n{}".format(rt.flat_values))
 
<tf.RaggedTensor [[[1, 3], [0, 0], [1, 3]], [[5, 3]], [[3, 3], [1, 2]]]>
Shape: (3, None, 2)
Number of partitioned dimensions: 1
Flat values shape: (6, 2)
Flat values:
[[1 3]
 [0 0]
 [1 3]
 [5 3]
 [3 3]
 [1 2]]

Einheitliche nicht innere Abmessungen

Zackige Tensoren mit einheitlichen nicht inneren Abmessungen werden durch Partitionieren von Zeilen mit einheitlicher uniform_row_length codiert.

uniform_outer

 rt = tf.RaggedTensor.from_uniform_row_length(
    values=tf.RaggedTensor.from_row_splits(
        values=[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
        row_splits=[0, 3, 5, 9, 10]),
    uniform_row_length=2)
print(rt)
print("Shape: {}".format(rt.shape))
print("Number of partitioned dimensions: {}".format(rt.ragged_rank))
 
<tf.RaggedTensor [[[10, 11, 12], [13, 14]], [[15, 16, 17, 18], [19]]]>
Shape: (2, 2, None)
Number of partitioned dimensions: 2