이 페이지에서는 새 데이터세트를 구현할 때 일반적인 구현 방법을 설명합니다.
레거시 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
또는 Google 직원의 경우 gtfds new
)를 사용하여 템플릿을 생성하세요.
이유 : 이전 구조에는 체크섬, 가짜 데이터에 대한 절대 경로가 필요했으며 데이터 세트 파일을 여러 위치에 배포했습니다. 이로 인해 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 기타 텍스트
ClassLabel 이름을 잊어버렸습니다.
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%:]'])
파이썬 스타일 가이드
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