טנסורים מרופטים

הצג באתר TensorFlow.org הפעל בגוגל קולאב צפה במקור ב-GitHubהורד מחברת

תיעוד API: tf.RaggedTensor tf.ragged

להכין

import math
import tensorflow as tf

סקירה כללית

הנתונים שלך מגיעים בצורות רבות; גם הטנסורים שלך צריכים. טנזורים מרופטים הם המקבילה של TensorFlow לרשימות מקוננות באורך משתנה. הם מקלים על אחסון ועיבוד נתונים עם צורות לא אחידות, כולל:

  • תכונות באורך משתנה, כגון סט השחקנים בסרט.
  • קבוצות של כניסות עוקבות באורך משתנה, כגון משפטים או קטעי וידאו.
  • קלט היררכי, כגון מסמכי טקסט המחולקים לחלקים, פסקאות, משפטים ומילים.
  • שדות בודדים בתשומות מובנות, כגון מאגרי פרוטוקול.

מה אתה יכול לעשות עם טנזור מרופט

טנזורים מרופטים נתמכים על ידי יותר ממאה פעולות TensorFlow, כולל פעולות מתמטיות (כגון tf.add ו- tf.reduce_mean ), פעולות מערך (כגון tf.concat ו- tf.tile ), פעולות למניפולציה של מחרוזות (כגון tf.substr ), בקרה על פעולות זרימה (כגון tf.while_loop ו- tf.map_fn ), ועוד רבים אחרים:

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], []]>

ישנן גם מספר שיטות ופעולות הספציפיות לטנזורים מרופטים, כולל שיטות מפעל, שיטות המרה ופעולות מיפוי ערך. לרשימה של פעולות נתמכות, עיין בתיעוד החבילה tf.ragged .

טנזורים מרופטים נתמכים על ידי ממשקי API רבים של TensorFlow, כולל Keras , Datasets , tf.function , SavedModels ו- tf.Example . למידע נוסף, עיין בסעיף על ממשקי API של TensorFlow למטה.

כמו בטנסור רגיל, אתה יכול להשתמש באינדקס בסגנון Python כדי לגשת לפרוסות ספציפיות של טנזור מרופט. למידע נוסף, עיין בסעיף על יצירת אינדקס להלן.

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], []]>

ובדיוק כמו טנסורים רגילים, אתה יכול להשתמש בחשבון Python ואופרטורים להשוואה כדי לבצע פעולות אלמנטריות. למידע נוסף, עיין בסעיף על מפעילי עומס יתר למטה.

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], []]>

אם אתה צריך לבצע טרנספורמציה אלמנטרית לערכים של RaggedTensor , אתה יכול להשתמש ב- tf.ragged.map_flat_values , שלוקח פונקציה בתוספת ארגומנט אחד או יותר, ומחיל את הפונקציה כדי להפוך את הערכים של 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], []]>

ניתן להמיר טנזורים מרופטים list פייתונים מקוננות ולמערכי array :

digits.to_list()
[[3, 1, 4, 1], [], [5, 9, 2], [6], []]
digits.numpy()
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ragged/ragged_tensor.py:2063: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  return np.array(rows)
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)

בניית טנזור מרופט

הדרך הפשוטה ביותר לבנות טנסור מרופט היא שימוש ב- tf.ragged.constant , שבונה את ה- RaggedTensor המתאים list Python מקוננת או array NumPy:

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']]]>

ניתן לבנות טנסורים מרופטים גם על ידי התאמה של טנסורים של ערכים שטוחים עם טנסורים tf.RaggedTensor.from_row_splits שורות , המציינים כיצד יש לחלק את הערכים הללו לשורות, תוך שימוש בשיטות כיתות מפעל כגון tf.RaggedTensor.from_value_rowids , tf.RaggedTensor.from_row_lengths

tf.RaggedTensor.from_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

אם אתה יודע כמה אורכה כל שורה, אז אתה יכול להשתמש row_lengths למחיצות שורות:

row_lengths טנזור מחיצת שורות

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

אם אתה יודע את האינדקס שבו כל שורה מתחילה ומסתיימת, אז אתה יכול להשתמש 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]]>

עיין בתיעוד מחלקה tf.RaggedTensor לקבלת רשימה מלאה של שיטות המפעל.

מה שאתה יכול לאחסן בטנזור מרופט

