Menulis kumpulan data khusus

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

Periksa daftar dataset kami untuk melihat apakah dataset yang Anda inginkan sudah tersedia.

Ringkasan singkat:

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_dataset_builder.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 oleh tfds build ).
  • Alternatifnya, Anda dapat secara eksplisit 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

Ringkasan

Dataset didistribusikan dalam berbagai format dan di berbagai tempat, dan tidak selalu disimpan dalam format yang siap untuk dimasukkan ke dalam alur kerja pembelajaran mesin. Di sinilah TFDS berperan.

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

Sebagian besar pra-pemrosesan dilakukan secara otomatis. Setiap dataset mengimplementasikan subkelas dari tfds.core.DatasetBuilder , yang menentukan:

  • Dari mana data tersebut berasal (yaitu URL-nya);
  • Seperti apa tampilan dataset tersebut (yaitu fitur-fiturnya);
  • Bagaimana data harus dibagi (misalnya, TRAIN dan TEST );
  • dan contoh-contoh individual dalam dataset tersebut.

Tuliskan dataset Anda

Templat default: tfds new

Gunakan TFDS CLI untuk menghasilkan file template python yang dibutuhkan.

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

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

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).

Cari TODO(my_dataset) di sini dan modifikasi sesuai kebutuhan.

Contoh dataset

Semua dataset diimplementasikan sebagai subkelas dari tfds.core.DatasetBuilder , yang menangani sebagian besar kode berulang. Dataset ini mendukung:

  • Kumpulan data kecil/sedang yang dapat dihasilkan pada satu mesin (tutorial ini).
  • Kumpulan data yang sangat besar yang memerlukan pembangkitan terdistribusi (menggunakan Apache Beam , lihat panduan kumpulan data besar kami)

Berikut adalah contoh minimal dari pembuat dataset yang didasarkan pada 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',
      }

Perlu dicatat bahwa, untuk beberapa format data spesifik, kami menyediakan pembuat dataset siap pakai untuk menangani sebagian besar pemrosesan data.

Mari kita lihat secara detail 3 metode abstrak untuk menimpa.

_info : metadata dataset

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

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,
  )

Sebagian besar kolom seharusnya mudah dipahami. Beberapa penjelasan tambahan:

Menulis file BibText CITATIONS.bib :

  • Cari petunjuk pengutipan di situs web dataset (gunakan format BibTex).
  • Untuk makalah arXiv : temukan makalah tersebut dan klik tautan BibText di sisi kanan.
  • Temukan makalah tersebut di Google Scholar dan klik tanda kutip ganda di bawah judul, lalu pada jendela pop-up, klik BibTeX .
  • Jika tidak ada makalah terkait (misalnya, hanya ada situs web), Anda dapat menggunakan Editor Online BibTeX untuk membuat entri BibTeX khusus (menu tarik-turun memiliki tipe entri Online ).

Memperbarui file TAGS.txt :

  • Semua tag yang diizinkan sudah terisi otomatis dalam file yang dihasilkan.
  • Hapus semua tag yang tidak berlaku untuk dataset tersebut.
  • Tag yang valid tercantum dalam tensorflow_datasets/core/valid_tags.txt .
  • Untuk menambahkan tag ke daftar tersebut, silakan kirim PR.

Pertahankan urutan dataset.

Secara default, dataset diacak saat disimpan untuk membuat distribusi kelas lebih seragam di seluruh dataset, karena seringkali dataset yang termasuk dalam kelas yang sama berdekatan. Untuk menentukan bahwa dataset harus diurutkan berdasarkan kunci yang dihasilkan oleh _generate_examples , field disable_shuffling harus diatur ke True . Secara default, nilainya adalah False .

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

Perlu diingat bahwa menonaktifkan pengacakan (shuffling) akan berdampak pada performa karena shard tidak dapat lagi dibaca secara paralel.

_split_generators : mengunduh dan membagi data

Mengunduh dan mengekstrak data sumber

Sebagian besar dataset perlu mengunduh data dari web. Ini dilakukan dengan menggunakan argumen input tfds.download.DownloadManager dari _split_generators . dl_manager memiliki metode-metode berikut:

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

Semua metode tersebut mengembalikan tfds.core.Path (alias untuk epath.Path ), yang merupakan objek mirip pathlib.Path .

