Yaygın uygulama kazanımları

Bu sayfada yeni bir veri kümesi uygulanırken karşılaşılan ortak uygulama kazanımları açıklanmaktadır.

Eski SplitGenerator kaçınılmalıdır

Eski tfds.core.SplitGenerator API'si kullanımdan kaldırıldı.

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

Şununla değiştirilmelidir:

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

Gerekçe : Yeni API daha az ayrıntılı ve daha açıktır. Eski API gelecek sürümde kaldırılacaktır.

Yeni veri kümeleri bir klasörde bağımsız olarak bulunmalıdır

tensorflow_datasets/ depo içine bir veri kümesi eklerken, lütfen klasör olarak veri kümesi yapısını izlediğinizden emin olun (tüm sağlama toplamları, yapay veriler, bir klasörde bulunan uygulama kodu).

  • Eski veri kümeleri (kötü): <category>/<ds_name>.py
  • Yeni veri kümeleri (iyi): <category>/<ds_name>/<ds_name>.py

Şablonu oluşturmak için TFDS CLI'yi ( tfds new veya Google çalışanları için gtfds new ) kullanın.

Gerekçe : Eski yapı, sağlama toplamları için mutlak yollar, sahte veriler gerektiriyordu ve veri kümesi dosyalarını birçok yere dağıtıyordu. Veri kümelerinin TFDS deposu dışında uygulanmasını zorlaştırıyordu. Tutarlılık açısından yeni yapının artık her yerde kullanılması gerekiyor.

Açıklama listeleri işaretleme olarak biçimlendirilmelidir

DatasetInfo.description str markdown olarak biçimlendirilmiştir. İşaretleme listeleri, ilk öğeden önce boş bir satır gerektirir:

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

Gerekçe : Kötü biçimlendirilmiş açıklama, katalog belgelerimizde görsel kusurlar yaratır. Boş satırlar olmasaydı yukarıdaki metin şu şekilde oluşturulur:

Bazı metin. 1. Madde 1 2. Madde 1 3. Madde 1 Başka bir metin

ClassLabel adlarını unuttum

tfds.features.ClassLabel kullanırken, insanlar tarafından okunabilen str etiketlerini names= veya names_file= ( num_classes=10 yerine) sağlamaya çalışın.

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

Gerekçe : İnsan tarafından okunabilen etiketler birçok yerde kullanılmaktadır:

  • _generate_examples doğrudan str elde edilmesine izin ver: yield {'label': 'dog'}
  • info.features['label'].names gibi kullanıcılarda gösterilir (dönüştürme yöntemi .str2int('dog') ,... ayrıca mevcuttur)
  • Görselleştirmede kullanılır tfds.show_examples , tfds.as_dataframe

Resim şeklini unuttum

tfds.features.Image , tfds.features.Video kullanılırken, görseller statik şekle sahipse açıkça belirtilmelidir:

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

Gerekçe : Toplu işlem için gerekli olan statik şekil çıkarımına (örn. ds.element_spec['image'].shape ) izin verir (bilinmeyen şekle sahip görüntülerin toplu olarak işlenmesi, önce bunların yeniden boyutlandırılmasını gerektirir).

tfds.features.Tensor yerine daha spesifik türü tercih edin

Mümkün olduğunda, genel tfds.features.Tensor yerine daha spesifik tfds.features.ClassLabel , tfds.features.BBoxFeatures ,... türlerini tercih edin.

Gerekçe : Anlamsal olarak daha doğru olmasının yanı sıra, belirli özellikler kullanıcılara ek meta veriler sağlar ve araçlar tarafından tespit edilir.

Küresel alanda tembel ithalat

Tembel ithalat küresel alandan çağrılmamalıdır. Örneğin aşağıdakiler yanlıştır:

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

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

Gerekçe : Tembel içe aktarmanın küresel kapsamda kullanılması, modülün tüm tfds kullanıcıları için içe aktarılmasına neden olur ve tembel içe aktarmanın amacını boşa çıkarır.

Tren/test ayrımlarını dinamik olarak hesaplama

Veri kümesi resmi bölünmeler sağlamıyorsa TFDS de sağlamamalıdır. Aşağıdakilerden kaçınılmalıdır:

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

Gerekçe : TFDS, orijinal veriye en yakın veri setlerini sağlamaya çalışır. Kullanıcıların istedikleri alt bölümleri dinamik olarak oluşturmalarına olanak sağlamak için bunun yerine alt bölüm API'si kullanılmalıdır:

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

Python stili kılavuzu

Pathlib API'yi kullanmayı tercih edin

tf.io.gfile API'si yerine pathlib API'sinin kullanılması tercih edilir. Tüm dl_manager yöntemleri, GCS, S3,... ile uyumlu pathlib benzeri nesneleri döndürür.

path = dl_manager.download_and_extract('http://some-website/my_data.zip')

json_path = path / 'data/file.json'

json.loads(json_path.read_text())

Gerekçe : pathlib API, ortak metni kaldıran modern bir nesne yönelimli dosya API'sidir. .read_text() / .read_bytes() işlevini kullanmak aynı zamanda dosyaların doğru şekilde kapatıldığını da garanti eder.

Yöntem self kullanmıyorsa bir işlev olmalıdır

Bir sınıf yöntemi self kullanmıyorsa, basit bir işlev olmalıdır (sınıfın dışında tanımlanmış).

Gerekçe : Okuyucuya, işlevin yan etkilerinin ya da gizli girdi/çıktısının olmadığını açıkça belirtir:

x = f(y)  # Clear inputs/outputs

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

Python'da tembel içe aktarma

TensorFlow gibi büyük modülleri tembelce içe aktarıyoruz. Tembel içe aktarmalar, modülün fiili içe aktarılmasını modülün ilk kullanımına erteler. Yani bu büyük modüle ihtiyacı olmayan kullanıcılar onu asla içe aktarmayacak. etils.epy.lazy_imports kullanıyoruz.

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

Temelde, LazyModule sınıfı bir fabrika gibi davranır ve modülü yalnızca bir özniteliğe erişildiğinde ( __getattr__ ) içe aktarır.

Ayrıca bir bağlam yöneticisiyle de rahatlıkla kullanabilirsiniz:

from etils import epy

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