撰寫自訂資料集

按照本指南建立新的資料集 (無論是在 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);
  • 資料集的樣貌 (即其功能);
  • 資料應如何分割 (例如,TRAINTEST);
  • 以及資料集中的個別範例。

撰寫您的資料集

預設範本:tfds new

使用 TFDS CLI 產生所需的範本 Python 檔案。

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 Beam,請參閱我們的巨量資料集指南)

以下是基於 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:資料集metadata

_info 傳回 tfds.core.DatasetInfo,其中包含資料集metadata

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 學術搜尋上找到論文,然後按一下標題下方的雙引號,並在彈出視窗中按一下 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:下載並分割資料

下載並解壓縮來源資料

大多數資料集都需要從網路下載資料。這是透過 _split_generatorstfds.download.DownloadManager 輸入引數完成的。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 的物件。

這些方法支援任意巢狀結構 (listdict),例如

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 具有 traintest 分割),請保留這些分割。否則,僅指定單一 all 分割。使用者可以使用子分割 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_diros.path.listdir 順序等等。產生資料兩次應產生相同的金鑰。
    • 可比較:如果停用洗牌,則金鑰將用於排序資料集。
  • feature_dict:包含範例值的 dict
    • 結構應符合在 tfds.core.DatasetInfo 中定義的 features= 結構。
    • 複雜的資料類型 (影像、影片、音訊等等) 將自動編碼。
    • 每個功能通常接受多種輸入類型 (例如,影片接受 /path/to/vid.mp4np.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

為了支援雲端儲存系統,請避免使用 Python 內建的 I/O 運算。

相反地,dl_manager 會傳回直接與 Google Cloud Storage 相容的類似 pathlib 的物件

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 而不是內建 API 進行檔案作業

Pathlib 應優先於 tf.io.gfile (請參閱理由

額外的依附元件

有些資料集僅在產生期間需要額外的 Python 依附元件。例如,SVHN 資料集使用 scipy 載入某些資料。

如果您要將資料集新增至 TFDS 存放庫,請使用 tfds.core.lazy_imports 以保持 tensorflow-datasets 套件小巧。使用者只會在需要時安裝額外的依附元件。

若要使用 lazy_imports

  • setup.py 中的 DATASET_EXTRAS 中為您的資料集新增一個項目。這樣做是為了讓使用者可以執行例如 pip install 'tensorflow-datasets[svhn]' 來安裝額外的依附元件。
  • LazyImporterLazyImportsTest 中為您的匯入新增一個項目。
  • 在您的 DatasetBuilder 中使用 tfds.core.lazy_imports 存取依附元件 (例如,tfds.core.lazy_imports.scipy)。

損毀的資料

有些資料集並非完全乾淨,且包含一些損毀的資料 (例如,影像在 JPEG 檔案中,但有些是無效的 JPEG)。這些範例應略過,但在資料集說明中註明已捨棄多少範例以及原因。

資料集組態/變體 (tfds.core.BuilderConfig)

有些資料集可能有多個變體,或關於資料如何預先處理和寫入磁碟的選項。例如,cycle_gan 每個物件配對都有一個組態 (cycle_gan/horse2zebracycle_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. MyDataset 中定義 BUILDER_CONFIGS = [] 類別成員,列出資料集公開的 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. MyDataset 中使用 self.builder_config 來設定資料產生 (例如,shape=self.builder_config.img_size)。這可能包括在 _info() 中設定不同的值或變更下載資料存取。

注意事項

  • 每個組態都有一個唯一的名稱。組態的完整名稱是 dataset_name/config_name (例如,coco/2017)。
  • 如果未指定,將使用 BUILDER_CONFIGS 中的第一個組態 (例如,tfds.load('c4') 預設為 c4/en)

請參閱 anli,以取得使用 BuilderConfig 的資料集範例。

版本

版本可以指兩種不同的含義

  • 「外部」原始資料版本:例如 COCO v2019、v2017 等等。
  • 「內部」TFDS 程式碼版本:例如,在 tfds.features.FeaturesDict 中重新命名功能,修正 _generate_examples 中的錯誤

若要更新資料集

  • 對於「外部」資料更新:多個使用者可能想要同時存取特定的年份/版本。這是透過每個版本使用一個 tfds.core.BuilderConfig (例如,coco/2017coco/2019) 或每個版本一個類別 (例如,Voc2007Voc2012) 來完成的。
  • 對於「內部」程式碼更新:使用者只會下載最新版本。任何程式碼更新都應依照語意版本控制,增加 VERSION 類別屬性 (例如,從 1.0.0VERSION = tfds.core.Version('2.0.0'))。

新增匯入以進行註冊

別忘了將資料集模組匯入您的專案 __init__,以便在 tfds.loadtfds.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

若要產生資料集,請從 my_dataset/ 目錄執行 tfds build

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 檔案 (例如,在您的 setup.pypackage_data 中)。

單元測試您的資料集

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 上分享您的意見回饋。