Segui questa guida per creare un nuovo set di dati (in TFDS o nel tuo repository personale).
Consulta il nostro elenco di dataset per verificare se il dataset che desideri è già presente.
In breve
Il modo più semplice per scrivere un nuovo dataset è utilizzare la CLI di 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/`
Per utilizzare il nuovo dataset con tfds.load('my_dataset') :
-
tfds.loadrileverà e caricherà automaticamente il dataset generato in~/tensorflow_datasets/my_dataset/(ad esempio datfds build). - In alternativa, puoi
import my.project.datasets.my_datasetper registrare il tuo dataset:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Panoramica
I dataset sono distribuiti in svariati formati e in svariate posizioni, e non sempre vengono archiviati in un formato pronto per essere utilizzato in una pipeline di machine learning. Ecco che entra in gioco TFDS.
TFDS elabora questi set di dati convertendoli in un formato standard (dati esterni -> file serializzati), che possono poi essere caricati come pipeline di machine learning (file serializzati -> tf.data.Dataset ). La serializzazione viene eseguita una sola volta. Gli accessi successivi leggeranno direttamente da questi file pre-elaborati.
La maggior parte della preelaborazione viene eseguita automaticamente. Ogni dataset implementa una sottoclasse di tfds.core.DatasetBuilder , che specifica:
- Da dove provengono i dati (ovvero i relativi URL);
- Che aspetto ha il dataset (ovvero le sue caratteristiche);
- Come suddividere i dati (ad esempio,
TRAINeTEST); - e i singoli esempi presenti nel dataset.
Scrivi il tuo set di dati
Modello predefinito: tfds new
Utilizza TFDS CLI per generare i file Python modello necessari.
cd path/to/project/datasets/ # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset
Questo comando genererà una nuova cartella my_dataset/ con la seguente struttura:
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).
Cerca TODO(my_dataset) qui e modifica di conseguenza.
Esempio di set di dati
Tutti i dataset sono sottoclassi implementate di tfds.core.DatasetBuilder , che si occupa della maggior parte del codice ripetitivo. Supporta:
- Set di dati di piccole/medie dimensioni che possono essere generati su una singola macchina (questo tutorial).
- Set di dati molto grandi che richiedono la generazione distribuita (utilizzando Apache Beam , vedi la nostra guida sui set di dati di grandi dimensioni ).
Ecco un esempio minimo di generatore di dataset basato su 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',
}
Si noti che, per alcuni formati di dati specifici, forniamo strumenti di creazione di dataset pronti all'uso per gestire la maggior parte dell'elaborazione dei dati.
Vediamo nel dettaglio i 3 metodi astratti per sovrascrivere.
_info : metadati del dataset
_info restituisce tfds.core.DatasetInfo contenente i metadati del dataset .
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 maggior parte dei campi dovrebbe essere autoesplicativa. Alcune precisazioni:
-
features: specifica la struttura del dataset, la forma, ecc. Supporta tipi di dati complessi (audio, video, sequenze annidate, ecc.). Per ulteriori informazioni, consulta le funzionalità disponibili o la guida al connettore delle funzionalità . -
disable_shuffling: vedere la sezione Mantenere l'ordine del dataset .
Scrittura del file BibText CITATIONS.bib :
- Consulta il sito web del dataset per le istruzioni di citazione (utilizza il formato BibTex).
- Per gli articoli su arXiv : individua l'articolo e clicca sul link
BibTexta destra. - Trova l'articolo su Google Scholar , fai clic sulle virgolette doppie sotto il titolo e nella finestra a comparsa fai clic su
BibTeX. - Se non è presente un documento cartaceo associato (ad esempio, esiste solo un sito web), è possibile utilizzare l' editor online di BibTeX per creare una voce BibTeX personalizzata (il menu a tendina include la tipologia di voce
Online).
Aggiornamento del file TAGS.txt :
- Tutti i tag consentiti sono precompilati nel file generato.
- Rimuovi tutti i tag che non si applicano al dataset.
- I tag validi sono elencati nel file tensorflow_datasets/core/valid_tags.txt .
- Per aggiungere un tag a quell'elenco, invia una pull request.
Mantenere l'ordine dei dataset
Per impostazione predefinita, i record dei dataset vengono mescolati durante il salvataggio per rendere più uniforme la distribuzione delle classi all'interno del dataset, poiché spesso i record appartenenti alla stessa classe sono contigui. Per specificare che il dataset deve essere ordinato in base alla chiave generata da _generate_examples , il campo disable_shuffling deve essere impostato su True . Per impostazione predefinita è impostato su False .
def _info(self):
return self.dataset_info_from_configs(
# [...]
disable_shuffling=True,
# [...]
)
Tieni presente che la disattivazione dello shuffling ha un impatto sulle prestazioni, poiché i frammenti non possono più essere letti in parallelo.
_split_generators : scarica e divide i dati
Download ed estrazione dei dati sorgente
La maggior parte dei dataset richiede il download dei dati dal web. Questo viene fatto utilizzando l'argomento di input tfds.download.DownloadManager di _split_generators . dl_manager ha i seguenti metodi:
-
download: supportahttp(s)://,ftp(s):// -
extract: attualmente supporta file.zip,.gze.tar. -
download_and_extract: Equivalente adl_manager.extract(dl_manager.download(urls))
Tutti questi metodi restituiscono tfds.core.Path (alias per epath.Path ), che sono oggetti simili a pathlib.Path .
Questi metodi supportano strutture annidate arbitrarie ( list , dict ), come ad esempio:
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/'),
}
Download ed estrazione manuali
Alcuni dati non possono essere scaricati automaticamente (ad esempio, richiedono l'accesso tramite login); in questo caso, l'utente dovrà scaricare manualmente i dati sorgente e posizionarli nella manual_dir/ (il percorso predefinito è ~/tensorflow_datasets/downloads/manual/ ).
È quindi possibile accedere ai file tramite 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 posizione manual_dir può essere personalizzata con tfds build --manual_dir= oppure utilizzando tfds.download.DownloadConfig .
Leggi l'archivio direttamente
dl_manager.iter_archive legge gli archivi in sequenza senza estrarli. Questo può consentire di risparmiare spazio di archiviazione e migliorare le prestazioni su alcuni file system.
for filename, fobj in dl_manager.iter_archive('path/to/archive.zip'):
...
fobj ha gli stessi metodi di with open('rb') as fobj: (ad esempio fobj.read() )
Specificare le suddivisioni del set di dati
Se il dataset include suddivisioni predefinite (ad esempio, MNIST ha suddivisioni train e test ), mantenetele. Altrimenti, specificate solo una singola suddivisione " all ". Gli utenti possono creare dinamicamente le proprie sotto-suddivisioni con l' API subsplit (ad esempio split='train[80%:]' ). Si noti che è possibile utilizzare qualsiasi stringa alfabetica come nome della suddivisione, ad eccezione del già citato 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 : Generatore di esempi
_generate_examples genera gli esempi per ogni suddivisione a partire dai dati di origine.
Questo metodo in genere legge gli artefatti del dataset di origine (ad esempio un file CSV) e restituisce tuple (key, feature_dict) :
-
key: identificatore dell'esempio. Utilizzato per mescolare in modo deterministico gli esempi tramitehash(key)o per ordinare per chiave quando la mescolatura è disabilitata (vedere la sezione Mantenere l'ordine del dataset ). Dovrebbe essere:- unico : se due esempi utilizzano la stessa chiave, verrà generata un'eccezione.
- deterministico : non dovrebbe dipendere dall'ordine di
download_dir,os.path.listdir,... La generazione dei dati due volte dovrebbe produrre la stessa chiave. - comparabile : se la randomizzazione è disabilitata, la chiave verrà utilizzata per ordinare il dataset.
-
feature_dict: Undictcontenente i valori di esempio.- La struttura deve corrispondere alla struttura
features=definita intfds.core.DatasetInfo. - I tipi di dati complessi (immagini, video, audio, ecc.) verranno codificati automaticamente.
- Ogni funzionalità spesso accetta più tipi di input (ad esempio, i video accettano
/path/to/vid.mp4,np.array(shape=(l, h, w, c)),List[paths],List[np.array(shape=(h, w, c)],List[img_bytes], ...) - Consulta la guida ai connettori delle funzionalità per ulteriori informazioni.
- La struttura deve corrispondere alla struttura
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'],
}
Accesso ai file e tf.io.gfile
Per supportare i sistemi di archiviazione cloud, evitare l'utilizzo delle operazioni di I/O integrate di Python.
Invece, dl_manager restituisce oggetti simili a pathlib direttamente compatibili con l'archiviazione di 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())
In alternativa, per le operazioni sui file, utilizzare l'API tf.io.gfile anziché quella integrata:
-
open->tf.io.gfile.GFile -
os.rename->tf.io.gfile.rename - ...
Pathlib dovrebbe essere preferito a tf.io.gfile (vedi rational .
Dipendenze aggiuntive
Alcuni dataset richiedono dipendenze Python aggiuntive solo durante la fase di generazione. Ad esempio, il dataset SVHN utilizza scipy per caricare alcuni dati.
Se stai aggiungendo un dataset al repository TFDS, utilizza tfds.core.lazy_imports per mantenere il pacchetto tensorflow-datasets di dimensioni ridotte. Gli utenti installeranno le dipendenze aggiuntive solo se necessario.
Per utilizzare lazy_imports :
- Aggiungi una voce per il tuo dataset in
DATASET_EXTRASnelsetup.py. In questo modo, gli utenti potranno, ad esempio, eseguirepip install 'tensorflow-datasets[svhn]'per installare le dipendenze aggiuntive. - Aggiungi una voce per la tua importazione a
LazyImportere aLazyImportsTest. - Utilizza
tfds.core.lazy_importsper accedere alla dipendenza (ad esempio,tfds.core.lazy_imports.scipy) nel tuoDatasetBuilder.
Dati corrotti
Alcuni dataset non sono perfettamente puliti e contengono dati corrotti (ad esempio, le immagini sono in file JPEG ma alcune non sono JPEG validi). Questi esempi dovrebbero essere ignorati, ma è necessario aggiungere una nota nella descrizione del dataset indicando quanti esempi sono stati scartati e perché.
Configurazione/varianti del dataset (tfds.core.BuilderConfig)
Alcuni dataset possono avere più varianti, ovvero diverse opzioni per la preelaborazione e la scrittura dei dati su disco. Ad esempio, cycle_gan ha una configurazione per ogni coppia di oggetti ( cycle_gan/horse2zebra , cycle_gan/monet2photo , ...).
Questo viene fatto tramite tfds.core.BuilderConfig s:
Definisci il tuo oggetto di configurazione come una sottoclasse di
tfds.core.BuilderConfig. Ad esempio,MyDatasetConfig.@dataclasses.dataclass class MyDatasetConfig(tfds.core.BuilderConfig): img_size: Tuple[int, int] = (0, 0)Definisci il membro di classe
BUILDER_CONFIGS = []inMyDatasetche elenca leMyDatasetConfigesposte dal dataset.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-argsUtilizza
self.builder_configinMyDatasetper configurare la generazione dei dati (ad esempio,shape=self.builder_config.img_size). Ciò potrebbe includere l'impostazione di valori diversi in_info()o la modifica dell'accesso ai dati scaricati.
Note:
- Ogni configurazione ha un nome univoco. Il nome completo di una configurazione è
dataset_name/config_name(ad esempiococo/2017). - Se non specificato, verrà utilizzata la prima configurazione in
BUILDER_CONFIGS(ad esempiotfds.load('c4')predefinito suc4/en).
Vedi anli per un esempio di dataset che utilizza BuilderConfig .
Versione
La versione può riferirsi a due significati diversi:
- La versione originale dei dati "esterna": ad esempio COCO v2019, v2017,...
- La versione "interna" del codice TFDS: ad esempio, rinominare una funzionalità in
tfds.features.FeaturesDict, correggere un bug in_generate_examples
Per aggiornare un set di dati:
- Per l'aggiornamento dei dati "esterni": più utenti potrebbero voler accedere contemporaneamente a un anno/versione specifici. Ciò si ottiene utilizzando un
tfds.core.BuilderConfigper ogni versione (ad esempiococo/2017,coco/2019) o una classe per ogni versione (ad esempioVoc2007,Voc2012). - Per gli aggiornamenti del codice "interni": gli utenti scaricano solo la versione più recente. Qualsiasi aggiornamento del codice dovrebbe incrementare l'attributo di classe
VERSION(ad esempio da1.0.0aVERSION = tfds.core.Version('2.0.0')) seguendo la versione semantica .
Aggiungi l'importazione per la registrazione
Non dimenticare di importare il modulo dataset nel tuo progetto __init__ per essere registrato automaticamente in tfds.load e tfds.builder .
import my_project.datasets.my_dataset # Register MyDataset
ds = tfds.load('my_dataset') # MyDataset available
Ad esempio, se stai contribuendo a tensorflow/datasets , aggiungi l'importazione del modulo al file __init__.py della sua sottocartella (ad esempio image/__init__.py ).
Verifica la presenza di problemi comuni durante l'implementazione.
Si prega di verificare la presenza di problemi comuni durante l'implementazione .
Verifica il tuo set di dati
Scarica e prepara: tfds build
Per generare il dataset, esegui tfds build dalla directory my_dataset/ :
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Alcuni flag utili per lo sviluppo:
-
--pdb: Attiva la modalità di debug se viene generata un'eccezione. -
--overwrite: Elimina i file esistenti se il dataset è già stato generato. -
--max_examples_per_split: Genera solo i primi X esempi (valore predefinito: 1), anziché l'intero set di dati. -
--register_checksums: Registra i checksum degli URL scaricati. Da utilizzare solo in fase di sviluppo.
Consultare la documentazione della CLI per l'elenco completo dei flag.
Codici di controllo
Si consiglia di registrare i checksum dei propri dataset per garantire il determinismo, facilitare la documentazione, ecc. Questo si fa generando il dataset con l'opzione --register_checksums (vedere la sezione precedente).
Se pubblichi i tuoi dataset tramite PyPI, non dimenticare di esportare i file checksums.tsv (ad esempio nella package_data del tuo setup.py ).
Esegui un test unitario sul tuo set di dati.
tfds.testing.DatasetBuilderTestCase è un TestCase di base per testare a fondo un dataset. Utilizza "dati fittizi" come dati di test che replicano la struttura del dataset di origine.
- I dati di test devono essere inseriti nella directory
my_dataset/dummy_data/e devono replicare gli artefatti del dataset di origine così come sono stati scaricati ed estratti. Possono essere creati manualmente o automaticamente tramite uno script ( esempio di script ). - Assicurati di utilizzare dati diversi nelle suddivisioni del set di dati di test, poiché il test fallirà se le suddivisioni del set di dati si sovrappongono.
- I dati di test non devono contenere materiale protetto da copyright . In caso di dubbio, non creare i dati utilizzando materiale proveniente dal dataset originale.
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()
Eseguire il seguente comando per testare il set di dati.
python my_dataset_test.py
inviaci un feedback
Ci impegniamo costantemente a migliorare il flusso di lavoro per la creazione dei dataset, ma possiamo farlo solo se siamo a conoscenza dei problemi. Quali problemi o errori hai riscontrato durante la creazione del dataset? C'è stata qualche fase che ti ha creato confusione o che non ha funzionato al primo tentativo?
Vi preghiamo di condividere il vostro feedback su GitHub .