כמו ב- Tensor s רגיל, הערכים ב- RaggedTensor חייבים להיות כולם באותו סוג; והערכים חייבים להיות כולם באותו עומק קינון ( דרגת הטנזור):

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

מקרה שימוש לדוגמה

הדוגמה הבאה מדגימה כיצד ניתן להשתמש ב- RaggedTensor כדי לבנות ולשלב הטבעות של unigram ו-bigram עבור אצווה של שאילתות באורך משתנה, תוך שימוש בסמנים מיוחדים להתחלה ולסוף של כל משפט. לפרטים נוספים על האופציות המשמשות בדוגמה זו, עיין בתיעוד החבילה 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 and 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.14285272  0.02908629 -0.16327512 -0.14529026]
 [-0.4479212  -0.35615516  0.17110227  0.2522229 ]
 [-0.1987868  -0.13152348 -0.0325102   0.02125177]], shape=(3, 4), dtype=float32)

דוגמה טנסור מרופט

מידות מרופטות ואחידות

מימד מרופט הוא מימד שאורכים שונים לפרוסות שלו. לדוגמה, הממד הפנימי (העמודה) של rt=[[3, 1, 4, 1], [], [5, 9, 2], [6], []] הוא מרופט, מכיוון שהעמודה פרוסות ( rt[0, :] , ..., rt[4, :] ) יש אורכים שונים. מידות שלכל הפרוסות שלהן אותו אורך נקראות מידות אחידות .

הממד החיצוני ביותר של טנזור מרופט הוא תמיד אחיד, מכיוון שהוא מורכב מפרוסה אחת (ולכן, אין אפשרות לאורכי פרוסה שונים). שאר הממדים עשויים להיות מרופטים או אחידים. לדוגמה, אתה יכול לאחסן את ההטמעות של המילה עבור כל מילה בקבוצת משפטים באמצעות טנזור מרופט עם צורה [num_sentences, (num_words), embedding_size] , כאשר הסוגריים מסביב (num_words) מציינים שהממד הוא מרופט.

הטמעת מילים באמצעות טנזור מרופט

לטנזורים מרופטים עשויים להיות מידות מרופטות מרובות. לדוגמה, תוכל לאחסן אצווה של מסמכי טקסט מובנים באמצעות טנזור עם צורה [num_documents, (num_paragraphs), (num_sentences), (num_words)] (כאשר שוב משתמשים בסוגריים לציון ממדים מרופטים).

כמו ב- tf.Tensor , הדרגה של טנזור מרופט היא מספר הממדים הכולל שלו (כולל מידות מרופטות ואחידות כאחד). טנסור שעלול להיות מרופט הוא ערך שעשוי להיות tf.Tensor או tf.RaggedTensor .

כאשר מתארים את הצורה של RaggedTensor, מידות מרופטות מסומנות באופן קונבנציונלי על ידי הוספתם בסוגריים. לדוגמה, כפי שראית למעלה, ניתן לכתוב את הצורה של RaggedTensor תלת-ממדית המאחסנת הטמעות מילים עבור כל מילה בקבוצת משפטים כ- [num_sentences, (num_words), embedding_size] .

התכונה RaggedTensor.shape מחזירה tf.TensorShape עבור טנזור מרופט שבו לממדים מרופטים יש גודל None :

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

ניתן להשתמש בשיטה tf.RaggedTensor.bounding_shape כדי למצוא צורת תוחמת הדוקה עבור RaggedTensor נתון:

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

מרופט מול דליל

אין לחשוב על טנזור מרופט כסוג של טנסור דליל. במיוחד, טנזורים דלילים הם קידודים יעילים עבור tf.Tensor את אותם נתונים בפורמט קומפקטי; אבל טנסור מרופט הוא הרחבה ל- tf.Tensor מחלקה מורחבת של נתונים. הבדל זה חיוני בעת הגדרת פעולות:

  • החלת אופ על טנזור דליל או צפוף אמורה לתת תמיד את אותה תוצאה.
  • החלת אופציה על טנזור מרופט או דליל עשויה לתת תוצאות שונות.

כדוגמה להמחשה, שקול כיצד פעולות מערך כגון concat , stack ו- tile מוגדרות עבור טנזורים מרופטים לעומת דלילים. שרשור טנזורים מרופטים מצטרפים לכל שורה ויוצרים שורה אחת עם האורך המשולב:

שרשור טנזורים מרופטים

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']]>

