דף זה מתאר את היישום הנפוץ 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', ...]),
}
נימוק : תוויות קריאות לאדם משמשות במקומות רבים:
- אפשר להניב
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
במקום ה-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