مسكات التنفيذ المشتركة

تصف هذه الصفحة مشكلة التنفيذ الشائعة عند تنفيذ مجموعة بيانات جديدة.

ينبغي تجنب Legacy SplitGenerator

تم إهمال واجهة برمجة التطبيقات tfds.core.SplitGenerator القديمة.

def _split_generator(...):
  return [
      tfds.core.SplitGenerator(name='train', gen_kwargs={'path': train_path}),
      tfds.core.SplitGenerator(name='test', gen_kwargs={'path': test_path}),
  ]

يجب استبداله بـ:

def _split_generator(...):
  return {
      'train': self._generate_examples(path=train_path),
      'test': self._generate_examples(path=test_path),
  }

الأساس المنطقي : واجهة برمجة التطبيقات الجديدة أقل تفصيلاً وأكثر وضوحًا. ستتم إزالة واجهة برمجة التطبيقات القديمة في الإصدار المستقبلي.

يجب أن تكون مجموعات البيانات الجديدة قائمة بذاتها في مجلد

عند إضافة مجموعة بيانات داخل مستودع tensorflow_datasets/ ، يرجى التأكد من اتباع بنية مجموعة البيانات كمجلد (جميع المجاميع الاختبارية، والبيانات الوهمية، وكود التنفيذ موجود بذاته في مجلد).

  • مجموعات البيانات القديمة (سيئة): <category>/<ds_name>.py
  • مجموعات البيانات الجديدة (جيدة): <category>/<ds_name>/<ds_name>.py

استخدم TFDS CLI ( tfds new أو gtfds new لموظفي Google) لإنشاء القالب.

الأساس المنطقي : تطلب الهيكل القديم مسارات مطلقة للمجموعات الاختبارية والبيانات المزيفة وكان يوزع ملفات مجموعة البيانات في العديد من الأماكن. كان ذلك يزيد من صعوبة تنفيذ مجموعات البيانات خارج مستودع TFDS. ومن أجل تحقيق الاتساق، ينبغي استخدام الهيكل الجديد في كل مكان الآن.

يجب أن يتم تنسيق قوائم الوصف كتخفيض

تم تنسيق str DatasetInfo.description كتخفيض. تتطلب قوائم تخفيض السعر سطرًا فارغًا قبل العنصر الأول:

_DESCRIPTION = """
Some text.
                      # << Empty line here !!!
1. Item 1
2. Item 1
3. Item 1
                      # << Empty line here !!!
Some other text.
"""

الأساس المنطقي : يؤدي الوصف المنسق بشكل سيئ إلى إنشاء عناصر مرئية في وثائق الكتالوج الخاص بنا. بدون الأسطر الفارغة، سيتم تقديم النص أعلاه على النحو التالي:

بعض النصوص. 1. البند 1 2. البند 1 3. البند 1 بعض النصوص الأخرى

نسيت أسماء ClassLabel

عند استخدام tfds.features.ClassLabel ، حاول توفير التسميات التي يمكن قراءتها str الإنسان مع names= أو names_file= (بدلاً من num_classes=10 ).

features = {
    'label': tfds.features.ClassLabel(names=['dog', 'cat', ...]),
}

الأساس المنطقي : يتم استخدام العلامات القابلة للقراءة البشرية في العديد من الأماكن:

  • السماح بإنتاج str مباشرة في _generate_examples : yield {'label': 'dog'}
  • مكشوف لدى المستخدمين مثل info.features['label'].names (طريقة التحويل .str2int('dog') ،... متاحة أيضًا)
  • يُستخدم في أدوات التصور tfds.show_examples و tfds.as_dataframe

نسيت شكل الصورة

عند استخدام tfds.features.Image ، tfds.features.Video ، إذا كانت الصور ذات شكل ثابت، فيجب تحديدها بوضوح:

features = {
    'image': tfds.features.Image(shape=(256, 256, 3)),
}

الأساس المنطقي : يسمح باستدلال شكل ثابت (على سبيل المثال ds.element_spec['image'].shape )، وهو أمر مطلوب للتجميع (قد يتطلب تجميع الصور ذات الشكل غير المعروف تغيير حجمها أولاً).

تفضل نوع أكثر تحديدًا بدلاً من tfds.features.Tensor

عندما يكون ذلك ممكنًا، فضل الأنواع الأكثر تحديدًا tfds.features.ClassLabel ، tfds.features.BBoxFeatures ،... بدلاً من tfds.features.Tensor العام.

