تنسورهای خراب

مشاهده در TensorFlow.org در Google Colab اجرا شود مشاهده منبع در GitHubدانلود دفترچه یادداشت

اسناد API: tf.RaggedTensor tf.ragged

برپایی

import math
import tensorflow as tf

بررسی اجمالی

داده های شما به اشکال مختلفی می آیند. تانسورهای شما نیز باید. تانسورهای Ragged معادل TensorFlow لیست‌های طول متغیر تودرتو هستند. آنها ذخیره و پردازش داده ها را با اشکال غیر یکنواخت آسان می کنند، از جمله:

  • ویژگی های با طول متغیر، مانند مجموعه بازیگران در یک فیلم.
  • دسته‌ای از ورودی‌های متوالی با طول متغیر، مانند جملات یا کلیپ‌های ویدیویی.
  • ورودی های سلسله مراتبی، مانند اسناد متنی که به بخش ها، پاراگراف ها، جملات و کلمات تقسیم می شوند.
  • فیلدهای مجزا در ورودی های ساخت یافته، مانند بافرهای پروتکل.

کاری که می توانید با یک تانسور ناهموار انجام دهید

تانسورهای Ragged توسط بیش از صد عملیات 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 مراجعه کنید.

تانسورهای Ragged توسط بسیاری از APIهای TensorFlow پشتیبانی می‌شوند، از جمله Keras ، Datasets ، tf.function ، SavedModels ، و tf.Example . برای اطلاعات بیشتر، بخش مربوط به API های TensorFlow را در زیر بررسی کنید.

همانند تانسورهای معمولی، می‌توانید از نمایه‌سازی به سبک پایتون برای دسترسی به برش‌های خاصی از یک تانسور ناهموار استفاده کنید. برای اطلاعات بیشتر به بخش نمایه سازی زیر مراجعه کنید.

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

و درست مانند تانسورهای معمولی، می‌توانید از عملگرهای محاسباتی و مقایسه پایتون برای انجام عملیات عنصری استفاده کنید. برای اطلاعات بیشتر، بخش اپراتورهای Overloaded را در زیر بررسی کنید.

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

تانسورهای Ragged را می توان به list های پایتون تودرتو و array NumPy تبدیل کرد:

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)

ساخت یک تانسور ناهموار

ساده ترین راه برای ساختن یک تانسور ragged استفاده از tf.ragged.constant است که RaggedTensor مربوط به یک list تودرتو پایتون یا 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']]]>

تانسورهای Ragged را می‌توان با جفت کردن تانسورهای مقادیر مسطح با تانسورهای تقسیم‌بندی ردیفی ساخت که نشان می‌دهد چگونه آن مقادیر باید به ردیف‌ها تقسیم شوند، با استفاده از روش‌های tf.RaggedTensor.from_row_splits کارخانه‌ای مانند tf.RaggedTensor.from_value_rowids ، tf.RaggedTensor.from_row_lengths .

tf.RaggedTensor.from_value_rowids

اگر می‌دانید هر مقدار به کدام ردیف تعلق دارد، می‌توانید با استفاده از یک تانسور تقسیم‌بندی ردیف value_rowids یک RaggedTensor بسازید:

تانسور پارتیشن بندی ردیف 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-partitioning استفاده کنید:

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 معمولی، مقادیر در یک 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, :] ) طول های مختلفی دارند. به ابعادی که برش های آن ها طول یکسانی دارند، ابعاد یکنواخت می گویند.

بیرونی‌ترین بعد یک تانسور ژنده‌دار همیشه یکنواخت است، زیرا از یک تکه تشکیل شده است (و بنابراین، هیچ امکانی برای طول‌های برش متفاوت وجود ندارد). ابعاد باقیمانده ممکن است ناهموار یا یکنواخت باشند. برای مثال، می‌توانید واژه‌های embeddings را برای هر کلمه در دسته‌ای از جملات با استفاده از یک تانسور ژنده‌دار با شکل [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 را برای یک تانسور ناهموار که در آن ابعاد ragged اندازه 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)

Ragged vs Sparse

