Sigue esta guía para crear un nuevo conjunto de datos (ya sea en TFDS o en tu propio repositorio).
Consulta nuestra lista de conjuntos de datos para comprobar si el conjunto de datos que buscas ya está disponible.
TL;DR
La forma más sencilla de escribir un nuevo conjunto de datos es usar la interfaz de línea de comandos de 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/`
Para usar el nuevo conjunto de datos con tfds.load('my_dataset') :
-
tfds.loaddetectará y cargará automáticamente el conjunto de datos generado en~/tensorflow_datasets/my_dataset/(por ejemplo, mediantetfds build). - Como alternativa, puede
import my.project.datasets.my_datasetpara registrar su conjunto de datos:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Descripción general
Los conjuntos de datos se distribuyen en todo tipo de formatos y en todo tipo de lugares, y no siempre se almacenan en un formato listo para ser introducido en un proceso de aprendizaje automático. Aquí es donde entra TFDS.
TFDS procesa estos conjuntos de datos y los convierte a un formato estándar (datos externos -> archivos serializados), que luego se pueden cargar como parte de un flujo de trabajo de aprendizaje automático (archivos serializados -> tf.data.Dataset ). La serialización se realiza una sola vez. Los accesos posteriores leerán directamente de esos archivos preprocesados.
La mayor parte del preprocesamiento se realiza automáticamente. Cada conjunto de datos implementa una subclase de tfds.core.DatasetBuilder , que especifica:
- De dónde provienen los datos (es decir, sus URL);
- Cómo es el conjunto de datos (es decir, sus características);
- Cómo se deben dividir los datos (por ejemplo,
TRAINyTEST); - y los ejemplos individuales del conjunto de datos.
Escribe tu conjunto de datos
Plantilla predeterminada: tfds new
Utilice la interfaz de línea de comandos de TFDS para generar los archivos de plantilla de Python necesarios.
cd path/to/project/datasets/ # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset
Este comando generará una nueva carpeta my_dataset/ con la siguiente estructura:
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).
Busque TODO(my_dataset) aquí y modifíquelo según corresponda.
Ejemplo de conjunto de datos
Todos los conjuntos de datos son subclases implementadas de tfds.core.DatasetBuilder , que se encarga de la mayor parte del código repetitivo. Admite:
- Conjuntos de datos pequeños/medianos que se pueden generar en una sola máquina (este tutorial).
- Conjuntos de datos muy grandes que requieren generación distribuida (usando Apache Beam , consulte nuestra guía para conjuntos de datos enormes ).
Aquí hay un ejemplo mínimo de un constructor de conjuntos de datos que se basa en 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',
}
Tenga en cuenta que, para algunos formatos de datos específicos, proporcionamos generadores de conjuntos de datos listos para usar que se encargan de la mayor parte del procesamiento de datos.
Veamos en detalle los 3 métodos abstractos para sobrescribir.
_info : metadatos del conjunto de datos
_info devuelve el objeto tfds.core.DatasetInfo que contiene los metadatos del conjunto de datos .
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,
)
La mayoría de los campos deberían ser autoexplicativos. Algunas precisiones:
-
features: Esto especifica la estructura del conjunto de datos, su forma, etc. Admite tipos de datos complejos (audio, vídeo, secuencias anidadas, etc.). Consulte las características disponibles o la guía del conector de características para obtener más información. -
disable_shuffling: Consulte la sección Mantener el orden del conjunto de datos .
Escribiendo el archivo BibText CITATIONS.bib :
- Busque en el sitio web del conjunto de datos las instrucciones para citar los datos (utilice el formato BibTeX).
- Para artículos de arXiv : busque el artículo y haga clic en el enlace
BibTextque aparece en el lado derecho. - Busque el artículo en Google Scholar y haga clic en las comillas dobles que aparecen debajo del título y, en la ventana emergente, haga clic en
BibTeX. - Si no hay ningún documento asociado (por ejemplo, si solo hay un sitio web), puede utilizar el editor en línea de BibTeX para crear una entrada BibTeX personalizada (el menú desplegable tiene un tipo de entrada
Online).
Actualizando el archivo TAGS.txt :
- Todas las etiquetas permitidas están precargadas en el archivo generado.
- Elimine todas las etiquetas que no se apliquen al conjunto de datos.
- Las etiquetas válidas se enumeran en tensorflow_datasets/core/valid_tags.txt .
- Para agregar una etiqueta a esa lista, envíe una solicitud de extracción (PR).
Mantener el orden del conjunto de datos
Por defecto, los registros de los conjuntos de datos se mezclan aleatoriamente al almacenarse para lograr una distribución más uniforme de las clases, ya que a menudo los registros de la misma clase son contiguos. Para especificar que el conjunto de datos se ordene según la clave generada por _generate_examples el campo disable_shuffling debe establecerse en True . Por defecto, está establecido en False .
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
Tenga en cuenta que deshabilitar la reorganización de datos tiene un impacto en el rendimiento, ya que los fragmentos ya no se pueden leer en paralelo.
_split_generators : descarga y divide datos
Descarga y extracción de datos de origen
La mayoría de los conjuntos de datos necesitan descargar datos de la web. Esto se hace utilizando el argumento de entrada tfds.download.DownloadManager de _split_generators . dl_manager tiene los siguientes métodos:
-
download: admitehttp(s)://,ftp(s):// -
extract: actualmente admite archivos.zip,.gzy.tar. -
download_and_extract: Igual quedl_manager.extract(dl_manager.download(urls))
Todos esos métodos devuelven tfds.core.Path (alias para epath.Path ), que son objetos similares a pathlib.Path .
Estos métodos admiten estructuras anidadas arbitrarias ( list , dict ), como por ejemplo:
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/'),
}
Descarga y extracción manual
Algunos datos no se pueden descargar automáticamente (por ejemplo, requieren iniciar sesión); en este caso, el usuario deberá descargar manualmente los datos de origen y colocarlos en manual_dir/ (por defecto, ~/tensorflow_datasets/downloads/manual/ ).
Los archivos se pueden acceder a través de 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)
...
La ubicación manual_dir se puede personalizar con tfds build --manual_dir= o usando tfds.download.DownloadConfig .
Lea el archivo directamente
dl_manager.iter_archive lee los archivos secuencialmente sin extraerlos. Esto puede ahorrar espacio de almacenamiento y mejorar el rendimiento en algunos sistemas de archivos.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
fobj tiene los mismos métodos que with open('rb') as fobj: (por ejemplo fobj.read() )
Especificación de divisiones de conjuntos de datos
Si el conjunto de datos incluye divisiones predefinidas (por ejemplo, MNIST tiene divisiones train y test ), manténgalas. De lo contrario, especifique solo una única división all ". Los usuarios pueden crear dinámicamente sus propias subdivisiones con la API de subdivisiones (por ejemplo split='train[80%:]' ). Tenga en cuenta que se puede usar cualquier cadena alfabética como nombre de división, excepto la mencionada 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 : Generador de ejemplos
_generate_examples genera los ejemplos para cada división a partir de los datos de origen.
Este método normalmente leerá los artefactos del conjunto de datos de origen (por ejemplo, un archivo CSV) y generará tuplas (key, feature_dict) :
-
key: Identificador de ejemplo. Se utiliza para mezclar de forma determinista los ejemplos mediantehash(key)o para ordenar por clave cuando la mezcla está desactivada (véase la sección Mantener el orden del conjunto de datos ). Debe ser:- único : Si dos ejemplos utilizan la misma clave, se generará una excepción.
- determinista : No debería depender del orden
download_dir,os.path.listdir,... Generar los datos dos veces debería producir la misma clave. - comparable : Si la función de barajado está desactivada, la clave se utilizará para ordenar el conjunto de datos.
-
feature_dict: Undictque contiene los valores de ejemplo.- La estructura debe coincidir con la estructura
features=definida entfds.core.DatasetInfo. - Los tipos de datos complejos (imagen, vídeo, audio,...) se codificarán automáticamente.
- Cada función suele aceptar varios tipos de entrada (por ejemplo, video acepta
/path/to/vid.mp4,np.array(shape=(l, h, w, c)),List[paths],List[np.array(shape=(h, w, c)],List[img_bytes], ...) - Consulte la guía del conector de funciones para obtener más información.
- La estructura debe coincidir con la estructura
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'],
}
Acceso a archivos y tf.io.gfile
Para poder utilizar sistemas de almacenamiento en la nube, evite el uso de las operaciones de entrada/salida integradas de Python.
En cambio, dl_manager devuelve objetos similares a pathlib directamente compatibles con el almacenamiento de Google Cloud:
path = dl_manager.download_and_extract('http://some-website/my_data.zip')
json_path = path / 'data/file.json'
json.loads(json_path.read_text())
Como alternativa, utilice la API tf.io.gfile en lugar de la integrada para operaciones con archivos:
-
open->tf.io.gfile.GFile -
os.rename->tf.io.gfile.rename - ...
Se debe preferir Pathlib a tf.io.gfile (ver rational .
dependencias adicionales
Algunos conjuntos de datos requieren dependencias adicionales de Python únicamente durante su generación. Por ejemplo, el conjunto de datos SVHN utiliza scipy para cargar algunos datos.
Si va a añadir un conjunto de datos al repositorio TFDS, utilice tfds.core.lazy_imports para mantener el tamaño del paquete tensorflow-datasets reducido. Los usuarios instalarán dependencias adicionales solo cuando sea necesario.
Para usar lazy_imports :
- Agregue una entrada para su conjunto de datos en
DATASET_EXTRASensetup.py. Esto permite que los usuarios puedan, por ejemplo, instalar las dependencias adicionalespip install 'tensorflow-datasets[svhn]'. - Agregue una entrada para su importación a
LazyImportery aLazyImportsTest. - Utilice
tfds.core.lazy_importspara acceder a la dependencia (por ejemplo,tfds.core.lazy_imports.scipy) en suDatasetBuilder.
Datos corruptos
Algunos conjuntos de datos no están completamente limpios y contienen datos corruptos (por ejemplo, las imágenes están en formato JPEG, pero algunas no son válidas). Estos ejemplos deben omitirse, pero se debe incluir una nota en la descripción del conjunto de datos indicando cuántos ejemplos se eliminaron y por qué.
Configuración/variantes del conjunto de datos (tfds.core.BuilderConfig)
Algunos conjuntos de datos pueden tener múltiples variantes u opciones sobre cómo se preprocesan y escriben los datos en el disco. Por ejemplo, cycle_gan tiene una configuración por cada par de objetos ( cycle_gan/horse2zebra , cycle_gan/monet2photo ,...).
Esto se hace a través de tfds.core.BuilderConfig s:
Defina su objeto de configuración como una subclase de
tfds.core.BuilderConfig. Por ejemplo,MyDatasetConfig.@dataclasses.dataclass class MyDatasetConfig(tfds.core.BuilderConfig): img_size: Tuple[int, int] = (0, 0)Defina el miembro de clase
BUILDER_CONFIGS = []enMyDatasetque enumera losMyDatasetConfigque expone el conjunto de datos.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-argsUtilice
self.builder_configenMyDatasetpara configurar la generación de datos (por ejemplo,shape=self.builder_config.img_size). Esto puede incluir establecer valores diferentes en_info()o cambiar el acceso a los datos de descarga.
Notas:
- Cada configuración tiene un nombre único. El nombre completo de una configuración es
dataset_name/config_name(por ejemplo,coco/2017). - Si no se especifica, se utilizará la primera configuración en
BUILDER_CONFIGS(por ejemplotfds.load('c4')por defecto ac4/en).
Consulte anli para ver un ejemplo de un conjunto de datos que utiliza BuilderConfig .
Versión
Versión puede referirse a dos significados diferentes:
- La versión de datos original "externa": por ejemplo, COCO v2019, v2017,...
- La versión "interna" del código TFDS: por ejemplo, cambiar el nombre de una característica en
tfds.features.FeaturesDict, corregir un error en_generate_examples
Para actualizar un conjunto de datos:
- Para la actualización de datos "externos": Varios usuarios pueden querer acceder a un año/versión específicos simultáneamente. Esto se hace utilizando un
tfds.core.BuilderConfigpor versión (por ejemplo,coco/2017,coco/2019) o una clase por versión (por ejemplo,Voc2007,Voc2012). - Para la actualización de código "interna": los usuarios solo descargan la versión más reciente. Cualquier actualización de código debe incrementar el atributo de clase
VERSION(por ejemplo, de1.0.0aVERSION = tfds.core.Version('2.0.0')) siguiendo el versionado semántico .
Agregar una importación para el registro
No olvides importar el módulo del conjunto de datos a tu proyecto __init__ para que se registre automáticamente en tfds.load , tfds.builder .
import my_project.datasets.my_dataset # Register MyDataset
ds = tfds.load('my_dataset') # MyDataset available
Por ejemplo, si está contribuyendo a tensorflow/datasets , agregue la importación del módulo al archivo __init__.py de su subdirectorio (por ejemplo, image/__init__.py ).
Comprueba si hay problemas comunes de implementación.
Por favor, compruebe si existen problemas comunes de implementación .
Prueba tu conjunto de datos
Descarga y prepara: tfds build
Para generar el conjunto de datos, ejecute tfds build desde el directorio my_dataset/ :
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Algunas banderas útiles para el desarrollo:
-
--pdb: Entra en modo de depuración si se produce una excepción. -
--overwrite: Elimina los archivos existentes si el conjunto de datos ya se generó. -
--max_examples_per_split: Generar solo los primeros X ejemplos (valor predeterminado: 1), en lugar del conjunto de datos completo. -
--register_checksums: Registra las sumas de verificación de las URL descargadas. Solo debe usarse durante el desarrollo.
Consulte la documentación de la interfaz de línea de comandos (CLI) para obtener la lista completa de indicadores.
sumas de verificación
Se recomienda registrar las sumas de verificación de sus conjuntos de datos para garantizar el determinismo, facilitar la documentación, etc. Esto se hace generando el conjunto de datos con la opción --register_checksums (véase la sección anterior).
Si publicas tus conjuntos de datos a través de PyPI, no olvides exportar los archivos checksums.tsv (por ejemplo, en package_data de tu setup.py ).
Prueba unitaria de tu conjunto de datos
tfds.testing.DatasetBuilderTestCase es un TestCase base para probar completamente un conjunto de datos. Utiliza "datos ficticios" como datos de prueba que imitan la estructura del conjunto de datos de origen.
- Los datos de prueba deben colocarse en el directorio
my_dataset/dummy_data/y deben imitar los artefactos del conjunto de datos original tal como se descargaron y extrajeron. Se pueden crear manualmente o automáticamente con un script ( ejemplo de script ). - Asegúrese de utilizar datos diferentes en las divisiones de sus datos de prueba, ya que la prueba fallará si las divisiones de su conjunto de datos se superponen.
- Los datos de prueba no deben contener material protegido por derechos de autor . En caso de duda, no cree los datos utilizando material del conjunto de datos original.
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()
Ejecute el siguiente comando para probar el conjunto de datos.
python my_dataset_test.py
Envíanos tus comentarios
Nos esforzamos continuamente por mejorar el flujo de trabajo de creación de conjuntos de datos, pero solo podemos hacerlo si conocemos los problemas. ¿Qué problemas o errores encontraste al crear el conjunto de datos? ¿Hubo alguna parte que te resultara confusa o que no funcionara correctamente la primera vez?
Por favor, comparte tus comentarios en GitHub .