Metode-metode tersebut mendukung struktur bersarang sembarang ( 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/'),
}

Pengunduhan dan ekstraksi manual

Beberapa data tidak dapat diunduh secara otomatis (misalnya memerlukan login), dalam hal ini, pengguna akan mengunduh data sumber secara manual dan menempatkannya di manual_dir/ (secara default ~/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)
    ...

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

Baca arsip secara langsung

dl_manager.iter_archive membaca arsip secara berurutan tanpa mengekstraknya. Hal 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 pembagian dataset

Jika dataset sudah dilengkapi dengan pembagian yang telah ditentukan sebelumnya (misalnya MNIST memiliki pembagian data train dan test ), pertahankan pembagian tersebut. Jika tidak, cukup tentukan satu pembagian " all . Pengguna dapat membuat sub-pembagian sendiri secara dinamis dengan API sub-pembagian (misalnya split='train[80%:]' ). Perhatikan bahwa string alfabet apa pun dapat digunakan sebagai nama pembagian, selain all yang telah disebutkan sebelumnya.

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

_generate_examples menghasilkan contoh untuk setiap pemisahan dari data sumber.

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

  • key : Pengidentifikasi contoh. Digunakan untuk mengacak contoh secara deterministik menggunakan hash(key) atau untuk mengurutkan berdasarkan key ketika pengacakan dinonaktifkan (lihat bagian Memelihara urutan dataset ). Seharusnya:
    • unik : Jika dua contoh menggunakan kunci yang sama, pengecualian akan muncul.
    • Deterministik : Seharusnya tidak bergantung pada download_dir , os.path.listdir order,... Pembuatan data dua kali seharusnya menghasilkan kunci yang sama.
    • sebanding : Jika pengacakan dinonaktifkan, kunci akan digunakan untuk mengurutkan dataset.
  • feature_dict : Sebuah dict yang berisi nilai-nilai contoh.
    • Struktur tersebut harus sesuai dengan struktur features= yang didefinisikan dalam tfds.core.DatasetInfo .
    • Tipe data kompleks (gambar, video, audio,...) akan dienkode secara otomatis.
    • Setiap fitur sering menerima beberapa tipe input (misalnya video 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 informasi selengkapnya.
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 mengembalikan objek mirip pathlib yang kompatibel langsung 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())

Alternatifnya, gunakan API tf.io.gfile sebagai pengganti fungsi bawaan untuk operasi file:

Pathlib sebaiknya lebih diutamakan daripada tf.io.gfile (lihat alasannya) .

Ketergantungan tambahan

Beberapa dataset hanya memerlukan dependensi Python tambahan selama proses pembuatan. Misalnya, dataset SVHN menggunakan scipy untuk memuat beberapa data.

Jika Anda menambahkan dataset ke repositori TFDS, harap gunakan tfds.core.lazy_imports agar paket tensorflow-datasets tetap kecil. Pengguna hanya akan menginstal dependensi tambahan jika diperlukan.

Untuk menggunakan lazy_imports :

  • Tambahkan entri untuk dataset Anda ke dalam DATASET_EXTRAS di setup.py . Ini memungkinkan pengguna untuk melakukan, misalnya, pip install 'tensorflow-datasets[svhn]' untuk menginstal dependensi tambahan.
  • Tambahkan entri untuk impor Anda ke LazyImporter dan ke LazyImportsTest .
  • Gunakan tfds.core.lazy_imports untuk mengakses dependensi (misalnya, tfds.core.lazy_imports.scipy ) di DatasetBuilder Anda.

Data rusak

Beberapa dataset tidak sepenuhnya bersih dan mengandung beberapa data yang rusak (misalnya, gambar berada dalam file JPEG tetapi beberapa di antaranya adalah JPEG yang tidak valid). Contoh-contoh ini sebaiknya diabaikan, tetapi cantumkan catatan dalam deskripsi dataset tentang berapa banyak contoh yang dihilangkan dan alasannya.

Konfigurasi/varian dataset (tfds.core.BuilderConfig)

Beberapa dataset mungkin memiliki beberapa varian, atau opsi tentang bagaimana data diproses dan ditulis ke disk. Misalnya, cycle_gan memiliki satu konfigurasi per pasangan objek ( cycle_gan/horse2zebra , cycle_gan/monet2photo , ...).

