Se você possui um proto tf.train.Example
(dentro de .tfrecord
, .riegeli
,...), que foi gerado por ferramentas de terceiros, que você gostaria de carregar diretamente com a API tfds, então esta página é para você.
Para carregar seus arquivos .tfrecord
, você só precisa:
- Siga a convenção de nomenclatura TFDS.
- Adicione arquivos de metadados (
dataset_info.json
,features.json
) junto com seus arquivos tfrecord.
Limitações:
-
tf.train.SequenceExample
não é compatível, apenastf.train.Example
. - Você precisa ser capaz de expressar
tf.train.Example
em termos detfds.features
(veja a seção abaixo).
Convenção de nomenclatura de arquivos
TFDS suporta a definição de um modelo para nomes de arquivos, o que fornece flexibilidade para usar diferentes esquemas de nomenclatura de arquivos. O modelo é representado por um tfds.core.ShardedFileTemplate
e suporta as seguintes variáveis: {DATASET}
, {SPLIT}
, {FILEFORMAT}
, {SHARD_INDEX}
, {NUM_SHARDS}
e {SHARD_X_OF_Y}
. Por exemplo, o esquema de nomenclatura de arquivo padrão do TFDS é: {DATASET}-{SPLIT}.{FILEFORMAT}-{SHARD_X_OF_Y}
. Para MNIST, isso significa que os nomes dos arquivos têm a seguinte aparência:
-
mnist-test.tfrecord-00000-of-00001
-
mnist-train.tfrecord-00000-of-00001
Adicionar metadados
Forneça a estrutura de recursos
Para que o TFDS seja capaz de decodificar o proto tf.train.Example
, você precisa fornecer a estrutura tfds.features
que corresponda às suas especificações. Por exemplo:
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 às seguintes especificações 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 os recursos permite que o TFDS decodifique automaticamente imagens, vídeos,... Como qualquer outro conjunto de dados TFDS, os metadados dos recursos (por exemplo, nomes de rótulos,...) serão expostos ao usuário (por exemplo, info.features['label'].names
).
Se você controlar o pipeline de geração
Se você gerar conjuntos de dados fora do TFDS, mas ainda controlar o pipeline de geração, poderá usar tfds.features.FeatureConnector.serialize_example
para codificar seus dados de dict[np.ndarray]
para 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)
Isso garantirá a compatibilidade dos recursos com o TFDS.
Da mesma forma, existe um feature.deserialize_example
para decodificar o proto ( exemplo )
Se você não controlar o pipeline de geração
Se você quiser ver como tfds.features
são representados em um tf.train.Example
, você pode examinar isso no colab:
- Para traduzir
tfds.features
na estrutura legível por humanos dotf.train.Example
, você pode chamarfeatures.get_serialized_info()
. - Para obter a especificação exata
FixedLenFeature
,... passada paratf.io.parse_single_example
, você pode usarspec = features.tf_example_spec
Obtenha estatísticas sobre divisões
O TFDS exige saber o número exato de exemplos dentro de cada fragmento. Isso é necessário para recursos como len(ds)
ou a API subplit : split='train[75%:]'
.
Se você tiver essas informações, poderá criar explicitamente uma lista de
tfds.core.SplitInfo
e pular para a próxima seção: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', ...), ]
Se você não souber essas informações, poderá calculá-las usando o script
compute_split_info.py
(ou em seu próprio script comtfds.folder_dataset.compute_split_info
). Ele iniciará um pipeline de feixe que lerá todos os fragmentos em um determinado diretório e calculará as informações.
Adicionar arquivos de metadados
Para adicionar automaticamente os arquivos de metadados adequados ao seu conjunto de dados, 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.""",
)
Depois que a função for chamada uma vez em seu diretório de conjunto de dados, os arquivos de metadados ( dataset_info.json
,...) foram adicionados e seus conjuntos de dados estão prontos para serem carregados com TFDS (veja a próxima seção).
Carregar conjunto de dados com TFDS
Diretamente da pasta
Depois que os metadados forem gerados, os conjuntos de dados podem ser carregados usando tfds.builder_from_directory
que retorna um tfds.core.DatasetBuilder
com a API TFDS padrão (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:
...
Diretamente de várias pastas
Também é possível carregar dados de várias pastas. Isso pode acontecer, por exemplo, no aprendizado por reforço, quando vários agentes estão gerando, cada um, um conjunto de dados separado e você deseja carregar todos eles juntos. Outros casos de uso são quando um novo conjunto de dados é produzido regularmente, por exemplo, um novo conjunto de dados por dia, e você deseja carregar dados de um intervalo de datas.
Para carregar dados de várias pastas, use tfds.builder_from_directories
, que retorna um tfds.core.DatasetBuilder
com a API TFDS padrão (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:
...
Estrutura de pastas (opcional)
Para melhor compatibilidade com TFDS, você pode organizar seus dados como <data_dir>/<dataset_name>[/<dataset_config>]/<dataset_version>
. Por exemplo:
data_dir/
dataset0/
1.0.0/
1.0.1/
dataset1/
config0/
2.0.0/
config1/
2.0.0/
Isso tornará seus conjuntos de dados compatíveis com a API tfds.load
/ tfds.builder
, simplesmente fornecendo data_dir/
:
ds0 = tfds.load('dataset0', data_dir='data_dir/')
ds1 = tfds.load('dataset1/config0', data_dir='data_dir/')