Cargar tfrecord externo con TFDS

Si tiene un tf.train.Example (dentro de .tfrecord , .riegeli ,...), que ha sido generado por herramientas de terceros, que le gustaría cargar directamente con la API de tfds, entonces esta página es para usted.

Para cargar sus archivos .tfrecord , solo necesita:

  • Siga la convención de nomenclatura de TFDS.
  • Agregue archivos de metadatos ( dataset_info.json , features.json ) junto con sus archivos tfrecord.

Limitaciones:

Convención de nomenclatura de archivos

TFDS admite la definición de una plantilla para nombres de archivos, lo que brinda flexibilidad para usar diferentes esquemas de nombres de archivos. La plantilla está representada por tfds.core.ShardedFileTemplate y admite las siguientes variables: {DATASET} , {SPLIT} , {FILEFORMAT} , {SHARD_INDEX} , {NUM_SHARDS} y {SHARD_X_OF_Y} . Por ejemplo, el esquema de nombres de archivo predeterminado de TFDS es: {DATASET}-{SPLIT}.{FILEFORMAT}-{SHARD_X_OF_Y} . Para MNIST, esto significa que los nombres de archivo tienen el siguiente aspecto:

  • mnist-test.tfrecord-00000-of-00001
  • mnist-train.tfrecord-00000-of-00001

Agregar metadatos

Proporcione la estructura de características

Para que TFDS pueda descodificar el tf.train.Example , debe proporcionar la estructura tfds.features que coincida con sus especificaciones. Por ejemplo:

features = tfds.features.FeaturesDict({
    'image':
        tfds.features.Image(
            shape=(256, 256, 3),
            doc='Picture taken by smartphone, downscaled.'),
    'label':
        tfds.features.ClassLabel(names=['dog', 'cat']),
    'objects':
        tfds.features.Sequence({
            'camera/K': tfds.features.Tensor(shape=(3,), dtype=tf.float32),
        }),
})

Corresponde a las siguientes especificaciones de tf.train.Example :

{
    'image': tf.io.FixedLenFeature(shape=(), dtype=tf.string),
    'label': tf.io.FixedLenFeature(shape=(), dtype=tf.int64),
    'objects/camera/K': tf.io.FixedLenSequenceFeature(shape=(3,), dtype=tf.int64),
}

Especificar las funciones permite que TFDS decodifique automáticamente imágenes, videos,... Como cualquier otro conjunto de datos de TFDS, los metadatos de las funciones (p. ej., nombres de etiquetas,...) estarán expuestos al usuario (p. ej info.features['label'].names ).

Si controlas el gasoducto de generación

Si genera conjuntos de datos fuera de TFDS pero aún controla la canalización de generación, puede usar tfds.features.FeatureConnector.serialize_example para codificar sus datos de dict[np.ndarray] a tf.train.Example proto bytes :

with tf.io.TFRecordWriter('path/to/file.tfrecord') as writer:
  for ex in all_exs:
    ex_bytes = features.serialize_example(data)
    writer.write(ex_bytes)

Esto garantizará la compatibilidad de funciones con TFDS.

Del mismo modo, existe un feature.deserialize_example para decodificar el prototipo ( ejemplo )

Si no controlas el pipeline de generación

Si desea ver cómo se representan tfds.features en un tf.train.Example , puede examinar esto en colab:

  • Para traducir tfds.features a la estructura legible por humanos de tf.train.Example , puede llamar a functions.get_serialized_info features.get_serialized_info() .
  • Para obtener la especificación FixedLenFeature exacta,... pasada a tf.io.parse_single_example , puede usar spec = features.tf_example_spec

Obtener estadísticas sobre divisiones

