Следуйте этому руководству, чтобы создать новый набор данных (в TFDS или в вашем собственном репозитории).
Проверьте наш список наборов данных , чтобы узнать, существует ли уже нужный вам набор данных.
ТЛ;ДР
Самый простой способ написать новый набор данных — использовать CLI TFDS :
cd path/to/my/project/datasets/
tfds new my_dataset # Create `my_dataset/my_dataset.py` template files
# [...] Manually modify `my_dataset/my_dataset_dataset_builder.py` to implement your dataset.
cd my_dataset/
tfds build # Download and prepare the dataset to `~/tensorflow_datasets/`
Чтобы использовать новый набор данных с tfds.load('my_dataset')
:
-
tfds.load
автоматически обнаружит и загрузит набор данных, сгенерированный в~/tensorflow_datasets/my_dataset/
(например, с помощьюtfds build
). - Альтернативно вы можете явно
import my.project.datasets.my_dataset
чтобы зарегистрировать свой набор данных:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Обзор
Наборы данных распространяются во всех форматах и во всех местах, и они не всегда хранятся в формате, готовом к передаче в конвейер машинного обучения. Введите ТФДС.
TFDS обрабатывает эти наборы данных в стандартный формат (внешние данные -> сериализованные файлы), которые затем можно загрузить как конвейер машинного обучения (сериализованные файлы -> tf.data.Dataset
). Сериализация выполняется только один раз. Последующий доступ будет производить чтение непосредственно из этих предварительно обработанных файлов.
Большая часть предварительной обработки выполняется автоматически. Каждый набор данных реализует подкласс tfds.core.DatasetBuilder
, который определяет:
- Откуда поступают данные (т. е. их URL-адреса);
- Как выглядит набор данных (т.е. его характеристики);
- Как данные должны быть разделены (например,
TRAIN
иTEST
); - и отдельные примеры в наборе данных.
Напишите свой набор данных
Шаблон по умолчанию: tfds new
Используйте TFDS CLI для создания необходимых файлов шаблонов Python.
cd path/to/project/datasets/ # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset
Эта команда создаст новую папку my_dataset/
со следующей структурой:
my_dataset/
__init__.py
README.md # Markdown description of the dataset.
CITATIONS.bib # Bibtex citation for the dataset.
TAGS.txt # List of tags describing the dataset.
my_dataset_dataset_builder.py # Dataset definition
my_dataset_dataset_builder_test.py # Test
dummy_data/ # (optional) Fake data (used for testing)
checksum.tsv # (optional) URL checksums (see `checksums` section).
Найдите здесь TODO(my_dataset)
и измените соответствующим образом.
Пример набора данных
Все наборы данных являются подклассами tfds.core.DatasetBuilder
, который заботится о большей части шаблонов. Он поддерживает:
- Маленькие/средние наборы данных, которые можно создать на одном компьютере (это руководство).
- Очень большие наборы данных, требующие распределенной генерации (с использованием Apache Beam , см. наше руководство по огромным наборам данных ).
Вот минимальный пример построителя набора данных, основанного на tfds.core.GeneratorBasedBuilder
:
class Builder(tfds.core.GeneratorBasedBuilder):
"""DatasetBuilder for my_dataset dataset."""
VERSION = tfds.core.Version('1.0.0')
RELEASE_NOTES = {
'1.0.0': 'Initial release.',
}
def _info(self) -> tfds.core.DatasetInfo:
"""Dataset metadata (homepage, citation,...)."""
return self.dataset_info_from_configs(
features=tfds.features.FeaturesDict({
'image': tfds.features.Image(shape=(256, 256, 3)),
'label': tfds.features.ClassLabel(
names=['no', 'yes'],
doc='Whether this is a picture of a cat'),
}),
)
def _split_generators(self, dl_manager: tfds.download.DownloadManager):
"""Download the data and define splits."""
extracted_path = dl_manager.download_and_extract('http://data.org/data.zip')
# dl_manager returns pathlib-like objects with `path.read_text()`,
# `path.iterdir()`,...
return {
'train': self._generate_examples(path=extracted_path / 'train_images'),
'test': self._generate_examples(path=extracted_path / 'test_images'),
}
def _generate_examples(self, path) -> Iterator[Tuple[Key, Example]]:
"""Generator of examples for each split."""
for img_path in path.glob('*.jpeg'):
# Yields (key, example)
yield img_path.name, {
'image': img_path,
'label': 'yes' if img_path.name.startswith('yes_') else 'no',
}
Обратите внимание, что для некоторых конкретных форматов данных мы предоставляем готовые к использованию конструкторы наборов данных , которые помогут выполнить большую часть обработки данных.
Давайте подробно рассмотрим три абстрактных метода перезаписи.
_info
: метаданные набора данных
_info
возвращает tfds.core.DatasetInfo
, содержащий метаданные набора данных .
def _info(self):
# The `dataset_info_from_configs` base method will construct the
# `tfds.core.DatasetInfo` object using the passed-in parameters and
# adding: builder (self), description/citations/tags from the config
# files located in the same package.
return self.dataset_info_from_configs(
homepage='https://dataset-homepage.org',
features=tfds.features.FeaturesDict({
'image_description': tfds.features.Text(),
'image': tfds.features.Image(),
# Here, 'label' can be 0-4.
'label': tfds.features.ClassLabel(num_classes=5),
}),
# If there's a common `(input, target)` tuple from the features,
# specify them here. They'll be used if as_supervised=True in
# builder.as_dataset.
supervised_keys=('image', 'label'),
# Specify whether to disable shuffling on the examples. Set to False by default.
disable_shuffling=False,
)
Большинство полей не требуют пояснений. Некоторые уточнения:
-
features
: здесь указывается структура, форма набора данных... Поддержка сложных типов данных (аудио, видео, вложенные последовательности...). Дополнительные сведения см. в доступных функциях или в руководстве по подключению функций . -
disable_shuffling
: См. раздел «Поддержание порядка набора данных» .
Написание файла BibText
CITATIONS.bib
:
- Найдите на веб-сайте набора данных инструкции по цитированию (используйте их в формате BibTex).
- Для статей arXiv : найдите статью и щелкните ссылку
BibText
справа. - Найдите статью в Google Scholar , щелкните двойную кавычку под заголовком и во всплывающем окне нажмите
BibTeX
. - Если связанного документа нет (например, есть только веб-сайт), вы можете использовать онлайн-редактор BibTeX для создания пользовательской записи BibTeX (в раскрывающемся меню есть тип записи
Online
).
Обновление файла TAGS.txt
:
- Все разрешенные теги предварительно заполняются в сгенерированном файле.
- Удалите все теги, которые не относятся к набору данных.
- Допустимые теги перечислены в tensorflow_datasets/core/valid_tags.txt .
- Чтобы добавить тег в этот список, отправьте PR.
Поддерживать порядок набора данных
По умолчанию записи наборов данных при хранении перемешиваются, чтобы сделать распределение классов более равномерным по набору данных, поскольку зачастую записи, принадлежащие одному классу, являются смежными. Чтобы указать, что набор данных должен быть отсортирован по ключу, сгенерированному _generate_examples
, поле disable_shuffling
должно быть установлено в True
. По умолчанию установлено значение False
.
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
Имейте в виду, что отключение перетасовки влияет на производительность, поскольку сегменты больше не могут читаться параллельно.
_split_generators
: загружает и разделяет данные.
Загрузка и извлечение исходных данных
Большинству наборов данных необходимо загружать данные из Интернета. Это делается с помощью входного аргумента tfds.download.DownloadManager
_split_generators
. dl_manager
имеет следующие методы:
-
download
: поддерживаетhttp(s)://
,ftp(s)://
-
extract
: в настоящее время поддерживаются файлы.zip
,.gz
и.tar
. -
download_and_extract
: То же, что иdl_manager.extract(dl_manager.download(urls))
Все эти методы возвращают tfds.core.Path
(псевдонимы для epath.Path
), которые являются объектами , подобными pathlib.Path .
Эти методы поддерживают произвольную вложенную структуру ( list
, dict
), например:
extracted_paths = dl_manager.download_and_extract({
'foo': 'https://example.com/foo.zip',
'bar': 'https://example.com/bar.zip',
})
# This returns:
assert extracted_paths == {
'foo': Path('/path/to/extracted_foo/'),
'bar': Path('/path/extracted_bar/'),
}
Ручная загрузка и извлечение
Некоторые данные не могут быть загружены автоматически (например, требуется вход в систему), в этом случае пользователь вручную загрузит исходные данные и поместит их в manual_dir/
(по умолчанию ~/tensorflow_datasets/downloads/manual/
).
Доступ к файлам можно будет получить через dl_manager.manual_dir
:
class MyDataset(tfds.core.GeneratorBasedBuilder):
MANUAL_DOWNLOAD_INSTRUCTIONS = """
Register into https://example.org/login to get the data. Place the `data.zip`
file in the `manual_dir/`.
"""
def _split_generators(self, dl_manager):
# data_path is a pathlib-like `Path('<manual_dir>/data.zip')`
archive_path = dl_manager.manual_dir / 'data.zip'
# Extract the manually downloaded `data.zip`
extracted_path = dl_manager.extract(archive_path)
...
Местоположение manual_dir
можно настроить с помощью tfds build --manual_dir=
или с помощью tfds.download.DownloadConfig
.
Читать архив напрямую
dl_manager.iter_archive
читает архивы последовательно, не распаковывая их. Это может сэкономить место для хранения и повысить производительность некоторых файловых систем.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
fobj
имеет те же методы, что и with open('rb') as fobj:
(например, fobj.read()
)
Указание разделения набора данных
Если набор данных поставляется с заранее определенными разбиениями (например, MNIST
есть разделения train
и test
), сохраните их. В противном случае укажите только одно разделение all
. Пользователи могут динамически создавать свои собственные подразделения с помощью API-интерфейса subsplit (например, split='train[80%:]'
). Обратите внимание, что в качестве имени разделения можно использовать любую буквенную строку, кроме вышеупомянутой all
.
def _split_generators(self, dl_manager):
# Download source data
extracted_path = dl_manager.download_and_extract(...)
# Specify the splits
return {
'train': self._generate_examples(
images_path=extracted_path / 'train_imgs',
label_path=extracted_path / 'train_labels.csv',
),
'test': self._generate_examples(
images_path=extracted_path / 'test_imgs',
label_path=extracted_path / 'test_labels.csv',
),
}
_generate_examples
: Пример генератора
_generate_examples
генерирует примеры для каждого разделения из исходных данных.
Этот метод обычно считывает артефакты исходного набора данных (например, CSV-файл) и выдает кортежи (key, feature_dict)
:
-
key
: Пример идентификатора. Используется для детерминированного перемешивания примеров с использованиемhash(key)
или для сортировки по ключу, когда перемешивание отключено (см. раздел «Поддержание порядка набора данных» ). Должно быть:- unique : если в двух примерах используется один и тот же ключ, будет возбуждено исключение.
- детерминированный : не должен зависеть от порядка
download_dir
,os.path.listdir
... Двойная генерация данных должна дать один и тот же ключ. - сопоставимый : если перетасовка отключена, ключ будет использоваться для сортировки набора данных.
-
feature_dict
:dict
содержащий примеры значений.- Структура должна соответствовать структуре
features=
определенной вtfds.core.DatasetInfo
. - Сложные типы данных (изображение, видео, аудио и т. д.) будут автоматически кодироваться.
- Каждая функция часто принимает несколько типов ввода (например, видео принимает
/path/to/vid.mp4
,np.array(shape=(l, h, w, c))
,List[paths]
,List[np.array(shape=(h, w, c)]
,List[img_bytes]
,...) - Дополнительную информацию см. в руководстве по функциональному разъему .
- Структура должна соответствовать структуре
def _generate_examples(self, images_path, label_path):
# Read the input data out of the source files
with label_path.open() as f:
for row in csv.DictReader(f):
image_id = row['image_id']
# And yield (key, feature_dict)
yield image_id, {
'image_description': row['description'],
'image': images_path / f'{image_id}.jpeg',
'label': row['label'],
}
Доступ к файлам и tf.io.gfile
Для поддержки облачных систем хранения избегайте использования встроенных операций ввода-вывода Python.
Вместо этого dl_manager
возвращает объекты , подобные pathlib, напрямую совместимые с облачным хранилищем Google:
path = dl_manager.download_and_extract('http://some-website/my_data.zip')
json_path = path / 'data/file.json'
json.loads(json_path.read_text())
Альтернативно, используйте API tf.io.gfile
вместо встроенного для файловых операций:
-
open
->tf.io.gfile.GFile
-
os.rename
->tf.io.gfile.rename
- ...
Pathlib следует отдавать предпочтение tf.io.gfile
( см .
Дополнительные зависимости
Для некоторых наборов данных дополнительные зависимости Python требуются только во время генерации. Например, набор данных SVHN использует scipy
для загрузки некоторых данных.
Если вы добавляете набор данных в репозиторий TFDS, используйте tfds.core.lazy_imports
чтобы сохранить небольшой размер пакета tensorflow-datasets
. Пользователи будут устанавливать дополнительные зависимости только по мере необходимости.
Чтобы использовать lazy_imports
:
- Добавьте запись для вашего набора данных в
DATASET_EXTRAS
вsetup.py
. Благодаря этому пользователи могут, например, выполнитьpip install 'tensorflow-datasets[svhn]'
чтобы установить дополнительные зависимости. - Добавьте запись для импорта в
LazyImporter
иLazyImportsTest
. - Используйте
tfds.core.lazy_imports
для доступа к зависимости (например,tfds.core.lazy_imports.scipy
) в вашемDatasetBuilder
.
Поврежденные данные
Некоторые наборы данных не совсем чисты и содержат поврежденные данные (например, изображения находятся в файлах JPEG, но некоторые из них являются недействительными JPEG). Эти примеры следует пропустить, но оставьте в описании набора данных пометку, сколько примеров было исключено и почему.
Конфигурация/варианты набора данных (tfds.core.BuilderConfig)
Некоторые наборы данных могут иметь несколько вариантов или вариантов предварительной обработки и записи данных на диск. Например, у Cycl_gan есть одна конфигурация для каждой пары объектов ( cycle_gan/horse2zebra
, cycle_gan/monet2photo
,...).
Это делается через tfds.core.BuilderConfig
:
Определите свой объект конфигурации как подкласс
tfds.core.BuilderConfig
. Например,MyDatasetConfig
.@dataclasses.dataclass class MyDatasetConfig(tfds.core.BuilderConfig): img_size: Tuple[int, int] = (0, 0)
Определите член класса
BUILDER_CONFIGS = []
вMyDataset
, в котором перечисленыMyDatasetConfig
, предоставляемые набором данных.class MyDataset(tfds.core.GeneratorBasedBuilder): VERSION = tfds.core.Version('1.0.0') # pytype: disable=wrong-keyword-args BUILDER_CONFIGS = [ # `name` (and optionally `description`) are required for each config MyDatasetConfig(name='small', description='Small ...', img_size=(8, 8)), MyDatasetConfig(name='big', description='Big ...', img_size=(32, 32)), ] # pytype: enable=wrong-keyword-args
Используйте
self.builder_config
вMyDataset
для настройки генерации данных (например,shape=self.builder_config.img_size
). Это может включать установку других значений в_info()
или изменение доступа к данным загрузки.
Примечания:
- Каждая конфигурация имеет уникальное имя. Полное имя конфигурации —
dataset_name/config_name
(например,coco/2017
). - Если не указано, будет использоваться первая конфигурация в
BUILDER_CONFIGS
(например,tfds.load('c4')
по умолчанию —c4/en
)
См. anli
для примера набора данных, который использует BuilderConfig
s.
Версия
Версия может иметь два разных значения:
- «Внешняя» исходная версия данных: например, COCO v2019, v2017,...
- «Внутренняя» версия кода TFDS: например, переименуйте функцию в
tfds.features.FeaturesDict
, исправьте ошибку в_generate_examples
Чтобы обновить набор данных:
- Для «внешнего» обновления данных: несколько пользователей могут одновременно захотеть получить доступ к определенному году/версии. Это делается с помощью одного
tfds.core.BuilderConfig
для каждой версии (например,coco/2017
,coco/2019
) или одного класса для каждой версии (например,Voc2007
,Voc2012
). - Для «внутреннего» обновления кода: пользователи загружают только самую последнюю версию. Любое обновление кода должно увеличивать атрибут класса
VERSION
(например, с1.0.0
доVERSION = tfds.core.Version('2.0.0')
) после семантического управления версиями .
Добавить импорт для регистрации
Не забудьте импортировать модуль набора данных в свой проект __init__
, чтобы он автоматически регистрировался в tfds.load
, tfds.builder
.
import my_project.datasets.my_dataset # Register MyDataset
ds = tfds.load('my_dataset') # MyDataset available
Например, если вы участвуете в проекте tensorflow/datasets
, добавьте импорт модуля в __init__.py
его подкаталога (например, image/__init__.py
.
Проверьте распространенные ошибки реализации
Пожалуйста, проверьте распространенные ошибки реализации .
Проверьте свой набор данных
Загрузите и подготовьте: tfds build
Чтобы сгенерировать набор данных, запустите tfds build
из каталога my_dataset/
:
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Некоторые полезные флаги для разработки:
-
--pdb
: войти в режим отладки, если возникнет исключение. -
--overwrite
: удалить существующие файлы, если набор данных уже был создан. -
--max_examples_per_split
: генерировать только первые X примеров (по умолчанию 1), а не полный набор данных. -
--register_checksums
: записать контрольные суммы загруженных URL-адресов. Следует использовать только во время разработки.
Полный список флагов см. в документации CLI .
Контрольные суммы
Рекомендуется записывать контрольные суммы ваших наборов данных, чтобы гарантировать детерминированность, помогать с документацией... Это делается путем создания набора данных с помощью --register_checksums
(см. предыдущий раздел).
Если вы выпускаете свои наборы данных через PyPI, не забудьте экспортировать файлы checksums.tsv
(например, в package_data
вашего setup.py
).
Проведите модульное тестирование вашего набора данных
tfds.testing.DatasetBuilderTestCase
— это базовый TestCase
для полной проверки набора данных. Он использует «фиктивные данные» в качестве тестовых данных, имитирующих структуру исходного набора данных.
- Тестовые данные должны быть помещены в каталог
my_dataset/dummy_data/
и должны имитировать артефакты исходного набора данных при загрузке и извлечении. Его можно создать вручную или автоматически с помощью скрипта ( пример скрипта ). - Обязательно используйте разные данные в разбивках тестовых данных, так как тест завершится неудачно, если разбиения набора данных перекроются.
- Данные испытаний не должны содержать материалов, защищенных авторским правом . В случае сомнений не создавайте данные, используя материал из исходного набора данных.
import tensorflow_datasets as tfds
from . import my_dataset_dataset_builder
class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
"""Tests for my_dataset dataset."""
DATASET_CLASS = my_dataset_dataset_builder.Builder
SPLITS = {
'train': 3, # Number of fake train example
'test': 1, # Number of fake test example
}
# If you are calling `download/download_and_extract` with a dict, like:
# dl_manager.download({'some_key': 'http://a.org/out.txt', ...})
# then the tests needs to provide the fake output paths relative to the
# fake data directory
DL_EXTRACT_RESULT = {
'name1': 'path/to/file1', # Relative to my_dataset/dummy_data dir.
'name2': 'file2',
}
if __name__ == '__main__':
tfds.testing.test_main()
Запустите следующую команду, чтобы проверить набор данных.
python my_dataset_test.py
Отправьте нам отзыв
Мы постоянно пытаемся улучшить рабочий процесс создания наборов данных, но сможем сделать это только в том случае, если будем знать о проблемах. С какими проблемами или ошибками вы столкнулись при создании набора данных? Была ли какая-то часть, которая сбивала с толку или не работала с первого раза?
Поделитесь своим отзывом на GitHub .