نوشتن مجموعه داده های سفارشی

این راهنما را برای ایجاد یک مجموعه داده جدید (چه در TFDS یا در مخزن خود) دنبال کنید.

لیست مجموعه داده های ما را بررسی کنید تا ببینید آیا مجموعه داده مورد نظر شما از قبل وجود دارد یا خیر.

TL; DR

ساده ترین راه برای نوشتن یک مجموعه داده جدید استفاده از TFDS CLI است:

cd path/to/my/project/datasets/
tfds new my_dataset  # Create `my_dataset/my_dataset.py` template files
# [...] Manually modify `my_dataset/my_dataset_dataset_builder.py` to implement your dataset.
cd my_dataset/
tfds build  # Download and prepare the dataset to `~/tensorflow_datasets/`

برای استفاده از مجموعه داده جدید با tfds.load('my_dataset') :

  • tfds.load به طور خودکار مجموعه داده تولید شده در ~/tensorflow_datasets/my_dataset/ شناسایی و بارگذاری می کند (مثلاً توسط tfds build ).
  • از طرف دیگر، می‌توانید صراحتاً import my.project.datasets.my_dataset :
import my.project.datasets.my_dataset  # Register `my_dataset`

ds = tfds.load('my_dataset')  # `my_dataset` registered

بررسی اجمالی

مجموعه‌های داده در انواع فرمت‌ها و در انواع مکان‌ها توزیع می‌شوند، و همیشه در قالبی ذخیره نمی‌شوند که آماده ورود به خط لوله یادگیری ماشین باشد. TFDS را وارد کنید.

TFDS آن مجموعه داده‌ها را در قالبی استاندارد پردازش می‌کند (داده‌های خارجی -> فایل‌های سریالی)، که سپس می‌تواند به عنوان خط لوله یادگیری ماشین بارگیری شود (فایل‌های سریال -> tf.data.Dataset ). سریال سازی فقط یک بار انجام می شود. دسترسی بعدی مستقیماً از آن فایل های از پیش پردازش شده خوانده می شود.

بیشتر پیش پردازش ها به صورت خودکار انجام می شود. هر مجموعه داده یک زیر کلاس از tfds.core.DatasetBuilder را پیاده سازی می کند که مشخص می کند:

  • داده ها از کجا می آیند (یعنی URL های آن).
  • آنچه مجموعه داده به نظر می رسد (یعنی ویژگی های آن).
  • چگونه داده ها باید تقسیم شوند (به عنوان مثال TRAIN و TEST ).
  • و نمونه های فردی در مجموعه داده.

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

قالب پیش فرض: tfds new

از TFDS CLI برای تولید فایل های پایتون قالب مورد نیاز استفاده کنید.

cd path/to/project/datasets/  # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset

این دستور یک پوشه my_dataset/ جدید با ساختار زیر ایجاد می کند:

my_dataset/
    __init__.py
    README.md # Markdown description of the dataset.
    CITATIONS.bib # Bibtex citation for the dataset.
    TAGS.txt # List of tags describing the dataset.
    my_dataset_dataset_builder.py # Dataset definition
    my_dataset_dataset_builder_test.py # Test
    dummy_data/ # (optional) Fake data (used for testing)
    checksum.tsv # (optional) URL checksums (see `checksums` section).

TODO(my_dataset) را در اینجا جستجو کنید و بر اساس آن اصلاح کنید.

نمونه مجموعه داده

همه مجموعه‌های داده زیر کلاس‌های tfds.core.DatasetBuilder هستند که از بیشتر دیگ‌های بخار مراقبت می‌کند. پشتیبانی می کند:

  • مجموعه داده های کوچک/متوسط ​​که می توانند روی یک ماشین تولید شوند (این آموزش).
  • مجموعه داده‌های بسیار بزرگ که نیاز به تولید پراکنده دارند (با استفاده از پرتو Apache ، به راهنمای مجموعه داده عظیم ما مراجعه کنید)

در اینجا یک نمونه حداقلی از سازنده مجموعه داده است که بر اساس tfds.core.GeneratorBasedBuilder است:

