このページでは、新しいデータセットを実装する際の一般的な実装の問題について説明します。
従来のSplitGenerator
避けるべきです
古いtfds.core.SplitGenerator
API は非推奨になりました。
def _split_generator(...):
return [
tfds.core.SplitGenerator(name='train', gen_kwargs={'path': train_path}),
tfds.core.SplitGenerator(name='test', gen_kwargs={'path': test_path}),
]
以下のように置き換える必要があります。
def _split_generator(...):
return {
'train': self._generate_examples(path=train_path),
'test': self._generate_examples(path=test_path),
}
理論的根拠: 新しい API は冗長性が低く、より明示的になっています。古い API は将来のバージョンで削除される予定です。
新しいデータセットはフォルダー内に自己完結型である必要があります
tensorflow_datasets/
リポジトリ内にデータセットを追加するときは、フォルダーとしてのデータセット構造 (すべてのチェックサム、ダミー データ、フォルダー内に自己完結型の実装コード) に従っていることを確認してください。
- 古いデータセット (不良):
<category>/<ds_name>.py
- 新しいデータセット (良好):
<category>/<ds_name>/<ds_name>.py
TFDS CLI ( tfds new
、またはgtfds new
for googlers) を使用してテンプレートを生成します。
根拠: 古い構造では、チェックサムや偽のデータに絶対パスが必要で、データセット ファイルがさまざまな場所に分散されていました。そのため、TFDS リポジトリの外部にデータセットを実装することが困難になってきました。一貫性を保つために、今後はどこでも新しい構造を使用する必要があります。
説明リストはマークダウンとしてフォーマットする必要があります
DatasetInfo.description
str
はマークダウンとしてフォーマットされます。マークダウン リストでは、最初の項目の前に空の行が必要です。
_DESCRIPTION = """
Some text.
# << Empty line here !!!
1. Item 1
2. Item 1
3. Item 1
# << Empty line here !!!
Some other text.
"""
根拠: 不適切な形式の説明により、カタログ ドキュメントに視覚的なアーチファクトが作成されます。空行がないと、上記のテキストは次のように表示されます。
いくつかのテキスト。 1. 項目 1 2. 項目 1 3. 項目 1 他のテキスト
クラスラベル名を忘れた場合
tfds.features.ClassLabel
を使用する場合は、人間が読めるラベルstr
にnames=
またはnames_file=
( num_classes=10
の代わりに) を指定するようにしてください。
features = {
'label': tfds.features.ClassLabel(names=['dog', 'cat', ...]),
}
理論的根拠: 人間が判読できるラベルはさまざまな場所で使用されています。
-
_generate_examples
でstr
を直接生成できるようにします:yield {'label': 'dog'}
-
info.features['label'].names
のようにユーザーに公開されます (変換メソッド.str2int('dog')
、... も利用可能) - 視覚化ユーティリティ
tfds.show_examples
、tfds.as_dataframe
で使用されます。
画像の形を忘れた
tfds.features.Image
、 tfds.features.Video
を使用する場合、画像が静的な形状を持つ場合は、明示的に指定する必要があります。
features = {
'image': tfds.features.Image(shape=(256, 256, 3)),
}
理論的根拠: バッチ処理に必要な静的な形状推論 (例: ds.element_spec['image'].shape
) が可能になります (未知の形状の画像をバッチ処理するには、最初にサイズを変更する必要があります)。
tfds.features.Tensor
の代わりに、より具体的な型を優先します。
可能であれば、汎用のtfds.features.Tensor
ではなく、より具体的な型tfds.features.ClassLabel
、 tfds.features.BBoxFeatures
、... を優先してください。
根拠: 特定の機能は、意味的により正確であることに加えて、追加のメタデータをユーザーに提供し、ツールによって検出されます。
グローバル空間での遅延インポート
遅延インポートはグローバル空間から呼び出すべきではありません。たとえば、次のような記述は誤りです。
tfds.lazy_imports.apache_beam # << Error: Import beam in the global scope
def f() -> beam.Map:
...
理論的根拠: グローバル スコープで遅延インポートを使用すると、すべての tfds ユーザーに対してモジュールがインポートされるため、遅延インポートの目的が無効になります。
トレーニング/テスト分割を動的に計算する
データセットが公式の分割を提供しない場合、TFDS も提供すべきではありません。次のことは避けてください。
_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),
}
理論的根拠: TFDS は、元のデータに限りなく近いデータセットを提供しようとします。ユーザーが必要なサブスプリットを動的に作成できるようにするには、代わりにサブスプリット APIを使用する必要があります。
ds_train, ds_test = tfds.load(..., split=['train[:80%]', 'train[80%:]'])
Python スタイルガイド
pathlib API を使用することを推奨します
tf.io.gfile
API の代わりに、 pathlib APIを使用することをお勧めします。すべてのdl_manager
メソッドは、GCS、S3 などと互換性のある pathlib のようなオブジェクトを返します。
path = dl_manager.download_and_extract('http://some-website/my_data.zip')
json_path = path / 'data/file.json'
json.loads(json_path.read_text())
理論的根拠: pathlib API は、ボイラープレートを削除する最新のオブジェクト指向ファイル API です。 .read_text()
/ .read_bytes()
を使用すると、ファイルが正しく閉じられることも保証されます。
メソッドがself
を使用していない場合は、関数である必要があります
クラスメソッドがself
を使用していない場合、それは単純な関数 (クラスの外部で定義される) である必要があります。
理論的根拠: これにより、関数に副作用や隠蔽された入出力がないことが読者に明示されます。
x = f(y) # Clear inputs/outputs
x = self.f(y) # Does f depend on additional hidden variables ? Is it stateful ?
Python での遅延インポート
TensorFlow のような大きなモジュールを遅延インポートします。遅延インポートでは、モジュールの実際のインポートがモジュールの最初の使用まで延期されます。したがって、この大きなモジュールを必要としないユーザーは決してインポートしません。 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
内部では、 LazyModule
クラスはファクトリとして機能し、属性がアクセスされたとき ( __getattr__
) にのみ実際にモジュールをインポートします。
コンテキスト マネージャーと組み合わせて便利に使用することもできます。
from etils import epy
with epy.lazy_imports(error_callback=..., success_callback=...):
import some_big_module