Menulis kumpulan data khusus

Ikuti panduan ini untuk membuat kumpulan data baru (baik di TFDS atau di repositori Anda sendiri).

Periksa kami daftar dataset untuk melihat apakah kumpulan data yang ingin sudah ada.

TL;DR

Cara termudah untuk menulis dataset baru adalah dengan menggunakan 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.py` to implement your dataset.
cd my_dataset/
tfds build  # Download and prepare the dataset to `~/tensorflow_datasets/`

Untuk menggunakan dataset baru dengan tfds.load('my_dataset') :

  • tfds.load akan secara otomatis mendeteksi dan memuat dataset yang dihasilkan di ~/tensorflow_datasets/my_dataset/ (misalnya dengan tfds build ).
  • Atau, Anda secara eksplisit dapat import my.project.datasets.my_dataset untuk mendaftarkan dataset Anda:
import my.project.datasets.my_dataset  # Register `my_dataset`

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

Gambaran

Kumpulan data didistribusikan dalam semua jenis format dan di semua jenis tempat, dan tidak selalu disimpan dalam format yang siap dimasukkan ke dalam alur pembelajaran mesin. Masukkan TFDS.

TFDS memproses mereka dataset ke dalam format standar (data eksternal -> file serial), yang kemudian dapat dimuat sebagai pipa mesin pembelajaran (file serial -> tf.data.Dataset ). Serialisasi hanya dilakukan sekali. Akses selanjutnya akan membaca dari file yang telah diproses sebelumnya secara langsung.

Sebagian besar preprocessing dilakukan secara otomatis. Setiap dataset alat subclass dari tfds.core.DatasetBuilder , yang menentukan:

  • Dari mana data berasal (yaitu URL-nya);
  • Seperti apa dataset tersebut (yaitu fitur-fiturnya);
  • Bagaimana data harus split (misalnya TRAIN dan TEST );
  • dan contoh individu dalam kumpulan data.

Tulis kumpulan data Anda

Template default: tfds new

Gunakan TFDS CLI untuk menghasilkan template yang file python yang diperlukan.

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

Perintah ini akan menghasilkan baru my_dataset/ folder dengan struktur sebagai berikut:

my_dataset/
    __init__.py
    my_dataset.py # Dataset definition
    my_dataset_test.py # (optional) Test
    dummy_data/ # (optional) Fake data (used for testing)
    checksum.tsv # (optional) URL checksums (see `checksums` section).

Cari TODO(my_dataset) di sini dan memodifikasi sesuai.

Contoh kumpulan data

Semua dataset diimplementasikan sebagai tfds.core.GeneratorBasedBuilder , sebuah subclass dari tfds.core.DatasetBuilder yang mengurus paling boilerplate. Ini mendukung:

  • Kumpulan data kecil/menengah yang dapat dihasilkan pada satu mesin (tutorial ini).
  • Dataset yang sangat besar yang memerlukan generasi didistribusikan (menggunakan Apache Beam , lihat panduan dataset besar )

Berikut adalah contoh minimal kelas dataset:

class MyDataset(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 tfds.core.DatasetInfo(
        builder=self,
        features=tfds.features.FeaturesDict({
            'image': tfds.features.Image(shape=(256, 256, 3)),
            'label': tfds.features.ClassLabel(names=['no', 'yes']),
        }),
    )

  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',
      }

Mari kita lihat secara detail 3 metode abstrak untuk ditimpa.

_info : dataset metadata

_info kembali yang tfds.core.DatasetInfo yang berisi metadata dataset .

def _info(self):
  return tfds.core.DatasetInfo(
      builder=self,
      # Description and homepage used for documentation
      description="""
      Markdown description of the dataset. The text will be automatically
      stripped and dedent.
      """,
      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,
      # Bibtex citation for the dataset
      citation=r"""
      @article{my-awesome-dataset-2020,
               author = {Smith, John},}
      """,
  )

Sebagian besar bidang harus cukup jelas. Beberapa presisi:

  • features : Ini menentukan struktur dataset, bentuk, ... Dukungan jenis kompleks data (audio, video, urutan bersarang, ...). Lihat fitur yang tersedia atau fitur panduan konektor untuk info lebih lanjut.
  • disable_shuffling : Lihat bagian Menjaga agar dataset .
  • citation : Untuk menemukan BibText kutipan:
    • Cari situs dataset untuk instruksi kutipan (gunakan itu dalam format BibTex).
    • Untuk arXiv kertas: menemukan kertas dan klik BibText link di sisi kanan.
    • Menemukan kertas di Google Scholar dan klik tanda dua kutip di bawah judul dan pada popup, klik BibTeX .
    • Jika tidak ada terkait kertas (misalnya, hanya ada sebuah situs web), Anda dapat menggunakan BibTeX Editor Online untuk membuat custom BibTeX entri (menu drop-down memiliki Online jenis entri).

Pertahankan urutan kumpulan data

Secara default, catatan dari kumpulan data dikocok saat disimpan untuk membuat distribusi kelas lebih seragam di seluruh kumpulan data, karena sering kali catatan milik kelas yang sama bersebelahan. Dalam rangka untuk menentukan bahwa dataset harus diurutkan dengan kunci yang dihasilkan disediakan oleh _generate_examples bidang disable_shuffling harus di set ke True . Secara default sudah diatur untuk False .

def _info(self):
  return tfds.core.DatasetInfo(
    # [...]
    disable_shuffling=True,
    # [...]
  )

Perlu diingat bahwa menonaktifkan pengacakan memiliki dampak kinerja karena pecahan tidak dapat dibaca secara paralel lagi.

_split_generators : download dan perpecahan Data

Mengunduh dan mengekstrak data sumber

Sebagian besar kumpulan data perlu mengunduh data dari web. Hal ini dilakukan dengan menggunakan tfds.download.DownloadManager masukan argumen _split_generators . dl_manager memiliki metode berikut:

  • download : mendukung http(s):// , ftp(s)://
  • extract : saat ini mendukung .zip , .gz , dan .tar file.
  • download_and_extract : Sama seperti dl_manager.extract(dl_manager.download(urls))

Semua metode tersebut mengembalikan tfds.core.ReadOnlyPath , yang pathlib.Path-seperti objek.

Metode-metode yang mendukung sewenang-wenang struktur bersarang ( list , dict ), seperti:

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/'),
}

Unduhan dan ekstraksi manual

Beberapa data tidak dapat didownload secara otomatis (misalnya memerlukan login), dalam hal ini, pengguna secara manual akan men-download data sumber dan menempatkannya di manual_dir/ (defaultnya ~/tensorflow_datasets/downloads/manual/ ).

File kemudian dapat diakses melalui 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)
    ...

The manual_dir lokasi dapat disesuaikan dengan tfds build --manual_dir= atau menggunakan tfds.download.DownloadConfig .

Baca arsip secara langsung

dl_manager.iter_archive membaca sebuah arsip secara berurutan tanpa penggalian mereka. Ini dapat menghemat ruang penyimpanan dan meningkatkan kinerja pada beberapa sistem file.

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

fobj memiliki metode yang sama seperti with open('rb') as fobj: (misalnya fobj.read() )

Menentukan pemisahan kumpulan data

Jika dataset datang dengan pra-didefinisikan split (misalnya MNIST memiliki train dan test split), menjaga mereka. Jika tidak, hanya menentukan satu tfds.Split.TRAIN split. Pengguna dapat secara dinamis membuat subsplits mereka sendiri dengan subsplit API (misalnya split='train[80%:]' ).

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 : Contoh Generator

_generate_examples menghasilkan contoh untuk masing-masing berpisah dari sumber data.

Metode ini biasanya akan membaca sumber artefak dataset (misalnya CSV file) dan hasil (key, feature_dict) tupel:

  • key : Contoh identifier. Digunakan untuk deterministik mengocok contoh menggunakan hash(key) atau untuk mengurutkan berdasarkan kunci ketika menyeret dinonaktifkan (lihat bagian Menjaga agar dataset ). Seharusnya:
    • unik: Jika dua contoh menggunakan kunci yang sama, pengecualian akan dibangkitkan.
    • deterministik: Haruskah tidak tergantung pada download_dir , os.path.listdir order, ... Membangkitkan data dua kali harus menghasilkan kunci yang sama.
    • sebanding: Jika menyeret dinonaktifkan kunci akan digunakan untuk mengurutkan dataset.
  • feature_dict : Sebuah dict yang mengandung nilai contoh.
    • Struktur harus sesuai dengan features= struktur didefinisikan dalam tfds.core.DatasetInfo .
    • Tipe data kompleks (gambar, video, audio,...) akan dikodekan secara otomatis.
    • Setiap fitur yang sering menerima beberapa jenis input (misalnya video yang menerima /path/to/vid.mp4 , np.array(shape=(l, h, w, c)) , List[paths] , List[np.array(shape=(h, w, c)] , List[img_bytes] , ...)
    • Lihat panduan konektor fitur untuk info lebih lanjut.
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'],
      }

Akses file dan tf.io.gfile

Untuk mendukung sistem penyimpanan Cloud, hindari penggunaan operasi I/O bawaan Python.

Sebaliknya, dl_manager kembali pathlib-seperti benda-benda langsung kompatibel dengan penyimpanan 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())

Atau, gunakan tf.io.gfile API bukan built-in untuk operasi file:

Pathlib harus dipilih untuk tf.io.gfile (lihat rasional .

Ketergantungan ekstra

Beberapa kumpulan data memerlukan dependensi Python tambahan hanya selama pembuatan. Sebagai contoh, penggunaan SVHN dataset scipy untuk memuat beberapa data.

Jika Anda menambahkan dataset ke dalam repositori TFDS, silakan gunakan tfds.core.lazy_imports untuk menjaga tensorflow-datasets paket kecil. Pengguna akan menginstal dependensi tambahan hanya jika diperlukan.

Untuk menggunakan lazy_imports :

  • Menambahkan sebuah entri untuk dataset Anda ke DATASET_EXTRAS di setup.py . Hal ini membuat sehingga pengguna dapat melakukan, misalnya, pip install 'tensorflow-datasets[svhn]' untuk menginstal dependensi ekstra.
  • Menambahkan sebuah entri untuk impor Anda untuk LazyImporter dan ke LazyImportsTest .
  • Gunakan tfds.core.lazy_imports untuk mengakses ketergantungan (misalnya, tfds.core.lazy_imports.scipy ) di Anda DatasetBuilder .

Data rusak

Beberapa kumpulan data tidak sepenuhnya bersih dan berisi beberapa data yang rusak (misalnya, gambar dalam file JPEG tetapi beberapa adalah JPEG yang tidak valid). Contoh-contoh ini harus dilewati, tetapi tinggalkan catatan di deskripsi kumpulan data berapa banyak contoh yang dijatuhkan dan mengapa.

Konfigurasi/varian kumpulan data (tfds.core.BuilderConfig)

Beberapa kumpulan data mungkin memiliki beberapa varian, atau opsi tentang cara data diproses sebelumnya dan ditulis ke disk. Misalnya, cycle_gan memiliki satu config per pasang objek ( cycle_gan/horse2zebra , cycle_gan/monet2photo , ...).

Hal ini dilakukan melalui tfds.core.BuilderConfig s:

  1. Tentukan objek konfigurasi Anda sebagai subclass dari tfds.core.BuilderConfig . Misalnya, MyDatasetConfig .

    @dataclasses.dataclass
    class MyDatasetConfig(tfds.core.BuilderConfig):
      img_size: Tuple[int, int] = (0, 0)
    
  2. Tentukan BUILDER_CONFIGS = [] anggota kelas dalam MyDataset bahwa daftar MyDatasetConfig s bahwa mengekspos dataset.

    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. Gunakan self.builder_config di MyDataset untuk mengkonfigurasi pembuatan data (misalnya shape=self.builder_config.img_size ). Ini mungkin termasuk pengaturan nilai yang berbeda di _info() atau mengubah akses data download.

Catatan:

  • Setiap konfigurasi memiliki nama yang unik. Nama yang memenuhi syarat dari config adalah dataset_name/config_name (misalnya coco/2017 ).
  • Jika tidak ditentukan, konfigurasi pertama di BUILDER_CONFIGS akan digunakan (misalnya tfds.load('c4') default c4/en )

Lihat anli untuk contoh dataset yang menggunakan BuilderConfig s.

Versi: kapan

Versi dapat merujuk pada dua arti yang berbeda:

  • Versi data asli "eksternal": misalnya COCO v2019, v2017,...
  • "Internal" TFDS kode versi: misalnya mengubah nama fitur di tfds.features.FeaturesDict , memperbaiki bug di _generate_examples

Untuk memperbarui kumpulan data:

  • Untuk pembaruan data "eksternal": Beberapa pengguna mungkin ingin mengakses tahun/versi tertentu secara bersamaan. Hal ini dilakukan dengan menggunakan salah satu tfds.core.BuilderConfig per versi (misalnya coco/2017 , coco/2019 ) atau satu kelas per versi (misalnya Voc2007 , Voc2012 ).
  • Untuk pembaruan kode "internal": Pengguna hanya mengunduh versi terbaru. Setiap update kode harus meningkatkan VERSION atribut kelas (misalnya dari 1.0.0 ke VERSION = tfds.core.Version('2.0.0') ) berikut versi semantik .

Tambahkan impor untuk pendaftaran

Jangan lupa untuk mengimpor modul dataset untuk proyek Anda __init__ akan otomatis terdaftar di tfds.load , tfds.builder .

import my_project.datasets.my_dataset  # Register MyDataset

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

Misalnya, jika Anda berkontribusi untuk tensorflow/datasets , tambahkan impor modul untuk subdirektori nya __init__.py (misalnya image/__init__.py .

Periksa gotcha implementasi umum common

Silakan periksa untuk gotchas pelaksanaan umum .

Uji kumpulan data Anda

Download dan mempersiapkan: tfds build

Untuk menghasilkan dataset, jalankan tfds build dari my_dataset/ direktori:

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

Beberapa flag yang berguna untuk pengembangan:

  • --pdb : Masukkan modus debug jika eksepsi dimunculkan.
  • --overwrite : file yang ada Delete jika dataset itu sudah dihasilkan.
  • --max_examples_per_split : Hanya menghasilkan contoh pertama X (default 1), daripada dataset penuh.
  • --register_checksums : Catat checksum url download. Seharusnya hanya digunakan saat dalam pengembangan.

Lihat dokumentasi CLI untuk daftar lengkap flag.

Checksum

Disarankan untuk merekam checksum dataset Anda untuk jaminan determinisme, bantuan dengan dokumentasi, ... Hal ini dilakukan dengan menghasilkan dataset dengan --register_checksums (lihat bagian sebelumnya).

Jika Anda melepaskan dataset Anda melalui PyPI, jangan lupa untuk mengekspor checksums.tsv file (misalnya dalam package_data dari Anda setup.py ).

Uji unit dataset Anda

tfds.testing.DatasetBuilderTestCase adalah basis TestCase untuk sepenuhnya melaksanakan dataset. Ini menggunakan "data dummy" sebagai data uji yang meniru struktur kumpulan data sumber.

  • Data uji harus dimasukkan ke dalam my_dataset/dummy_data/ direktori dan harus meniru artefak sumber dataset sebagai download dan diekstrak. Hal ini dapat dibuat secara manual atau secara otomatis dengan script ( contoh script ).
  • Pastikan untuk menggunakan data yang berbeda dalam pemisahan data pengujian Anda, karena pengujian akan gagal jika pemisahan set data Anda tumpang tindih.
  • Data uji harus tidak mengandung materi yang dilindungi hak cipta. Jika ragu, jangan membuat data menggunakan materi dari dataset asli.
import tensorflow_datasets as tfds
from . import my_dataset


class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
  """Tests for my_dataset dataset."""
  DATASET_CLASS = my_dataset.MyDataset
  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 dummy_data/my_dataset dir.
      'name2': 'file2',
  }


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

Jalankan perintah berikut untuk menguji dataset.

python my_dataset_test.py

Kirimi kami umpan balik us

Kami terus berusaha meningkatkan alur kerja pembuatan kumpulan data, tetapi hanya dapat melakukannya jika kami mengetahui masalahnya. Masalah, kesalahan apa yang Anda temui saat membuat kumpulan data? Apakah ada bagian yang membingungkan, boilerplate atau tidak berfungsi pertama kali? Silakan berbagi Anda umpan balik pada github .