class Builder(tfds.core.GeneratorBasedBuilder):
  """DatasetBuilder for my_dataset dataset."""

  VERSION = tfds.core.Version('1.0.0')
  RELEASE_NOTES = {
      '1.0.0': 'Initial release.',
  }

  def _info(self) -> tfds.core.DatasetInfo:
    """Dataset metadata (homepage, citation,...)."""
    return self.dataset_info_from_configs(
        features=tfds.features.FeaturesDict({
            'image': tfds.features.Image(shape=(256, 256, 3)),
            'label': tfds.features.ClassLabel(
                names=['no', 'yes'],
                doc='Whether this is a picture of a cat'),
        }),
    )

  def _split_generators(self, dl_manager: tfds.download.DownloadManager):
    """Download the data and define splits."""
    extracted_path = dl_manager.download_and_extract('http://data.org/data.zip')
    # dl_manager returns pathlib-like objects with `path.read_text()`,
    # `path.iterdir()`,...
    return {
        'train': self._generate_examples(path=extracted_path / 'train_images'),
        'test': self._generate_examples(path=extracted_path / 'test_images'),
    }

  def _generate_examples(self, path) -> Iterator[Tuple[Key, Example]]:
    """Generator of examples for each split."""
    for img_path in path.glob('*.jpeg'):
      # Yields (key, example)
      yield img_path.name, {
          'image': img_path,
          'label': 'yes' if img_path.name.startswith('yes_') else 'no',
      }

توجه داشته باشید که برای برخی از فرمت‌های داده خاص، سازنده‌های داده آماده استفاده را برای مراقبت از بیشتر پردازش داده‌ها ارائه می‌کنیم.

بیایید 3 روش انتزاعی برای بازنویسی را با جزئیات ببینیم.

_info : فراداده مجموعه داده

_info tfds.core.DatasetInfo حاوی متادیتای مجموعه داده را برمی گرداند.

def _info(self):
  # The `dataset_info_from_configs` base method will construct the
  # `tfds.core.DatasetInfo` object using the passed-in parameters and
  # adding: builder (self), description/citations/tags from the config
  # files located in the same package.
  return self.dataset_info_from_configs(
      homepage='https://dataset-homepage.org',
      features=tfds.features.FeaturesDict({
          'image_description': tfds.features.Text(),
          'image': tfds.features.Image(),
          # Here, 'label' can be 0-4.
          'label': tfds.features.ClassLabel(num_classes=5),
      }),
      # If there's a common `(input, target)` tuple from the features,
      # specify them here. They'll be used if as_supervised=True in
      # builder.as_dataset.
      supervised_keys=('image', 'label'),
      # Specify whether to disable shuffling on the examples. Set to False by default.
      disable_shuffling=False,
  )

بیشتر زمینه ها باید خود توضیحی باشند. برخی از دقت ها:

نوشتن فایل BibText CITATIONS.bib :

  • وب سایت مجموعه داده را برای دستورالعمل استناد جستجو کنید (از آن در قالب BibTex استفاده کنید).
  • برای مقالات arXiv : مقاله را پیدا کنید و روی پیوند BibText در سمت راست کلیک کنید.
  • مقاله را در Google Scholar پیدا کنید و روی علامت نقل قول دوگانه در زیر عنوان کلیک کنید و در پنجره بازشو روی BibTeX کلیک کنید.
  • اگر کاغذ مرتبطی وجود ندارد (به عنوان مثال، فقط یک وب سایت وجود دارد)، می توانید از ویرایشگر آنلاین BibTeX برای ایجاد یک ورودی سفارشی BibTeX استفاده کنید (منوی کشویی دارای یک نوع ورودی Online است).

به روز رسانی فایل TAGS.txt :

  • تمامی تگ های مجاز از قبل در فایل تولید شده پر شده اند.
  • تمام برچسب هایی را که در مجموعه داده اعمال نمی شود حذف کنید.
  • برچسب‌های معتبر در tensorflow_datasets/core/valid_tags.txt فهرست شده‌اند.
  • برای افزودن یک برچسب به آن لیست، لطفا یک PR ارسال کنید.

نظم مجموعه داده را حفظ کنید