یک تانسور ژنده‌دار نباید به عنوان نوعی تانسور پراکنده در نظر گرفته شود. به طور خاص، تانسورهای پراکنده کدگذاری کارآمدی برای tf.Tensor که همان داده‌ها را در قالب فشرده مدل‌سازی می‌کنند. اما تانسور ژنده‌دار یک پسوند tf.Tensor است که کلاس گسترده‌ای از داده‌ها را مدل‌سازی می‌کند. این تفاوت هنگام تعریف عملیات بسیار مهم است:

  • اعمال یک op روی یک تانسور پراکنده یا متراکم باید همیشه نتیجه یکسانی داشته باشد.
  • اعمال یک op روی یک تانسور ناهموار یا پراکنده ممکن است نتایج متفاوتی به همراه داشته باشد.

به عنوان یک مثال گویا، در نظر بگیرید که چگونه عملیات آرایه مانند 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 برای ساخت و آموزش مدل های یادگیری عمیق است. با تنظیم ragged ragged=True در tf.keras.Input یا tf.keras.layers.InputLayer ، تانسورهای Ragged ممکن است به عنوان ورودی به مدل Keras ارسال شوند. تانسورهای ناهموار نیز ممکن است از بین لایه‌های Keras عبور داده شوند و توسط مدل‌های Keras برگردانده شوند. مثال زیر یک مدل 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 یا NumPy array می‌شود، مانند 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]

دسته بندی و جداسازی مجموعه داده ها با تانسورهای ناهموار

مجموعه های داده با تانسورهای ناهموار را می توان با استفاده از روش Dataset.batch بندی کرد (که n عنصر متوالی را در یک عنصر واحد ترکیب می کند).

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، آن تانسورهای غیر ژنده‌دار را به تانسورهای 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 ، تانسورهای ناهموار را در Datasets ایجاد یا تبدیل کنید:

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 را برای توابع پایتون از قبل محاسبه می کند، که می تواند عملکرد کد TensorFlow شما را به طور قابل ملاحظه ای بهبود بخشد. تانسورهای پاره شده را می توان به صورت شفاف با توابع @tf.function -decorated استفاده کرد. به عنوان مثال، تابع زیر با هر دو تانسور ragged و non-ragged کار می کند:

@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 را برای 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]]>

SavedModels

SavedModel یک برنامه TensorFlow سریالی است که هم وزن و هم محاسبات را شامل می شود. می توان آن را از یک مدل Keras یا از یک مدل سفارشی ساخت. در هر صورت، تانسورهای پاره پاره شده را می توان به طور شفاف با توابع و روش های تعریف شده توسط SavedModel استفاده کرد.

مثال: ذخیره یک مدل Keras

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 عملگرهای محاسبه و مقایسه پایتون استاندارد را بارگذاری می کند و انجام ریاضیات پایه را آسان می کند:

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

برای بحث در مورد موارد پیشرفته تر، بخش پخش را بررسی کنید.

تانسورهای Ragged مجموعه ای از عملگرها را به عنوان Tensor معمولی بارگذاری می کنند: عملگرهای unary - ~ و abs() ; و عملگرهای باینری + , - , * , / , // , % , ** , & , | ، ^ ، == ، < ، <= ، > و >= .

نمایه سازی

تانسورهای Ragged از نمایه سازی به سبک پایتون، از جمله نمایه سازی چند بعدی و برش پشتیبانی می کنند. مثال‌های زیر نمایه‌سازی تانسور ناهموار را با یک تانسور دو بعدی و سه بعدی نشان می‌دهند.

مثال‌های نمایه‌سازی: تانسور ناهموار دوبعدی

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) از آن مقدار بگذرید و یک تانسور با ردیف‌های کمتر از آنچه که با آن شروع کرده‌اید برگردانید. با پیروی از اصول راهنمای پایتون ("در مواجهه با ابهام، از وسوسه حدس زدن خودداری کنید")، این عملیات در حال حاضر مجاز نیست.

تبدیل نوع تانسور

کلاس 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 برای تبدیل تانسور ناهموار به لیست پایتون تو در تو استفاده کنید.
  2. از tf.RaggedTensor.numpy برای تبدیل تانسور ناهموار به آرایه NumPy استفاده کنید که مقادیر آن آرایه های NumPy تو در تو هستند.
  3. با استفاده از tf.RaggedTensor.values و tf.RaggedTensor.row_splits یا روش‌های تقسیم‌بندی ردیف مانند tf.RaggedTensor.row_lengths و tf.RaggedTensor.value_rowids ، تانسور ragged را به اجزای آن تجزیه کنید.
  4. از نمایه سازی پایتون برای انتخاب مقادیر از تانسور ناهموار استفاده کنید.
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 1 بعدی با 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 چند بعدی برای مقادیر مسطح (یعنی درونی ترین 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