Segui questa guida per creare un nuovo set di dati (in TFDS o nel tuo repository).
Controlla il nostro elenco di set di dati per vedere se il set di dati che desideri è già presente.
TL;DR
Il modo più semplice per scrivere un nuovo set di dati è utilizzare la CLI 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 set di dati con tfds.load('my_dataset')
:
-
tfds.load
rileverà e caricherà automaticamente il set di dati generato in~/tensorflow_datasets/my_dataset/
(ad esempio datfds build
). - In alternativa, puoi
import my.project.datasets.my_dataset
per registrare il tuo set di dati:
import my.project.datasets.my_dataset # Register `my_dataset`
ds = tfds.load('my_dataset') # `my_dataset` registered
Panoramica
I set di dati sono distribuiti in tutti i tipi di formati e in tutti i tipi di luoghi e non sono sempre archiviati in un formato pronto per essere inserito in una pipeline di machine learning. Inserisci TFDS.
TFDS elabora questi set di dati in un formato standard (dati esterni -> file serializzati), che può quindi essere caricato come pipeline di machine learning (file serializzati -> tf.data.Dataset
). La serializzazione viene eseguita una sola volta. L'accesso successivo leggerà direttamente da quei file pre-elaborati.
La maggior parte della preelaborazione viene eseguita automaticamente. Ogni set di dati implementa una sottoclasse di tfds.core.DatasetBuilder
, che specifica:
- Da dove provengono i dati (ovvero i loro URL);
- Come si presenta il set di dati (ovvero le sue caratteristiche);
- Come devono essere suddivisi i dati (es.
TRAIN
eTEST
); - e i singoli esempi nel set di dati.
Scrivi il tuo set di dati
Modello predefinito: tfds new
Utilizza la CLI di TFDS per generare i file Python modello richiesti.
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 modificalo di conseguenza.
Esempio di set di dati
Tutti i set di dati sono sottoclassi implementate di tfds.core.DatasetBuilder
, che si occupa della maggior parte dei boilerplate. 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 , consulta la nostra guida sui set di dati di grandi dimensioni )
Ecco un esempio minimo di un generatore di set di dati 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',
}
Tieni presente che, per alcuni formati di dati specifici, forniamo generatori di set di dati pronti all'uso per occuparsi della maggior parte dell'elaborazione dei dati.
Vediamo nel dettaglio i 3 metodi astratti per sovrascrivere.
_info
: metadati del set di dati
_info
restituisce tfds.core.DatasetInfo
contenente i metadati del set di dati .
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 set di dati, la forma,... Supporta tipi di dati complessi (audio, video, sequenze nidificate,...). Per ulteriori informazioni, consulta le funzionalità disponibili o la guida al connettore delle funzionalità . -
disable_shuffling
: vedere la sezione Mantenere l'ordine del set di dati .
Scrittura del file BibText
CITATIONS.bib
:
- Cerca nel sito Web del set di dati istruzioni per la citazione (utilizzalo in formato BibTex).
- Per i documenti arXiv : trova il documento e fai clic sul collegamento
BibText
sul lato destro. - Trova l'articolo su Google Scholar e fai clic sulle virgolette doppie sotto il titolo e nel popup fai clic su
BibTeX
. - Se non è presente alcun documento associato (ad esempio, c'è solo un sito Web), puoi utilizzare l' editor BibTeX Online per creare una voce BibTeX personalizzata (il menu a discesa ha un tipo 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 set di dati.
- I tag validi sono elencati in tensorflow_datasets/core/valid_tags.txt .
- Per aggiungere un tag a quell'elenco, invia un PR.
Mantieni l'ordine del set di dati
Per impostazione predefinita, i record dei dataset vengono mescolati quando vengono archiviati per rendere la distribuzione delle classi più uniforme nel dataset, poiché spesso i record appartenenti alla stessa classe sono contigui. Per specificare che il set di dati deve essere ordinato in base alla chiave generata fornita 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 spostamento casuale ha un impatto sulle prestazioni poiché gli shard non possono più essere letti in parallelo.
_split_generators
: scarica e divide i dati
Download ed estrazione dei dati di origine
La maggior parte dei set di dati deve scaricare 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
,.gz
e.tar
. -
download_and_extract
: uguale 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 nidificate arbitrarie ( list
, dict
), come:
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 manuale
Alcuni dati non possono essere scaricati automaticamente (ad esempio richiedono un accesso), in questo caso l'utente scaricherà manualmente i dati di origine e li inserirà in manual_dir/
(il valore 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=
o utilizzando tfds.download.DownloadConfig
.
Leggi direttamente l'archivio
dl_manager.iter_archive
legge un archivio in modo sequenziale senza estrarlo. Ciò può 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 with open('rb') as fobj:
(ad esempio fobj.read()
)
Specifica delle suddivisioni del set di dati
Se il set di dati viene fornito con suddivisioni predefinite (ad esempio MNIST
ha suddivisioni train
e test
), mantieni quelle. Altrimenti, specificare solo una singola suddivisione all
. Gli utenti possono creare dinamicamente i propri subsplit con l' API subsplit (ad esempio split='train[80%:]'
). Si noti che qualsiasi stringa alfabetica può essere utilizzata come nome diviso, 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 dai dati di origine.
Questo metodo in genere legge gli artefatti del set di dati di origine (ad esempio un file CSV) e produce tuple (key, feature_dict)
:
-
key
: identificatore di esempio. Utilizzato per mescolare deterministicamente gli esempi utilizzandohash(key)
o per ordinare per chiave quando la mescolanza è disabilitata (vedere la sezione Mantenere l'ordine del set di dati ). Dovrebbe essere:- unique : se due esempi utilizzano la stessa chiave, verrà sollevata un'eccezione.
- deterministico : non dovrebbe dipendere da
download_dir
,os.path.listdir
order,... La generazione dei dati due volte dovrebbe produrre la stessa chiave. - comparabile : se la riproduzione casuale è disabilitata, la chiave verrà utilizzata per ordinare il set di dati.
-
feature_dict
: undict
contenente i valori di esempio.- La struttura deve corrispondere alla struttura
features=
definita intfds.core.DatasetInfo
. - I tipi di dati complessi (immagine, video, audio,...) verranno codificati automaticamente.
- Ciascuna funzionalità spesso accetta più tipi di input (ad esempio video accetta
/path/to/vid.mp4
,np.array(shape=(l, h, w, c))
,List[paths]
,List[np.array(shape=(h, w, c)]
,List[img_bytes]
,...) - Per ulteriori informazioni, consultare la guida al connettore delle funzionalità .
- 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'uso delle operazioni di I/O integrate in Python.
Invece, dl_manager
restituisce oggetti simili a pathlib direttamente compatibili con l'archiviazione 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, utilizza l'API tf.io.gfile
anziché quella integrata per le operazioni sui file:
-
open
->tf.io.gfile.GFile
-
os.rename
->tf.io.gfile.rename
- ...
Pathlib dovrebbe essere preferito a tf.io.gfile
(vedere razionale .
Dipendenze aggiuntive
Alcuni set di dati richiedono dipendenze Python aggiuntive solo durante la generazione. Ad esempio, il set di dati SVHN utilizza scipy
per caricare alcuni dati.
Se stai aggiungendo il set di dati al repository TFDS, utilizza tfds.core.lazy_imports
per mantenere piccolo il pacchetto tensorflow-datasets
. Gli utenti installeranno dipendenze aggiuntive solo se necessario.
Per utilizzare lazy_imports
:
- Aggiungi una voce per il tuo set di dati in
DATASET_EXTRAS
insetup.py
. Ciò fa sì che gli utenti possano eseguire, ad esempio,pip install 'tensorflow-datasets[svhn]'
per installare le dipendenze aggiuntive. - Aggiungi una voce per l'importazione in
LazyImporter
e inLazyImportsTest
. - Utilizza
tfds.core.lazy_imports
per accedere alla dipendenza (ad esempio,tfds.core.lazy_imports.scipy
) nel tuoDatasetBuilder
.
Dati danneggiati
Alcuni set di dati non sono perfettamente puliti e contengono dati corrotti (ad esempio, le immagini sono in file JPEG ma alcune sono JPEG non valide). Questi esempi dovrebbero essere saltati, ma lascia una nota nella descrizione del set di dati quanti esempi sono stati eliminati e perché.
Configurazione/varianti del set di dati (tfds.core.BuilderConfig)
Alcuni set di dati possono avere più varianti o opzioni su come i dati vengono preelaborati e scritti su disco. Ad esempio, cycle_gan ha una configurazione per 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)
Definire il membro della classe
BUILDER_CONFIGS = []
inMyDataset
che elenca iMyDatasetConfig
esposti dal set di dati.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-args
Utilizzare
self.builder_config
inMyDataset
per configurare la generazione dei dati (ad esempioshape=self.builder_config.img_size
). Ciò potrebbe includere l'impostazione di valori diversi in_info()
o la modifica dell'accesso ai dati di download.
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')
default toc4/en
)
Vedi anli
per un esempio di un set di dati che utilizza BuilderConfig
s.
Versione
La versione può avere due significati diversi:
- La versione dei dati originali "esterni": ad esempio COCO v2019, v2017,...
- La versione "interna" del codice TFDS: ad esempio rinomina una funzionalità in
tfds.features.FeaturesDict
, correggi 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 specifica. Questo viene fatto utilizzando un
tfds.core.BuilderConfig
per versione (ad esempiococo/2017
,coco/2019
) o una classe per versione (ad esempioVoc2007
,Voc2012
). - Per l'aggiornamento del codice "interno": gli utenti scaricano solo la versione più recente. Qualsiasi aggiornamento del codice dovrebbe aumentare l'attributo della classe
VERSION
(ad esempio da1.0.0
aVERSION = tfds.core.Version('2.0.0')
) seguendo il controllo delle versioni semantico .
Aggiungi un'importazione per la registrazione
Non dimenticare di importare il modulo del set di dati nel tuo progetto __init__
per essere registrato automaticamente in tfds.load
, 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 __init__.py
della sua sottodirectory (ad esempio image/__init__.py
.
Verificare la presenza di trucchi di implementazione comuni
Si prega di verificare i trucchi di implementazione comuni .
Metti alla prova il tuo set di dati
Scarica e prepara: tfds build
Per generare il set di dati, esegui tfds build
dalla directory my_dataset/
:
cd path/to/datasets/my_dataset/
tfds build --register_checksums
Alcuni flag utili per lo sviluppo:
-
--pdb
: entra in modalità debug se viene sollevata un'eccezione. -
--overwrite
: elimina i file esistenti se il set di dati è già stato generato. -
--max_examples_per_split
: genera solo i primi X esempi (il valore predefinito è 1), anziché il set di dati completo. -
--register_checksums
: registra i checksum degli URL scaricati. Dovrebbe essere utilizzato solo durante lo sviluppo.
Consulta la documentazione della CLI per l'elenco completo dei flag.
Checksum
Si consiglia di registrare i checksum dei propri set di dati per garantire il determinismo, aiutare con la documentazione,... Questo viene fatto generando il set di dati con --register_checksums
(vedere la sezione precedente).
Se rilasci i tuoi set di dati tramite PyPI, non dimenticare di esportare i file checksums.tsv
(ad esempio nel package_data
del tuo setup.py
).
Esegui test unitari del tuo set di dati
tfds.testing.DatasetBuilderTestCase
è un TestCase
di base per esercitare completamente un set di dati. Utilizza "dati fittizi" come dati di test che imitano la struttura del set di dati di origine.
- I dati di test devono essere inseriti nella directory
my_dataset/dummy_data/
e devono imitare gli artefatti del set di dati di origine scaricati ed estratti. Può essere creato manualmente o automaticamente con uno script ( script di esempio ). - Assicurati di utilizzare dati diversi nelle suddivisioni dei dati del test, poiché il test fallirà se le suddivisioni del set di dati si sovrappongono.
- I dati del test non devono contenere materiale protetto da copyright . In caso di dubbio, non creare i dati utilizzando materiale dal set di dati 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 comando seguente per testare il set di dati.
python my_dataset_test.py
Inviaci un feedback
Cerchiamo continuamente di migliorare il flusso di lavoro di creazione del set di dati, ma possiamo farlo solo se siamo consapevoli dei problemi. Quali problemi o errori hai riscontrato durante la creazione del set di dati? C'era una parte che creava confusione o non funzionava la prima volta?
Per favore condividi il tuo feedback su GitHub .