תקנות יישום נפוצות

דף זה מתאר את היישום הנפוץ gotcha בעת יישום מערך נתונים חדש.

יש להימנע SplitGenerator מדור קודם

ה-API הישן 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),
  }

נימוק : ה-API החדש הוא פחות מילולי ויותר מפורש. ה-API הישן יוסר בגרסה עתידית.

מערכי נתונים חדשים צריכים להיות עצמאיים בתיקייה

בעת הוספת מערך נתונים בתוך המאגר tensorflow_datasets/ , אנא הקפד לעקוב אחר מבנה מערך הנתונים כתיקיה (כל סכומי הבדיקה, נתוני הדמה, קוד היישום המוכל בתיקייה).

  • מערכי נתונים ישנים (פגועים): <category>/<ds_name>.py
  • מערכי נתונים חדשים (טובים): <category>/<ds_name>/<ds_name>.py

השתמש ב- TFDS CLI ( tfds new , או gtfds new for googlers) כדי ליצור את התבנית.

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

רשימות תיאור צריכות להיות בפורמט כ-markdown

ה- DatasetInfo.description str מעוצב כ-markdown. רשימות סימון מחייבות שורה ריקה לפני הפריט הראשון:

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

נימוק : תוויות קריאות לאדם משמשות במקומות רבים:

שכחת את צורת התמונה

בעת שימוש 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

במקום ה-API של tf.io.gfile , עדיף להשתמש ב- pathlib API . כל שיטות 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 הוא 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 ?

ייבוא ​​עצל ב-Python

אנו מייבאים בעצלתיים מודולים גדולים כמו 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