עם זאת, שרשור טנסורים דלילים שווה ערך לשרשור טנסורים צפופים תואמים, כפי שמודגם בדוגמה הבאה (כאשר Ø מציין ערכים חסרים):

שרשור טנסורים דלילים

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)

לדוגמא נוספת מדוע הבחנה זו חשובה, שקול את ההגדרה של "הערך הממוצע של כל שורה" עבור אופציה כגון tf.reduce_mean . עבור טנזור מרופט, הערך הממוצע לשורה הוא סכום ערכי השורה חלקי רוחב השורה. אבל עבור טנזור דליל, הערך הממוצע לשורה הוא סכום ערכי השורה חלקי הרוחב הכולל של הטנזור הדליל (שגדול או שווה לרוחב השורה הארוכה ביותר).

ממשקי API של TensorFlow

קראס

tf.keras הוא ה-API ברמה גבוהה של TensorFlow לבניית והדרכה של מודלים של למידה עמוקה. ניתן להעביר טנזורים מרופטים כקלטים לדגם Keras על ידי הגדרת ragged ragged=True ב- tf.keras.Input או tf.keras.layers.InputLayer . טנסורים מרופטים עשויים לעבור בין שכבות קרס, ולהחזיר אותם על ידי דגמי קרס. הדוגמה הבאה מציגה דגם LSTM של צעצוע שאומן באמצעות טנזורים מרופטים.

# 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 kernels since it doesn't meet the criteria. It will use a generic GPU kernel as fallback when running on GPU.
Epoch 1/5
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/framework/indexed_slices.py:449: UserWarning: Converting sparse IndexedSlices(IndexedSlices(indices=Tensor("gradient_tape/sequential/lstm/RaggedToTensor/boolean_mask_1/GatherV2:0", shape=(None,), dtype=int32), values=Tensor("gradient_tape/sequential/lstm/RaggedToTensor/boolean_mask/GatherV2:0", shape=(None, 16), dtype=float32), dense_shape=Tensor("gradient_tape/sequential/lstm/RaggedToTensor/Shape:0", shape=(2,), dtype=int32))) to a dense Tensor of unknown shape. This may consume a large amount of memory.
  "shape. This may consume a large amount of memory." % value)
1/1 [==============================] - 2s 2s/step - loss: 3.1269
Epoch 2/5
1/1 [==============================] - 0s 18ms/step - loss: 2.1197
Epoch 3/5
1/1 [==============================] - 0s 19ms/step - loss: 2.0196
Epoch 4/5
1/1 [==============================] - 0s 20ms/step - loss: 1.9371
Epoch 5/5
1/1 [==============================] - 0s 18ms/step - loss: 1.8857
[[0.02800461]
 [0.00945962]
 [0.02283431]
 [0.00252927]]

tf.דוגמה

