TFDS والحتمية

عرض على TensorFlow.org تشغيل في Google Colab عرض على جيثب تحميل دفتر

يوضح هذا المستند:

  • تضمن TFDS على الحتمية
  • في أي ترتيب تقرأ TFDS الأمثلة
  • محاذير ومتاعب مختلفة

يثبت

مجموعات البيانات

هناك حاجة إلى بعض السياق لفهم كيفية قراءة TFDS للبيانات.

خلال جيل، TFDS إرسال البيانات الأصلية إلى موحدة .tfrecord الملفات. لمجموعات البيانات الكبيرة، متعددة .tfrecord يتم إنشاء ملفات، كل منها يحتوي على أمثلة متعددة. ونحن ندعو كل .tfrecord ملف كسرة فخارية.

يستخدم هذا الدليل Imagenet الذي يحتوي على 1024 جزءًا:

import re
import tensorflow_datasets as tfds

imagenet = tfds.builder('imagenet2012')

num_shards = imagenet.info.splits['train'].num_shards
num_examples = imagenet.info.splits['train'].num_examples
print(f'imagenet has {num_shards} shards ({num_examples} examples)')
imagenet has 1024 shards (1281167 examples)

العثور على معرفات أمثلة مجموعة البيانات

يمكنك التخطي إلى القسم التالي إذا كنت تريد فقط معرفة الحتمية.

يتم تعريف كل سبيل المثال بيانات فريد من قبل id (على سبيل المثال 'imagenet2012-train.tfrecord-01023-of-01024__32' ). يمكنك استرداد هذه id عن طريق تمرير read_config.add_tfds_id = True والتي سوف تضيف 'tfds_id' المفتاح في ديكت من tf.data.Dataset .

في هذا البرنامج التعليمي ، نحدد استخدامًا صغيرًا يطبع أمثلة معرّفات مجموعة البيانات (المحولة بعدد صحيح ليكون أكثر قابلية للقراءة من قبل الإنسان):

الحتمية عند القراءة

يوضح هذا القسم ضمان deterministim من tfds.load .

مع shuffle_files=False (الافتراضي)

بواسطة TFDS الافتراضية تسفر أمثلة حتمي ( shuffle_files=False )

# Same as: imagenet.as_dataset(split='train').take(20)
print_ex_ids(imagenet, split='train', take=20)
print_ex_ids(imagenet, split='train', take=20)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1251, 1252, 1253, 1254]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1251, 1252, 1253, 1254]

للحصول على أداء، وقراءة TFDS شظايا متعددة في الوقت نفسه باستخدام tf.data.Dataset.interleave . ونحن نرى في هذا المثال أن TFDS التحول إلى قشرة 2 بعد قراءة 16 أمثلة ( ..., 14, 15, 1251, 1252, ... ). المزيد عن تداخل الخوار.

وبالمثل ، فإن واجهة برمجة التطبيقات الفرعية هي أيضًا حتمية:

print_ex_ids(imagenet, split='train[67%:84%]', take=20)
print_ex_ids(imagenet, split='train[67%:84%]', take=20)
[858382, 858383, 858384, 858385, 858386, 858387, 858388, 858389, 858390, 858391, 858392, 858393, 858394, 858395, 858396, 858397, 859533, 859534, 859535, 859536]
[858382, 858383, 858384, 858385, 858386, 858387, 858388, 858389, 858390, 858391, 858392, 858393, 858394, 858395, 858396, 858397, 859533, 859534, 859535, 859536]

إذا كنت تدريبية للعصر واحد أو أكثر، لا ينصح الإعداد أعلاه وجميع العهود وقراءة شظايا في نفس الترتيب (بحيث يقتصر العشوائية إلى ds = ds.shuffle(buffer) حجم المخزن المؤقت).

مع shuffle_files=True

مع shuffle_files=True ، وتعديلا شظايا لكل عصر، حتى القراءة ليست قطعية بعد الآن.

