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/ujian 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