الأساس المنطقي : بالإضافة إلى كونها أكثر صحة من الناحية الدلالية، توفر الميزات المحددة بيانات تعريف إضافية للمستخدمين ويتم اكتشافها بواسطة الأدوات.

الواردات الكسولة في الفضاء العالمي

لا ينبغي استدعاء الواردات الكسولة من الفضاء العالمي. على سبيل المثال ما يلي خطأ:

tfds.lazy_imports.apache_beam # << Error: Import beam in the global scope

def f() -> beam.Map:
  ...

الأساس المنطقي : سيؤدي استخدام الواردات البطيئة في النطاق العالمي إلى استيراد الوحدة النمطية لجميع مستخدمي tfds، مما يؤدي إلى إبطال غرض الواردات البطيئة.

الحوسبة الديناميكية لتقسيمات التدريب/الاختبار

إذا كانت مجموعة البيانات لا توفر تقسيمات رسمية، فلا ينبغي لـ TFDS أيضًا. ويجب تجنب ما يلي:

_TRAIN_TEST_RATIO = 0.7

def _split_generator():
  ids = list(range(num_examples))
  np.random.RandomState(seed).shuffle(ids)

  # Split train/test
  train_ids = ids[_TRAIN_TEST_RATIO * num_examples:]
  test_ids = ids[:_TRAIN_TEST_RATIO * num_examples]
  return {
      'train': self._generate_examples(train_ids),
      'test': self._generate_examples(test_ids),
  }

الأساس المنطقي : تحاول TFDS توفير مجموعات بيانات قريبة من البيانات الأصلية. يجب استخدام واجهة برمجة التطبيقات المقسمة فرعيًا بدلاً من ذلك للسماح للمستخدمين بإنشاء الأقسام الفرعية التي يريدونها ديناميكيًا:

ds_train, ds_test = tfds.load(..., split=['train[:80%]', 'train[80%:]'])

دليل أسلوب بايثون

تفضل استخدام pathlib API

بدلاً من واجهة برمجة التطبيقات tf.io.gfile ، يُفضل استخدام واجهة برمجة التطبيقات pathlib . تقوم جميع أساليب dl_manager بإرجاع كائنات شبيهة بـ pathlib متوافقة مع GCS وS3 و...

path = dl_manager.download_and_extract('http://some-website/my_data.zip')

json_path = path / 'data/file.json'

json.loads(json_path.read_text())

الأساس المنطقي : Pathlib API عبارة عن واجهة برمجة تطبيقات حديثة للملفات الموجهة للكائنات والتي تزيل النموذج المعياري. باستخدام .read_text() / .read_bytes() يضمن أيضًا إغلاق الملفات بشكل صحيح.

إذا كانت الطريقة لا تستخدم self ، فيجب أن تكون دالة

إذا كانت طريقة الفصل لا تستخدم self ، فيجب أن تكون دالة بسيطة (محددة خارج الفصل).

الأساس المنطقي : يوضح للقارئ أن الوظيفة ليس لها آثار جانبية، ولا مدخلات/مخرجات مخفية:

x = f(y)  # Clear inputs/outputs

x = self.f(y)  # Does f depend on additional hidden variables ? Is it stateful ?

الواردات الكسولة في بايثون

نحن نستورد بتكاسل وحدات كبيرة مثل TensorFlow. تعمل عمليات الاستيراد البطيئة على تأجيل الاستيراد الفعلي للوحدة إلى الاستخدام الأول للوحدة. لذا فإن المستخدمين الذين لا يحتاجون إلى هذه الوحدة الكبيرة لن يقوموا باستيرادها أبدًا. نحن نستخدم etils.epy.lazy_imports .

from tensorflow_datasets.core.utils.lazy_imports_utils import tensorflow as tf
# After this statement, TensorFlow is not imported yet

...

features = tfds.features.Image(dtype=tf.uint8)
# After using it (`tf.uint8`), TensorFlow is now imported

تحت الغطاء، تعمل فئة LazyModule كمصنع، والذي سيستورد الوحدة فعليًا فقط عند الوصول إلى إحدى السمات ( __getattr__ ).

يمكنك أيضًا استخدامه بسهولة مع مدير السياق:

from etils import epy

with epy.lazy_imports(error_callback=..., success_callback=...):
  import some_big_module