MLコミュニティデーは11月9日です! TensorFlow、JAXからの更新のために私たちに参加し、より多くの詳細をご覧ください

一般的な実装の落とし穴

このページでは、新しいデータセットを実装する際の一般的な実装の落とし穴について説明します。

レガシー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/リポジトリを、データセット-AS-フォルダ構造(すべてのチェックサム、ダミーデータ、実装コードのフォルダに自己完結型)に追従することを確認してください。

  • 古いデータセット(悪い): <category>/<ds_name>.py
  • 新しいデータセット(良い): <category>/<ds_name>/<ds_name>.py

使用TFDS CLItfds new 、またはgtfds newテンプレートを生成するためのGooglerのために)。

理論的根拠:古い構造は、チェックサム、偽のデータのための絶対パスを必要とし、多くの場所でのデータセットファイルを配布しました。 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.アイテム12.アイテム13.アイテム1その他のテキスト

ClassLabel名を忘れた

使用している場合tfds.features.ClassLabel 、人間が読めるラベルを提供しようとするstrnames=またはnames_file= (代わりのnum_classes=10 )。

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

理論的根拠:人間の読めるラベルは、多くの場所で使用されています。

  • 得許可strに直接_generate_examplesyield {'label': 'dog'}
  • 以下のようなユーザーにさらさinfo.features['label'].names (変換方法.str2int('dog') 、...も利用可能)
  • で使用される可視化utilsのtfds.show_examplestfds.as_dataframe

画像の形を忘れた

使用している場合tfds.features.Imagetfds.features.Videoイメージは静的な形状を持っている場合、彼らはexpliclty指定する必要があります。

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

理論的根拠:それ静的形状推論(例えば許すds.element_spec['image'].shapeバッチ処理のために必要とされる)、(未知の形状のバッチ処理画像が最初にそれらをサイズ変更が必要となります)。

より具体的なタイプの代わりに、優先tfds.features.Tensor

可能な場合は、より具体的なタイプを好むtfds.features.ClassLabeltfds.features.BBoxFeatures 、...ではなく、汎用のtfds.features.Tensor

原理は:より意味的に正確であることの他に、特定のユーザーに追加のメタデータを提供する機能とツールによって検出されます。

グローバル空間での怠惰なインポート

レイジーインポートは、グローバルスペースから呼び出すべきではありません。たとえば、次のように間違っています。

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

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

理由:グローバルスコープで怠惰な輸入品を使用すると、怠惰な輸入の目的を破り、すべてのTFDのユーザーのためのモジュールをインポートします。

トレイン/テスト分割を動的に計算する

データセットが公式の分割を提供しない場合、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は、ユーザーが動的に彼らが望むsubsplitsを作成できるようにする代わりに使用する必要があります。

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

Pythonスタイルガイド

pathlibAPIを使用することをお勧めします

代わりのtf.io.gfile API、使用することが好ましいpathlibのAPIを。すべてのdl_managerメソッドが返すpathlib状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())

理論的根拠: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 ?