tf.Example הוא קידוד פרוטובוף סטנדרטי עבור נתוני TensorFlow. נתונים המקודדים באמצעות tf.Example s כוללים לרוב תכונות באורך משתנה. לדוגמה, הקוד הבא מגדיר אצווה של ארבע הודעות tf.Example עם אורכי תכונה שונים:

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]} } } }''')]

אתה יכול לנתח את הנתונים המקודדים האלה באמצעות tf.io.parse_example , שלוקח טנסור של מחרוזות מסודרות ומילון מפרט תכונות, ומחזיר מילון מיפוי שמות תכונות לטנזורים. כדי לקרוא את התכונות באורך משתנה לתוך טנזורים מרופטים, אתה פשוט משתמש ב- tf.io.RaggedFeature במילון מפרט התכונות:

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 גם לקריאת תכונות עם מימדים מרופטים מרובים. לפרטים, עיין בתיעוד ה-API .

מערכי נתונים

tf.data הוא API המאפשר לך לבנות צינורות קלט מורכבים מחלקים פשוטים הניתנים לשימוש חוזר. מבנה הנתונים הליבה שלו הוא tf.data.Dataset , המייצג רצף של אלמנטים, שבהם כל אלמנט מורכב ממרכיב אחד או יותר.

# 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))

בניית מערכי נתונים עם טנזורים מרופטים

ניתן לבנות מערכי נתונים מטנזורים מרופטים באותן שיטות המשמשות לבנייתם ​​מ- tf.Tensor s או array slices, כגון 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]

אצווה וביטול אצווה מערכי נתונים עם טנזורים מרופטים

ניתן לקבץ מערכי נתונים עם טנזורים מרופטים (המשלב n אלמנטים עוקבים לרכיב בודד) באמצעות שיטת Dataset.batch .

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]]>

לעומת זאת, ניתן להפוך מערך נתונים אצווה למערך נתונים שטוח באמצעות 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]

ערכות נתונים אצווה עם טנזורים באורך משתנה שאינם מרופטים

אם יש לך ערכת נתונים שמכילה טנזורים לא מרופטים, ואורכי הטנזורים משתנים בין אלמנטים, אז אתה יכול לקבץ את הטנזורים הלא מרופטים האלה לטנזורים מרופטים על ידי החלת הטרנספורמציה dense_to_ragged_batch :

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]]>

שינוי מערכי נתונים עם טנזורים מרופטים

אתה יכול גם ליצור או לשנות טנזורים מרופטים במערכים נתונים באמצעות Dataset.map :

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]]>

tf.function

tf.function הוא מעצב שמחשב מראש גרפים של TensorFlow עבור פונקציות Python, מה שיכול לשפר משמעותית את הביצועים של קוד TensorFlow שלך. ניתן להשתמש בטנסורים מרופטים בשקיפות עם @tf.function . לדוגמה, הפונקציה הבאה פועלת עם טנזורים מרופטים וגם עם טנזורים לא מרופטים:

@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)
2021-09-22 20:36:51.018367: W tensorflow/core/grappler/optimizers/loop_optimizer.cc:907] Skipping loop optimization for Merge node with control input: RaggedConcat/assert_equal_1/Assert/AssertGuard/branch_executed/_9
<tf.RaggedTensor [[1, 2, 2, 1], [3, 3], [4, 5, 6, 6, 5, 4]]>

אם אתה רוצה לציין במפורש את input_signature עבור הפונקציה tf.function ., אז אתה יכול לעשות זאת באמצעות tf.RaggedTensorSpec .

@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)>)

פונקציות קונקרטיות

פונקציות קונקרטיות עוטפות גרפים בודדים שנבנו על ידי tf.function . ניתן להשתמש בטנסורים מרופטים בשקיפות עם פונקציות בטון.

@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))
<tf.RaggedTensor [[2, 3], [4], [5, 6, 7]]>

מודלים שמורים

A SavedModel היא תוכנית TensorFlow מסודרת, הכוללת גם משקלים וגם חישובים. ניתן לבנות אותו מדגם קרס או מדגם מותאם אישית. בכל מקרה, ניתן להשתמש בטנזורים מרופטים בשקיפות עם הפונקציות והשיטות המוגדרות על ידי SavedModel.

דוגמה: שמירת דגם של קרס

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)
2021-09-22 20:36:52.069689: W tensorflow/python/util/util.cc:348] Sets are not currently considered sequences, but this may change in the future, so consider avoiding using them.
WARNING:absl:Function `_wrapped_model` contains input name(s) args_0 with unsupported characters which will be renamed to args_0_1 in the SavedModel.
INFO:tensorflow:Assets written to: /tmp/tmp114axtt7/assets
INFO:tensorflow:Assets written to: /tmp/tmp114axtt7/assets
<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[0.02800461],
       [0.00945962],
       [0.02283431],
       [0.00252927]], dtype=float32)>

דוגמה: שמירת דגם מותאם אישית

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, you must ensure that concrete functions are
# built for each input signature that you 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/tmpnn4u8dy5/assets
INFO:tensorflow:Assets written to: /tmp/tmpnn4u8dy5/assets
<tf.RaggedTensor [[100.0, 400.0, 300.0], [200.0]]>

מפעילים עמוסים מדי

המחלקה RaggedTensor יתר על המידה את אופרטורי החשבון וההשוואה הסטנדרטיים של Python, מה שמקל על ביצוע מתמטיקה בסיסית אלמנטרית:

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]]>

מכיוון שהאופרטורים העמוסים מבצעים חישובים אלמנטריים, הקלט לכל הפעולות הבינאריות חייבות להיות באותה צורה או להיות ניתנות לשידור לאותה צורה. במקרה השידור הפשוט ביותר, סקלאר בודד משולב באופן אלמנטרי עם כל ערך בטנזור מרופט:

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

לדיון על מקרים מתקדמים יותר, עיין בסעיף על שידורים .

טנזורים מרופטים מעמיסים את אותה קבוצת אופרטורים כמו Tensor s רגילים: האופרטורים האנריים - , ~ ו- abs() ; והאופרטורים הבינאריים + , - , * , / , // , % , ** , & , | , ^ , == , < , <= , > ו >= .

יצירת אינדקס

טנזורים מרופטים תומכים באינדקס בסגנון Python, כולל אינדקס וחתך רב ממדי. הדוגמאות הבאות מדגימות אינדקס טנזור מרופט עם טנזור מרופט דו-ממדי ותלת-ממדי.

דוגמאות לאינדקס: טנזור מרופט דו-ממדי

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']]>

דוגמאות לאינדקס: טנזור מרופט בתלת מימד

rt = tf.ragged.constant([[[1, 2, 3], [4]],
                         [[5], [], [6]],
                         [[7]],
                         [[8, 9], [10]]])
print(rt[1])                        # Second row (2D RaggedTensor)
<tf.RaggedTensor [[5], [], [6]]>
print(rt[3, 0])                     # First element of fourth row (1D Tensor)
tf.Tensor([8 9], shape=(2,), dtype=int32)
print(rt[:, 1:3])                   # Items 1-3 of each row (3D RaggedTensor)
<tf.RaggedTensor [[[4]], [[], [6]], [], [[10]]]>
print(rt[:, -1:])                   # Last item of each row (3D RaggedTensor)
<tf.RaggedTensor [[[4]], [[6]], [[7]], [[10]]]>

RaggedTensor תומכים באינדקס ובחיתוך רב מימדי עם הגבלה אחת: אינדקס לממד מרופט אסור. מקרה זה בעייתי מכיוון שהערך המצוין עשוי להתקיים בשורות מסוימות אך לא באחרות. במקרים כאלה, לא ברור אם עליך (1) להעלות IndexError ; (2) השתמש בערך ברירת מחדל; או (3) דלג על הערך הזה והחזר טנסור עם פחות שורות ממה שהתחלת איתו. בעקבות העקרונות המנחים של Python ("מול אי בהירות, סרב לפיתוי לנחש"), פעולה זו אסורה כרגע.

המרת סוג טנסור

המחלקה RaggedTensor מגדירה שיטות שניתן להשתמש בהן כדי להמיר בין RaggedTensor s ל- tf.Tensor s או 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']]>

הערכת טנזורים מרופטים

כדי לגשת לערכים בטנזור מרופט, אתה יכול:

  1. השתמש tf.RaggedTensor.to_list כדי להמיר את הטנזור המרופט לרשימת Python מקוננת.
  2. השתמש tf.RaggedTensor.numpy כדי להמיר את הטנזור המרופט למערך NumPy שהערכים שלו הם מערכי NumPy מקוננים.
  3. לפרק את הטנזור המרופט למרכיביו, באמצעות המאפיינים tf.RaggedTensor.values ו- tf.RaggedTensor.row_splits , או שיטות חלוקת שורות כגון tf.RaggedTensor.row_lengths ו- tf.RaggedTensor.value_rowids .
  4. השתמש באינדקס של Python כדי לבחור ערכים מהטנזור המרופט.
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]
/tmpfs/src/tf_docs_env/lib/python3.7/site-packages/tensorflow/python/ops/ragged/ragged_tensor.py:2063: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  return np.array(rows)

שידור

שידור הוא תהליך של הפיכת טנסור עם צורות שונות לצורות תואמות לפעולות אלמנטיות. לרקע נוסף על שידור, עיין ב:

השלבים הבסיסיים לשידור של שני כניסות x ו- y כדי לקבל צורות תואמות הם:

  1. אם ל- x ול- y אין אותו מספר של מידות, הוסף מידות חיצוניות (עם מידה 1) עד שיהיו.

  2. עבור כל מימד שבו ל- x ול- y יש גדלים שונים:

  • אם ל- x או y יש גודל 1 בממד d , אז חזור על הערכים שלו על פני ממד d כדי להתאים לגודל הקלט האחר.
  • אחרת, העלה חריגה ( x ו- y אינם תואמים לשידור).

כאשר גודלו של טנזור בממד אחיד הוא מספר בודד (גודל הפרוסות על פני הממד הזה); והגודל של טנזור בממד מרופט הוא רשימה של אורכי פרוסה (עבור כל הפרוסות על פני הממד הזה).

דוגמאות לשידור

# 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]]]]>

הנה כמה דוגמאות לצורות שאינן משודרות:

# 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

טנזורים Ragged מקודדים באמצעות מחלקה RaggedTensor . באופן פנימי, כל RaggedTensor מורכב מ:

  • טנסור values , המשרשר את השורות באורך משתנה לרשימה שטוחה.
  • row_partition , אשר מציינת כיצד אותם ערכים שטוחים מחולקים לשורות.

קידוד RaggedTensor

ניתן לאחסן את row_partition באמצעות ארבעה קידודים שונים:

  • row_splits הוא וקטור שלם המציין את נקודות הפיצול בין שורות.
  • value_rowids הוא וקטור שלם המציין את אינדקס השורה עבור כל ערך.
  • row_lengths הוא וקטור שלם המציין את אורך כל שורה.
  • uniform_row_length הוא סקלאר שלם המציין אורך בודד עבור כל השורות.

קידודי row_partition

ניתן לכלול צמצום סקלרי של מספר שלם בקידוד nrows כדי row_partition בחשבון שורות עוקבות ריקות עם value_rowids או שורות ריקות עם 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]]>

הבחירה באיזה קידוד להשתמש עבור מחיצות שורות מנוהלת באופן פנימי על ידי טנזורים מרופטים כדי לשפר את היעילות בהקשרים מסוימים. בפרט, כמה מהיתרונות והחסרונות של סכימות חלוקת השורות השונות הן:

  • אינדקס יעיל : הקידוד row_splits מאפשר אינדקס בזמן קבוע וחיתוך לטנזורים מרופטים.
  • שרשור יעיל : קידוד row_lengths יעיל יותר בעת שרשור טנזורים מרופטים, מכיוון שאורכי השורות אינם משתנים כאשר שני טנסורים משורשרים יחדיו.
  • גודל קידוד קטן : הקידוד value_rowids יעיל יותר כאשר מאחסנים טנזורים מרופטים שיש להם מספר רב של שורות ריקות, מכיוון שגודל הטנזור תלוי רק במספר הערכים הכולל. מצד שני, row_splits ו- row_lengths יעילים יותר בעת אחסון טנזורים מרופטים עם שורות ארוכות יותר, מכיוון שהם דורשים רק ערך סקלארי אחד עבור כל שורה.
  • תאימות : ערכת value_rowids תואמת את פורמט הפילוח המשמש בפעולות, כגון tf.segment_sum . ערכת row_limits תואמת את הפורמט שבו משתמשים פעולות כגון tf.sequence_mask .
  • מידות אחידות : כפי שנדון להלן, הקידוד uniform_row_length משמש לקידוד טנזורים מרופטים עם מידות אחידות.

מידות מרופטות מרובות

טנסור מרופט עם מימדים מרובים מקודד על ידי שימוש ב- RaggedTensor מקונן עבור טנסור values . כל RaggedTensor מקונן מוסיף מימד מרופט יחיד.

קידוד של טנזור מרופט עם מימדים מרובים (דרגה 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

ניתן להשתמש בפונקציית היצרן tf.RaggedTensor.from_nested_row_splits לבניית RaggedTensor עם מימדים מרופטים מרובים ישירות על ידי אספקת רשימה של טנזורים 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]]]>

דרגה מרופדת וערכים שטוחים

הדירוג המרופט של טנסור מרופט הוא מספר הפעמים values הבסיסיים טנזור חולקו (כלומר עומק הקינון של אובייקטים RaggedTensor ). טנסור values הפנימיים ביותר ידוע בתור flat_values שלו. בדוגמה הבאה, conversations יש ragged_rank=3, וה- flat_values שלה הוא Tensor 1D עם 24 מחרוזות:

# 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)

מידות פנימיות אחידות

טנזורים מרופטים בעלי ממדים פנימיים אחידים מקודדים על ידי שימוש ב- tf.Tensor רב ממדי עבור ה-flat_values ​​(כלומר, values הפנימיים ביותר).

קידוד של טנזורים מרופטים במידות פנימיות אחידות

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]]

מידות לא פנימיות אחידות

טנזורים מרופטים עם ממדים אחידים שאינם פנימיים מקודדים על ידי חלוקת שורות עם uniform_row_length .

קידוד של טנזורים מרופטים בעלי מידות אחידות שאינן פנימיות

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