FeatureConnector

L'API tfds.features.FeatureConnector :

  • Definisce la struttura, le forme, i dtype del tf.data.Dataset finale
  • Serializzazione astratta su/da disco.
  • Esporre metadati aggiuntivi (ad esempio nomi di etichette, frequenza di campionamento audio,...)

Panoramica

tfds.features.FeatureConnector definisce la struttura delle caratteristiche del set di dati (in tfds.core.DatasetInfo ):

tfds.core.DatasetInfo(
    features=tfds.features.FeaturesDict({
        'image': tfds.features.Image(shape=(28, 28, 1), doc='Grayscale image'),
        'label': tfds.features.ClassLabel(
            names=['no', 'yes'],
            doc=tfds.features.Documentation(
                desc='Whether this is a picture of a cat',
                value_range='yes or no'
            ),
        ),
        'metadata': {
            'id': tf.int64,
            'timestamp': tfds.features.Scalar(
                tf.int64,
                doc='Timestamp when this picture was taken as seconds since epoch'),
            'language': tf.string,
        },
    }),
)

Le funzionalità possono essere documentate utilizzando solo una descrizione testuale ( doc='description' ) o utilizzando direttamente tfds.features.Documentation per fornire una descrizione più dettagliata della funzionalità.

Le caratteristiche possono essere:

  • Valori scalari: tf.bool , tf.string , tf.float32 ,... Quando si desidera documentare la funzionalità, è anche possibile utilizzare tfds.features.Scalar(tf.int64, doc='description') .
  • tfds.features.Audio , tfds.features.Video ,... (vedi l'elenco delle funzionalità disponibili)
  • dict di funzionalità nidificate: {'metadata': {'image': Image(), 'description': tf.string} } ,...
  • tfds.features.Sequence nidificate : Sequence({'image': ..., 'id': ...}) , Sequence(Sequence(tf.int64)) ,...

Durante la generazione, gli esempi verranno automaticamente serializzati da FeatureConnector.encode_example in un formato adatto al disco (attualmente buffer del protocollo tf.train.Example ):

yield {
    'image': '/path/to/img0.png',  # `np.array`, file bytes,... also accepted
    'label': 'yes',  # int (0-num_classes) also accepted
    'metadata': {
        'id': 43,
        'language': 'en',
    },
}

Durante la lettura del set di dati (ad esempio con tfds.load ), i dati vengono decodificati automaticamente con FeatureConnector.decode_example . Il tf.data.Dataset restituito corrisponderà alla struttura dict definita in tfds.core.DatasetInfo :

ds = tfds.load(...)
ds.element_spec == {
    'image': tf.TensorSpec(shape=(28, 28, 1), tf.uint8),
    'label': tf.TensorSpec(shape=(), tf.int64),
    'metadata': {
        'id': tf.TensorSpec(shape=(), tf.int64),
        'language': tf.TensorSpec(shape=(), tf.string),
    },
}

Serializza/deserializza in proto

TFDS espone un'API di basso livello per serializzare/deserializzare gli esempi nel proto tf.train.Example .

Per serializzare dict[np.ndarray | Path | str | ...] in proto bytes , utilizzare features.serialize_example :

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

Per deserializzare in proto bytes su tf.Tensor , utilizzare features.deserialize_example :

ds = tf.data.TFRecordDataset('path/to/file.tfrecord')
ds = ds.map(features.deserialize_example)

Accedi ai metadati

Consulta il documento introduttivo per accedere ai metadati delle funzionalità (nomi delle etichette, forma, dtype,...). Esempio:

ds, info = tfds.load(..., with_info=True)

info.features['label'].names  # ['cat', 'dog', ...]
info.features['label'].str2int('cat')  # 0

Crea il tuo tfds.features.FeatureConnector

Se ritieni che manchi una funzionalità tra quelle disponibili , apri un nuovo problema .

Per creare il tuo connettore di funzionalità, devi ereditare da tfds.features.FeatureConnector e implementare i metodi astratti.

  • Se la tua funzionalità è un singolo valore tensore, è meglio ereditare da tfds.features.Tensor e utilizzare super() quando necessario. Vedi il codice sorgente tfds.features.BBoxFeature per un esempio.
  • Se la tua funzionalità è un contenitore di più tensori, è meglio ereditare da tfds.features.FeaturesDict e utilizzare super() per codificare automaticamente i sottoconnettori.

L'oggetto tfds.features.FeatureConnector astrae il modo in cui la funzionalità è codificata sul disco da come viene presentata all'utente. Di seguito è riportato un diagramma che mostra i livelli di astrazione del set di dati e la trasformazione dai file del set di dati grezzi all'oggetto tf.data.Dataset .

Livelli di astrazione di DatasetBuilder

Per creare il tuo connettore di funzionalità, crea la sottoclasse tfds.features.FeatureConnector e implementa i metodi astratti:

  • encode_example(data) : Definisce come codificare i dati forniti nel generatore _generate_examples() in dati compatibili con tf.train.Example . Può restituire un singolo valore o un dict di valori.
  • decode_example(data) : definisce come decodificare i dati dal tensore letto da tf.train.Example nel tensore utente restituito da tf.data.Dataset .
  • get_tensor_info() : indica la forma/dtype dei tensori restituiti da tf.data.Dataset . Può essere facoltativo se si eredita da un altro tfds.features .
  • (facoltativo) get_serialized_info() : se le informazioni restituite da get_tensor_info() sono diverse da come i dati vengono effettivamente scritti su disco, è necessario sovrascrivere get_serialized_info() per corrispondere alle specifiche di tf.train.Example
  • to_json_content / from_json_content : è necessario per consentire il caricamento del set di dati senza il codice sorgente originale. Vedi la funzione Audio per un esempio.

Per ulteriori informazioni, dai un'occhiata alla documentazione di tfds.features.FeatureConnector . È anche meglio guardare esempi reali .