به‌طور پیش‌فرض، رکوردهای مجموعه‌های داده هنگام ذخیره می‌شوند تا توزیع کلاس‌ها در سراسر مجموعه داده یکنواخت‌تر شود، زیرا اغلب رکوردهای متعلق به یک کلاس به هم پیوسته هستند. برای اینکه مشخص شود مجموعه داده باید بر اساس کلید ایجاد شده توسط _generate_examples مرتب شود، فیلد disable_shuffling باید روی True تنظیم شود. به طور پیش فرض روی False تنظیم شده است.

def _info(self):
  return self.dataset_info_from_configs(
    # [...]
    disable_shuffling=True,
    # [...]
  )

به خاطر داشته باشید که غیرفعال کردن درهم‌رفتن تأثیری بر عملکرد دارد زیرا دیگر نمی‌توان خرده‌ها را به صورت موازی خواند.

_split_generators : دانلود و تقسیم داده ها

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

اکثر مجموعه داده ها نیاز به دانلود داده ها از وب دارند. این کار با استفاده از آرگومان ورودی tfds.download.DownloadManager از _split_generators انجام می شود. dl_manager روش های زیر را دارد:

  • download : از http(s):// , ftp(s):// پشتیبانی می کند
  • extract : در حال حاضر از فایل های .zip ، .gz ، و .tar پشتیبانی می کند.
  • download_and_extract : مانند dl_manager.extract(dl_manager.download(urls))

همه آن متدها tfds.core.Path (مستعار برای epath.Path ) را برمی گرداند که اشیایی شبیه pathlib.Path هستند.

این متدها از ساختار تودرتو دلخواه ( list ، dict ) پشتیبانی می کنند، مانند:

extracted_paths = dl_manager.download_and_extract({
    'foo': 'https://example.com/foo.zip',
    'bar': 'https://example.com/bar.zip',
})
# This returns:
assert extracted_paths == {
    'foo': Path('/path/to/extracted_foo/'),
    'bar': Path('/path/extracted_bar/'),
}

دانلود دستی و استخراج

برخی از داده ها را نمی توان به طور خودکار بارگیری کرد (مثلاً نیاز به ورود به سیستم دارد)، در این حالت، کاربر به صورت دستی داده های منبع را دانلود می کند و آن را در manual_dir/ قرار می دهد (به طور پیش فرض ~/tensorflow_datasets/downloads/manual/ ).

سپس از طریق dl_manager.manual_dir می توان به فایل ها دسترسی داشت:

class MyDataset(tfds.core.GeneratorBasedBuilder):

  MANUAL_DOWNLOAD_INSTRUCTIONS = """
  Register into https://example.org/login to get the data. Place the `data.zip`
  file in the `manual_dir/`.
  """

  def _split_generators(self, dl_manager):
    # data_path is a pathlib-like `Path('<manual_dir>/data.zip')`
    archive_path = dl_manager.manual_dir / 'data.zip'
    # Extract the manually downloaded `data.zip`
    extracted_path = dl_manager.extract(archive_path)
    ...

مکان manual_dir را می توان با tfds build --manual_dir= یا با استفاده از tfds.download.DownloadConfig سفارشی کرد.

بایگانی را مستقیم بخوانید

dl_manager.iter_archive یک بایگانی را به صورت متوالی بدون استخراج آنها می خواند. این می تواند فضای ذخیره سازی را ذخیره کند و عملکرد برخی از سیستم های فایل را بهبود بخشد.

for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
  ...

fobj همان روش‌هایی را دارد که with open('rb') as fobj: (مثلا fobj.read() )

تعیین تقسیم داده ها

اگر مجموعه داده با تقسیم‌های از پیش تعریف‌شده همراه است (مثلاً MNIST دارای تقسیم‌های train و test است)، آن‌ها را نگه دارید. در غیر این صورت، فقط یک all split را مشخص کنید. کاربران می توانند به صورت پویا زیرشاخه های خود را با subsplit API ایجاد کنند (به عنوان مثال split='train[80%:]' ). توجه داشته باشید که هر رشته الفبایی را می توان به عنوان نام تقسیم شده استفاده کرد، جدا از all موارد فوق.