TFDS requiere saber el número exacto de ejemplos dentro de cada fragmento. Esto es necesario para funciones como len(ds) o la API subdividida : split='train[75%:]' .

  • Si tiene esta información, puede crear explícitamente una lista de tfds.core.SplitInfo y pasar a la siguiente sección:

    split_infos = [
        tfds.core.SplitInfo(
            name='train',
            shard_lengths=[1024, ...],  # Num of examples in shard0, shard1,...
            num_bytes=0,  # Total size of your dataset (if unknown, set to 0)
        ),
        tfds.core.SplitInfo(name='test', ...),
    ]
    
  • Si no conoce esta información, puede calcularla utilizando el script compute_split_info.py (o en su propio script con tfds.folder_dataset.compute_split_info ). Lanzará una tubería de haz que leerá todos los fragmentos en el directorio dado y calculará la información.

Agregar archivos de metadatos

Para agregar automáticamente los archivos de metadatos adecuados a lo largo de su conjunto de datos, use tfds.folder_dataset.write_metadata :

tfds.folder_dataset.write_metadata(
    data_dir='/path/to/my/dataset/1.0.0/',
    features=features,
    # Pass the `out_dir` argument of compute_split_info (see section above)
    # You can also explicitly pass a list of `tfds.core.SplitInfo`.
    split_infos='/path/to/my/dataset/1.0.0/',
    # Pass a custom file name template or use None for the default TFDS
    # file name template.
    filename_template='{SPLIT}-{SHARD_X_OF_Y}.{FILEFORMAT}',

    # Optionally, additional DatasetInfo metadata can be provided
    # See:
    # https://www.tensorflow.org/datasets/api_docs/python/tfds/core/DatasetInfo
    description="""Multi-line description."""
    homepage='http://my-project.org',
    supervised_keys=('image', 'label'),
    citation="""BibTex citation.""",
)

Una vez que se haya llamado a la función una vez en el directorio de su conjunto de datos, se agregarán los archivos de metadatos ( dataset_info.json ,...) y sus conjuntos de datos estarán listos para cargarse con TFDS (consulte la siguiente sección).

Cargar conjunto de datos con TFDS

Directamente desde la carpeta

Una vez que se han generado los metadatos, los conjuntos de datos se pueden cargar mediante tfds.builder_from_directory que devuelve un tfds.core.DatasetBuilder con la API de TFDS estándar (como tfds.builder ):

builder = tfds.builder_from_directory('~/path/to/my_dataset/3.0.0/')

# Metadata are available as usual
builder.info.splits['train'].num_examples

# Construct the tf.data.Dataset pipeline
ds = builder.as_dataset(split='train[75%:]')
for ex in ds:
  ...

Directamente desde varias carpetas

También es posible cargar datos de varias carpetas. Esto puede suceder, por ejemplo, en el aprendizaje por refuerzo cuando varios agentes generan cada uno un conjunto de datos independiente y desea cargarlos todos juntos. Otros casos de uso son cuando se produce un nuevo conjunto de datos de forma regular, por ejemplo, un nuevo conjunto de datos por día, y desea cargar datos de un rango de fechas.

Para cargar datos de varias carpetas, utilice tfds.builder_from_directories , que devuelve un tfds.core.DatasetBuilder con la API de TFDS estándar (como tfds.builder ):

builder = tfds.builder_from_directories(builder_dirs=[
    '~/path/my_dataset/agent1/1.0.0/',
    '~/path/my_dataset/agent2/1.0.0/',
    '~/path/my_dataset/agent3/1.0.0/',
])

# Metadata are available as usual
builder.info.splits['train'].num_examples

# Construct the tf.data.Dataset pipeline
ds = builder.as_dataset(split='train[75%:]')
for ex in ds:
  ...

Estructura de carpetas (opcional)

Para una mejor compatibilidad con TFDS, puede organizar sus datos como <data_dir>/<dataset_name>[/<dataset_config>]/<dataset_version> . Por ejemplo:

data_dir/
    dataset0/
        1.0.0/
        1.0.1/
    dataset1/
        config0/
            2.0.0/
        config1/
            2.0.0/

Esto hará que sus conjuntos de datos sean compatibles con la API tfds.load / tfds.builder , simplemente proporcionando data_dir/ :

ds0 = tfds.load('dataset0', data_dir='data_dir/')
ds1 = tfds.load('dataset1/config0', data_dir='data_dir/')