Gotcha implementasi umum

Halaman ini menjelaskan penerapan umum yang mungkin terjadi saat mengimplementasikan kumpulan data baru.

SplitGenerator Lama harus dihindari

API tfds.core.SplitGenerator yang lama tidak digunakan lagi.

def _split_generator(...):
  return [
      tfds.core.SplitGenerator(name='train', gen_kwargs={'path': train_path}),
      tfds.core.SplitGenerator(name='test', gen_kwargs={'path': test_path}),
  ]

Harus diganti dengan:

def _split_generator(...):
  return {
      'train': self._generate_examples(path=train_path),
      'test': self._generate_examples(path=test_path),
  }

Dasar Pemikiran : API baru ini tidak terlalu bertele-tele dan lebih eksplisit. API lama akan dihapus di versi mendatang.

Kumpulan data baru harus disimpan sendiri dalam sebuah folder

Saat menambahkan kumpulan data di dalam repositori tensorflow_datasets/ , pastikan untuk mengikuti struktur kumpulan data sebagai folder (semua checksum, data dummy, kode implementasi terdapat dalam satu folder).

  • Kumpulan data lama (buruk): <category>/<ds_name>.py
  • Kumpulan data baru (bagus): <category>/<ds_name>/<ds_name>.py

Gunakan TFDS CLI ( tfds new , atau gtfds new untuk pengguna Google) untuk membuat template.

Dasar Pemikiran : Struktur lama memerlukan jalur absolut untuk checksum, data palsu, dan mendistribusikan file kumpulan data di banyak tempat. Hal ini mempersulit penerapan kumpulan data di luar repositori TFDS. Untuk konsistensi, struktur baru harus digunakan dimana-mana sekarang.

Daftar deskripsi harus diformat sebagai penurunan harga

str DatasetInfo.description diformat sebagai penurunan harga. Daftar penurunan harga memerlukan baris kosong sebelum item pertama:

_DESCRIPTION = """
Some text.
                      # << Empty line here !!!
1. Item 1
2. Item 1
3. Item 1
                      # << Empty line here !!!
Some other text.
"""

Dasar Pemikiran : Deskripsi dengan format buruk membuat artefak visual dalam dokumentasi katalog kami. Tanpa baris kosong, teks di atas akan ditampilkan sebagai:

Beberapa teks. 1. Butir 1 2. Butir 1 3. Butir 1 Beberapa teks lainnya

Lupa nama ClassLabel

Saat menggunakan tfds.features.ClassLabel , coba berikan label str yang dapat dibaca manusia dengan names= atau names_file= (bukan num_classes=10 ).

features = {
    'label': tfds.features.ClassLabel(names=['dog', 'cat', ...]),
}

Dasar Pemikiran : Label yang dapat dibaca manusia digunakan di banyak tempat:

  • Izinkan untuk menghasilkan str secara langsung di _generate_examples : yield {'label': 'dog'}
  • Terkena pada pengguna seperti info.features['label'].names (metode konversi .str2int('dog') ,... juga tersedia)
  • Digunakan dalam utilitas visualisasi tfds.show_examples , tfds.as_dataframe

Lupa bentuk gambar

Saat menggunakan tfds.features.Image , tfds.features.Video , jika gambar memiliki bentuk statis, gambar tersebut harus ditentukan secara eksplisit:

features = {
    'image': tfds.features.Image(shape=(256, 256, 3)),
}

Dasar Pemikiran : Ini memungkinkan inferensi bentuk statis (misalnya ds.element_spec['image'].shape ), yang diperlukan untuk pengelompokan (pengelompokan gambar dengan bentuk yang tidak diketahui akan memerlukan pengubahan ukurannya terlebih dahulu).

Lebih suka tipe yang lebih spesifik daripada tfds.features.Tensor

Jika memungkinkan, pilih jenis yang lebih spesifik tfds.features.ClassLabel , tfds.features.BBoxFeatures ,... daripada tfds.features.Tensor yang umum.

Dasar Pemikiran : Selain lebih benar secara semantik, fitur spesifik memberikan metadata tambahan kepada pengguna dan dideteksi oleh alat.

Impor yang malas di ruang global

Impor yang lamban tidak boleh dianggap berasal dari dunia global. Misalnya yang berikut ini salah:

tfds.lazy_imports.apache_beam # << Error: Import beam in the global scope

def f() -> beam.Map:
  ...

Dasar Pemikiran : Menggunakan impor lambat dalam lingkup global akan mengimpor modul untuk semua pengguna tfds, sehingga menggagalkan tujuan impor lambat.

Menghitung pemisahan kereta/pengujian secara dinamis

Jika kumpulan data tidak memberikan pemisahan resmi, TFDS juga tidak. Hal-hal berikut harus dihindari:

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

Dasar Pemikiran : TFDS mencoba menyediakan dataset sedekat data aslinya. API sub-pemisahan sebaiknya digunakan agar pengguna dapat secara dinamis membuat sub-pemisahan yang mereka inginkan:

ds_train, ds_test = tfds.load(..., split=['train[:80%]', 'train[80%:]'])

Panduan gaya python

Lebih suka menggunakan API pathlib

Daripada menggunakan tf.io.gfile API, lebih baik menggunakan pathlib API . Semua metode dl_manager mengembalikan objek seperti pathlib yang kompatibel dengan 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())

Dasar Pemikiran : pathlib API adalah API file berorientasi objek modern yang menghapus boilerplate. Menggunakan .read_text() / .read_bytes() juga menjamin file ditutup dengan benar.

Jika metode ini tidak menggunakan self , itu harus berupa fungsi

Jika metode kelas tidak menggunakan self , itu harus berupa fungsi sederhana (didefinisikan di luar kelas).

Dasar Pemikiran : Ini memperjelas kepada pembaca bahwa fungsi tersebut tidak memiliki efek samping, atau input/output tersembunyi:

x = f(y)  # Clear inputs/outputs

x = self.f(y)  # Does f depend on additional hidden variables ? Is it stateful ?

Impor yang malas dengan Python

Kami dengan malas mengimpor modul besar seperti TensorFlow. Impor lambat menunda impor modul yang sebenarnya hingga penggunaan modul yang pertama. Jadi pengguna yang tidak membutuhkan modul besar ini tidak akan pernah mengimpornya. Kami menggunakan 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

Di bawah tenda, kelas LazyModule bertindak sebagai pabrik, yang hanya akan mengimpor modul ketika atribut diakses ( __getattr__ ).

Anda juga dapat menggunakannya dengan nyaman dengan pengelola konteks:

from etils import epy

with epy.lazy_imports(error_callback=..., success_callback=...):
  import some_big_module