def _split_generators(self, dl_manager):
  # Download source data
  extracted_path = dl_manager.download_and_extract(...)

  # Specify the splits
  return {
      'train': self._generate_examples(
          images_path=extracted_path / 'train_imgs',
          label_path=extracted_path / 'train_labels.csv',
      ),
      'test': self._generate_examples(
          images_path=extracted_path / 'test_imgs',
          label_path=extracted_path / 'test_labels.csv',
      ),
  }

_generate_examples : مولد نمونه

_generate_examples نمونه هایی را برای هر تقسیم از داده های منبع تولید می کند.

این روش معمولاً مصنوعات مجموعه داده منبع (مثلاً یک فایل CSV) را می خواند و چند تاپل (key, feature_dict) را به دست می آورد:

  • key : شناسه نمونه. برای به هم زدن قطعی مثال‌ها با استفاده از hash(key) یا برای مرتب‌سازی بر اساس کلید در صورت غیرفعال‌سازی به هم زدن استفاده می‌شود (به بخش حفظ ترتیب مجموعه داده‌ها مراجعه کنید). باید باشد:
    • منحصر به فرد : اگر دو مثال از یک کلید استفاده کنند، یک استثنا ایجاد می شود.
    • قطعی : نباید به ترتیب download_dir ، os.path.listdir وابسته باشد،... با تولید دوبار داده باید همان کلید را به دست آورد.
    • comparable : در صورت غیرفعال بودن درهم‌رفتن، از کلید برای مرتب‌سازی مجموعه داده استفاده می‌شود.
  • feature_dict : dict که حاوی مقادیر مثال است.
    • ساختار باید با features= ساختار تعریف شده در tfds.core.DatasetInfo مطابقت داشته باشد.
    • انواع داده های پیچیده (تصویر، ویدئو، صدا،...) به طور خودکار کدگذاری می شوند.
    • هر ویژگی اغلب انواع ورودی را می‌پذیرد (مثلاً پذیرش /path/to/vid.mp4 ، np.array(shape=(l, h, w, c)) ، List[paths] ، List[np.array(shape=(h, w, c)] ، List[img_bytes] ،...)
    • برای اطلاعات بیشتر ، راهنمای اتصال ویژگی را ببینید.
def _generate_examples(self, images_path, label_path):
  # Read the input data out of the source files
  with label_path.open() as f:
    for row in csv.DictReader(f):
      image_id = row['image_id']
      # And yield (key, feature_dict)
      yield image_id, {
          'image_description': row['description'],
          'image': images_path / f'{image_id}.jpeg',
          'label': row['label'],
      }

دسترسی به فایل و tf.io.gfile

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

در عوض، dl_manager اشیایی شبیه pathlib را که مستقیماً با فضای ذخیره‌سازی Google Cloud سازگار هستند، برمی‌گرداند:

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

json_path = path / 'data/file.json'

json.loads(json_path.read_text())

از طرف دیگر، از tf.io.gfile API به جای داخلی برای عملیات فایل استفاده کنید:

Pathlib باید به tf.io.gfile ترجیح داده شود (به rational مراجعه کنید.

وابستگی های اضافی

برخی از مجموعه‌های داده فقط در طول تولید به وابستگی‌های اضافی پایتون نیاز دارند. به عنوان مثال، مجموعه داده SVHN از scipy برای بارگذاری برخی از داده ها استفاده می کند.

اگر مجموعه داده را به مخزن TFDS اضافه می‌کنید، لطفاً از tfds.core.lazy_imports برای کوچک نگه داشتن بسته tensorflow-datasets استفاده کنید. کاربران فقط در صورت نیاز وابستگی های اضافی را نصب می کنند.

برای استفاده از lazy_imports :

  • یک ورودی برای مجموعه داده خود به DATASET_EXTRAS در setup.py اضافه کنید. این باعث می‌شود که کاربران بتوانند، برای مثال، pip install 'tensorflow-datasets[svhn]' برای نصب وابستگی‌های اضافی انجام دهند.
  • یک ورودی برای واردات خود به LazyImporter و به LazyImportsTest اضافه کنید.
  • از tfds.core.lazy_imports برای دسترسی به وابستگی (مثلا tfds.core.lazy_imports.scipy ) در DatasetBuilder خود استفاده کنید.

داده های خراب

برخی از مجموعه‌های داده کاملاً تمیز نیستند و حاوی برخی داده‌های خراب هستند (به عنوان مثال، تصاویر در فایل‌های JPEG هستند اما برخی از آنها JPEG نامعتبر هستند). این نمونه ها باید نادیده گرفته شوند، اما در توضیحات مجموعه داده یادداشت کنید که چند نمونه حذف شده و چرا.

پیکربندی/انواع مجموعه داده (tfds.core.BuilderConfig)

برخی از مجموعه‌های داده ممکن است چندین گونه یا گزینه‌هایی برای نحوه پیش‌پردازش داده‌ها و نوشتن روی دیسک داشته باشند. برای مثال، cycle_gan یک پیکربندی برای هر جفت شی دارد ( cycle_gan/horse2zebra ، cycle_gan/monet2photo ،...).

این کار از طریق tfds.core.BuilderConfig انجام می شود:

  1. شی پیکربندی خود را به عنوان زیر کلاس tfds.core.BuilderConfig تعریف کنید. به عنوان مثال، MyDatasetConfig .

    @dataclasses.dataclass
    class MyDatasetConfig(tfds.core.BuilderConfig):
      img_size: Tuple[int, int] = (0, 0)
    
  2. عضو کلاس BUILDER_CONFIGS = [] را در MyDataset تعریف کنید که MyDatasetConfig هایی را که مجموعه داده نشان می دهد لیست می کند.

    class MyDataset(tfds.core.GeneratorBasedBuilder):
      VERSION = tfds.core.Version('1.0.0')
      # pytype: disable=wrong-keyword-args
      BUILDER_CONFIGS = [
          # `name` (and optionally `description`) are required for each config
          MyDatasetConfig(name='small', description='Small ...', img_size=(8, 8)),
          MyDatasetConfig(name='big', description='Big ...', img_size=(32, 32)),
      ]
      # pytype: enable=wrong-keyword-args
    
  3. از self.builder_config در MyDataset برای پیکربندی تولید داده استفاده کنید (به عنوان مثال shape=self.builder_config.img_size ). این ممکن است شامل تنظیم مقادیر مختلف در _info() یا تغییر دسترسی به داده های دانلود باشد.

یادداشت:

  • هر پیکربندی یک نام منحصر به فرد دارد. نام کاملاً واجد شرایط یک پیکربندی dataset_name/config_name است (به عنوان مثال coco/2017 ).
  • اگر مشخص نشده باشد، اولین پیکربندی در BUILDER_CONFIGS استفاده خواهد شد (به عنوان مثال tfds.load('c4') پیش‌فرض c4/en )

برای مثالی از مجموعه داده ای که از BuilderConfig s استفاده می کند، anli را ببینید.

نسخه

نسخه می تواند به دو معنای متفاوت اشاره داشته باشد:

  • نسخه داده اصلی "خارجی": به عنوان مثال COCO v2019، v2017،...
  • نسخه کد TFDS "داخلی": به عنوان مثال تغییر نام یک ویژگی در tfds.features.FeaturesDict ، رفع اشکال در _generate_examples

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

  • برای به روز رسانی داده های "خارجی": ممکن است چندین کاربر بخواهند به طور همزمان به یک سال/نسخه خاص دسترسی داشته باشند. این کار با استفاده از یک tfds.core.BuilderConfig در هر نسخه (به عنوان مثال coco/2017 ، coco/2019 ) یا یک کلاس در هر نسخه (مثلا Voc2007 ، Voc2012 ) انجام می شود.
  • برای به روز رسانی کد "داخلی": کاربران فقط آخرین نسخه را دانلود می کنند. هر به‌روزرسانی کد باید ویژگی کلاس VERSION را افزایش دهد (مثلاً از 1.0.0 به VERSION = tfds.core.Version('2.0.0') ) پس از نسخه‌سازی معنایی .

یک واردات برای ثبت اضافه کنید

فراموش نکنید که ماژول مجموعه داده را به پروژه __init__ خود وارد کنید تا به طور خودکار در tfds.load ، tfds.builder ثبت شود.

import my_project.datasets.my_dataset  # Register MyDataset

ds = tfds.load('my_dataset')  # MyDataset available

برای مثال، اگر در tensorflow/datasets مشارکت می‌کنید، وارد کردن ماژول را به فهرست فرعی __init__.py آن اضافه کنید (مثلاً image/__init__.py .

گوچاهای پیاده سازی رایج را بررسی کنید

لطفاً گوچاهای پیاده سازی رایج را بررسی کنید.

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

دانلود و آماده سازی: tfds build

برای تولید مجموعه داده، tfds build از پوشه my_dataset/ اجرا کنید:

cd path/to/datasets/my_dataset/
tfds build --register_checksums

برخی از پرچم های مفید برای توسعه:

  • --pdb : در صورت وجود استثنا، وارد حالت اشکال زدایی شوید.
  • --overwrite : اگر مجموعه داده قبلاً تولید شده باشد، فایل های موجود را حذف کنید.
  • --max_examples_per_split : فقط اولین نمونه های X را تولید کنید (به طور پیش فرض 1)، به جای مجموعه داده کامل.
  • --register_checksums : چک جمع های آدرس های دانلود شده را ضبط کنید. فقط باید در حین توسعه استفاده شود.

برای فهرست کامل پرچم‌ها به مستندات CLI مراجعه کنید.

جمع های چک

توصیه می‌شود جمع‌های کنترلی مجموعه داده‌های خود را برای تضمین قطعیت، کمک به مستندسازی،... این کار با تولید مجموعه داده با --register_checksums انجام می‌شود (به بخش قبلی مراجعه کنید).

اگر مجموعه داده های خود را از طریق PyPI منتشر می کنید، فراموش نکنید که فایل های checksums.tsv را صادر کنید (مثلاً در package_data setup.py خود).

مجموعه داده خود را واحد آزمایش کنید

tfds.testing.DatasetBuilderTestCase یک TestCase پایه برای اعمال کامل مجموعه داده است. از "داده های ساختگی" به عنوان داده های آزمایشی استفاده می کند که ساختار مجموعه داده منبع را تقلید می کند.

  • داده‌های آزمایشی باید در فهرست راهنمای my_dataset/dummy_data/ قرار داده شوند و باید از مصنوعات مجموعه داده منبع در هنگام دانلود و استخراج تقلید کنند. می توان آن را به صورت دستی یا خودکار با یک اسکریپت ایجاد کرد ( اسکریپت مثال ).
  • مطمئن شوید که از داده‌های متفاوتی در تقسیم‌بندی داده‌های آزمایشی خود استفاده می‌کنید، زیرا در صورت همپوشانی تقسیم داده‌های شما، آزمایش با شکست مواجه می‌شود.
  • داده های آزمون نباید حاوی مطالب دارای حق چاپ باشد . اگر شک دارید، داده ها را با استفاده از مواد از مجموعه داده اصلی ایجاد نکنید.
import tensorflow_datasets as tfds
from . import my_dataset_dataset_builder


class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
  """Tests for my_dataset dataset."""
  DATASET_CLASS = my_dataset_dataset_builder.Builder
  SPLITS = {
      'train': 3,  # Number of fake train example
      'test': 1,  # Number of fake test example
  }

  # If you are calling `download/download_and_extract` with a dict, like:
  #   dl_manager.download({'some_key': 'http://a.org/out.txt', ...})
  # then the tests needs to provide the fake output paths relative to the
  # fake data directory
  DL_EXTRACT_RESULT = {
      'name1': 'path/to/file1',  # Relative to my_dataset/dummy_data dir.
      'name2': 'file2',
  }


if __name__ == '__main__':
  tfds.testing.test_main()

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

python my_dataset_test.py

برای ما بازخورد ارسال کنید

ما به طور مداوم در تلاش برای بهبود گردش کار ایجاد مجموعه داده‌ها هستیم، اما تنها در صورتی می‌توانیم این کار را انجام دهیم که از مشکلات آگاه باشیم. هنگام ایجاد مجموعه داده با چه مشکلات یا خطاهایی مواجه شدید؟ آیا قسمتی وجود داشت که گیج کننده بود یا بار اول کار نمی کرد؟

لطفاً نظرات خود را در مورد GitHub به اشتراک بگذارید.