Cargar tfrecord externo con TFDS

Si tiene un protocolo 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 tus archivos .tfrecord , sólo necesitas:

  • Siga la convención de nomenclatura 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 proporciona flexibilidad para utilizar 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 nomenclatura de archivos predeterminado de TFDS es: {DATASET}-{SPLIT}.{FILEFORMAT}-{SHARD_X_OF_Y} . Para MNIST, esto significa que los nombres de los archivos tienen el siguiente aspecto:

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

Agregar metadatos

Proporcionar la estructura de características.

Para que TFDS pueda decodificar el protocolo 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 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),
}

La especificación de las funciones permite a TFDS decodificar automáticamente imágenes, videos,... Como cualquier otro conjunto de datos TFDS, los metadatos de las funciones (por ejemplo, nombres de etiquetas,...) estarán expuestos al usuario (por ejemplo info.features['label'].names ).

Si controlas el oleoducto 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 desde 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.

De manera similar, existe un feature.deserialize_example para decodificar el proto ( ejemplo )

Si no controlas el gasoducto de generación

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

Obtenga estadísticas sobre divisiones

TFDS requiere conocer la cantidad exacta de ejemplos dentro de cada fragmento. Esto es necesario para funciones como len(ds) o la API subplit : 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 usando el script compute_split_info.py (o en su propio script con tfds.folder_dataset.compute_split_info ). Lanzará una canalización de rayos 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 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 su directorio de 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 usando tfds.builder_from_directory , que devuelve un tfds.core.DatasetBuilder con la API 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 múltiples 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 separado y usted 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, use tfds.builder_from_directories , que devuelve un tfds.core.DatasetBuilder con la API 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/')