print_ex_ids(imagenet, split='train', shuffle_files=True, take=20)
print_ex_ids(imagenet, split='train', shuffle_files=True, take=20)
[568017, 329050, 329051, 329052, 329053, 329054, 329056, 329055, 568019, 568020, 568021, 568022, 568023, 568018, 568025, 568024, 568026, 568028, 568030, 568031]
[43790, 43791, 43792, 43793, 43796, 43794, 43797, 43798, 43795, 43799, 43800, 43801, 43802, 43803, 43804, 43805, 43806, 43807, 43809, 43810]

انظر الوصفة أدناه للحصول على الخلط الحتمي للملف.

تحذير الحتمية: تشذير الوسائط

تغيير read_config.interleave_cycle_length ، read_config.interleave_block_length ستغير أجل الأمثلة.

تعتمد TFDS على tf.data.Dataset.interleave لتحميل سوى بضع شظايا في آن واحد، وتحسين الأداء وتقليل استخدام الذاكرة.

الترتيب النموذجي مضمون فقط ليكون هو نفسه لقيمة ثابتة لرسومات التشذير. انظر وثيقة تعشيق لفهم ما cycle_length و block_length تتوافق أيضا.

  • cycle_length=16 ، block_length=16 (افتراضي، نفس النحو الوارد أعلاه):
print_ex_ids(imagenet, split='train', take=20)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1251, 1252, 1253, 1254]
  • cycle_length=3 ، block_length=2 :
read_config = tfds.ReadConfig(
    interleave_cycle_length=3,
    interleave_block_length=2,
)
print_ex_ids(imagenet, split='train', read_config=read_config, take=20)
[0, 1, 1251, 1252, 2502, 2503, 2, 3, 1253, 1254, 2504, 2505, 4, 5, 1255, 1256, 2506, 2507, 6, 7]

في المثال الثاني، ونحن نرى أن مجموعة البيانات قراءة 2 ( block_length=2 ) أمثلة في قشرة، ثم التبديل إلى قشرة المقبلة. كل 2 * 3 ( cycle_length=3 ) أمثلة، فإنه يعود إلى قشرة الأولى ( shard0-ex0, shard0-ex1, shard1-ex0, shard1-ex1, shard2-ex0, shard2-ex1, shard0-ex2, shard0-ex3, shard1-ex2, shard1-ex3, shard2-ex2,... ).

النظام الفرعي والمثال

كل المثال لديه معرف 0, 1, ..., num_examples-1 . و API subsplit اختيار شريحة من الأمثلة (مثل train[:x] حدد 0, 1, ..., x-1 ).

ومع ذلك ، داخل القسم الفرعي ، لا تتم قراءة الأمثلة بترتيب معرف متزايد (بسبب القطع والتداخل).

وبشكل أكثر تحديدا، ds.take(x) و split='train[:x]' لا يعادل!

يمكن رؤية هذا بسهولة في مثال التشذير أعلاه حيث تأتي الأمثلة من شظايا مختلفة.

print_ex_ids(imagenet, split='train', take=25)  # tfds.load(..., split='train').take(25)
print_ex_ids(imagenet, split='train[:25]', take=-1)  # tfds.load(..., split='train[:25]')
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24]

بعد 16 (block_length) أمثلة، .take(25) مفاتيح للقشرة المقبلة بينما train[:25] مواصلة القراءة أمثلة من الناحية قشرة الأولى.

وصفات

الحصول على ملف الخلط الحتمية

هناك طريقتان لإجراء خلط حتمي:

  1. وضع shuffle_seed . ملاحظة: هذا يتطلب تغيير البذرة في كل حقبة ، وإلا ستتم قراءة القطع بالترتيب نفسه بين الحقبة.
read_config = tfds.ReadConfig(
    shuffle_seed=32,
)