Hal ini dilakukan melalui tfds.core.BuilderConfig :

  1. Tetapkan objek konfigurasi Anda sebagai subkelas dari tfds.core.BuilderConfig . Misalnya, MyDatasetConfig .

    @dataclasses.dataclass
    class MyDatasetConfig(tfds.core.BuilderConfig):
      img_size: Tuple[int, int] = (0, 0)
    
  2. Definisikan anggota kelas BUILDER_CONFIGS = [] di MyDataset yang mencantumkan MyDatasetConfig yang diekspos oleh dataset tersebut.

    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 mengatur nilai yang berbeda di _info() atau mengubah akses unduhan data.

Catatan:

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

Lihat anli untuk contoh dataset yang menggunakan BuilderConfig .

Versi

Versi dapat merujuk pada dua arti yang berbeda:

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

Untuk memperbarui dataset:

  • Untuk pembaruan data "eksternal": Beberapa pengguna mungkin ingin mengakses tahun/versi tertentu secara bersamaan. Hal ini dilakukan dengan menggunakan 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 pembaruan kode harus meningkatkan atribut kelas VERSION (misalnya dari 1.0.0 menjadi VERSION = tfds.core.Version('2.0.0') ) sesuai dengan versi semantik .

Tambahkan impor untuk pendaftaran

Jangan lupa mengimpor modul dataset ke __init__ proyek Anda agar secara otomatis terdaftar di tfds.load dan tfds.builder .

import my_project.datasets.my_dataset  # Register MyDataset

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

Misalnya, jika Anda berkontribusi pada tensorflow/datasets , tambahkan impor modul ke __init__.py di subdirektori tersebut (misalnya image/__init__.py ).

Periksa kesalahan umum dalam implementasi.

Silakan periksa kesalahan umum yang mungkin terjadi saat implementasi .

Uji dataset Anda

Unduh dan siapkan: tfds build

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

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

Beberapa flag yang berguna untuk pengembangan:

  • --pdb : Masuk ke mode debugging jika terjadi pengecualian.
  • --overwrite : Hapus file yang sudah ada jika dataset sudah dibuat.
  • --max_examples_per_split : Hanya menghasilkan X contoh pertama (defaultnya 1), bukan seluruh dataset.
  • --register_checksums : Merekam checksum dari URL yang diunduh. Sebaiknya hanya digunakan selama pengembangan.

Lihat dokumentasi CLI untuk daftar lengkap flag.

Checksum

Disarankan untuk mencatat checksum dari dataset Anda untuk menjamin determinisme, membantu dokumentasi, dan lain-lain. Hal ini dilakukan dengan menghasilkan dataset menggunakan opsi --register_checksums (lihat bagian sebelumnya).

Jika Anda merilis dataset Anda melalui PyPI, jangan lupa untuk mengekspor file checksums.tsv (misalnya di package_data pada setup.py Anda).

Lakukan pengujian unit pada dataset Anda.

tfds.testing.DatasetBuilderTestCase adalah TestCase dasar untuk menguji sebuah dataset secara menyeluruh. TestCase ini menggunakan "data dummy" sebagai data uji yang meniru struktur dataset sumber.

  • Data uji harus ditempatkan di direktori my_dataset/dummy_data/ dan harus meniru artefak dataset sumber seperti yang diunduh dan diekstrak. Data uji dapat dibuat secara manual atau otomatis dengan skrip ( contoh skrip ).
  • Pastikan untuk menggunakan data yang berbeda dalam pembagian data uji Anda, karena pengujian akan gagal jika pembagian dataset Anda tumpang tindih.
  • Data uji tidak boleh 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_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()

Jalankan perintah berikut untuk menguji dataset.

python my_dataset_test.py

Kirimkan masukan kepada kami

Kami terus berupaya untuk meningkatkan alur kerja pembuatan dataset, tetapi hanya dapat melakukannya jika kami mengetahui masalahnya. Masalah atau kesalahan apa yang Anda temui saat membuat dataset? Apakah ada bagian yang membingungkan, atau tidak berfungsi pada percobaan pertama?

Silakan sampaikan masukan Anda di GitHub .