# Deterministic order, different from the default shuffle_files=False above
print_ex_ids(imagenet, split='train', shuffle_files=True, read_config=read_config, take=22)
print_ex_ids(imagenet, split='train', shuffle_files=True, read_config=read_config, take=22)
[176411, 176412, 176413, 176414, 176415, 176416, 176417, 176418, 176419, 176420, 176421, 176422, 176423, 176424, 176425, 176426, 710647, 710648, 710649, 710650, 710651, 710652]
[176411, 176412, 176413, 176414, 176415, 176416, 176417, 176418, 176419, 176420, 176421, 176422, 176423, 176424, 176425, 176426, 710647, 710648, 710649, 710650, 710651, 710652]
  1. باستخدام experimental_interleave_sort_fn : هذا يعطي السيطرة الكاملة على التي تقرأ شظايا وفي أي ترتيب، بدلا من الاعتماد على ds.shuffle النظام.
def _reverse_order(file_instructions):
  return list(reversed(file_instructions))

read_config = tfds.ReadConfig(
    experimental_interleave_sort_fn=_reverse_order,
)

# Last shard (01023-of-01024) is read first
print_ex_ids(imagenet, split='train', read_config=read_config, take=5)
[1279916, 1279917, 1279918, 1279919, 1279920]

احصل على خط أنابيب محدد وقابل للاستباق

هذا أكثر تعقيدا. لا يوجد حل سهل ومرض.

  1. دون ds.shuffle ومع خلط حتمية، من الناحية النظرية يجب أن يكون من الممكن الاعتماد على الأمثلة التي تم قراءة ونستنتج التي تم قراءة الأمثلة داخل في كل جزء (بوصفها وظيفة من cycle_length ، block_length والنظام قشرة). ثم skip ، take يمكن حقن لكل قشرة من خلال experimental_interleave_sort_fn .

  2. مع ds.shuffle فمن المحتمل المستحيل دون تعيد خط أنابيب التدريب بشكل كامل. فإن ذلك يتطلب توفير ds.shuffle دولة عازلة لنستنتج التي تم قراءة الأمثلة. أمثلة يمكن أن تكون غير المستمر (على سبيل المثال shard5_ex2 ، shard5_ex4 قراءة ولكن ليس shard5_ex3 ).

  3. مع ds.shuffle ، وهناك طريقة واحدة أن يكون على حفظ كافة shards_ids / example_ids قراءة (استنتاجها من tfds_id )، ثم استنتاج تعليمات ملف من ذلك.

أبسط الحالات ل 1. هو أن يكون .skip(x).take(y) مباراة train[x:x+y] مباراة. يتطلب:

  • مجموعة cycle_length=1 (بحيث تتم قراءة شظايا بالتتابع)
  • مجموعة shuffle_files=False
  • لا تستخدم ds.shuffle

يجب استخدامه فقط في مجموعة بيانات ضخمة حيث يكون التدريب فترة واحدة فقط. ستتم قراءة الأمثلة بالترتيب العشوائي الافتراضي.

read_config = tfds.ReadConfig(
    interleave_cycle_length=1,  # Read shards sequentially
)

print_ex_ids(imagenet, split='train', read_config=read_config, skip=40, take=22)
# If the job get pre-empted, using the subsplit API will skip at most `len(shard0)`
print_ex_ids(imagenet, split='train[40:]', read_config=read_config, take=22)
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61]
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61]

ابحث عن الأجزاء / الأمثلة التي تمت قراءتها لقسم فرعي معين

مع tfds.core.DatasetInfo ، لديك إمكانية الوصول المباشر إلى تعليمات القراءة.

imagenet.info.splits['train[44%:45%]'].file_instructions
[FileInstruction(filename='imagenet2012-train.tfrecord-00450-of-01024', skip=700, take=-1, num_examples=551),
 FileInstruction(filename='imagenet2012-train.tfrecord-00451-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00452-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00453-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00454-of-01024', skip=0, take=-1, num_examples=1252),
 FileInstruction(filename='imagenet2012-train.tfrecord-00455-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00456-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00457-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00458-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00459-of-01024', skip=0, take=-1, num_examples=1251),
 FileInstruction(filename='imagenet2012-train.tfrecord-00460-of-01024', skip=0, take=1001, num_examples=1001)]