Aiuto proteggere la Grande Barriera Corallina con tensorflow sul Kaggle Join Sfida

Scrittura di set di dati personalizzati

Segui questa guida per creare un nuovo set di dati (in TFDS o nel tuo repository).

Controllare la nostra lista di set di dati per vedere se il set di dati che si desidera è già presente.

TL;DR

Il modo più semplice per scrivere un nuovo insieme di dati è quello di utilizzare il TFDS CLI :

cd path/to/my/project/datasets/
tfds new my_dataset  # Create `my_dataset/my_dataset.py` template files
# [...] Manually modify `my_dataset/my_dataset.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à automaticamente e caricare il set di dati generato in ~/tensorflow_datasets/my_dataset/ (ad esempio, da tfds build ).
  • In alternativa, è possibile in modo esplicito import my.project.datasets.my_dataset registrare il proprio 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 elaborano quelle serie di dati in un formato standard (dati esterne -> file serializzato), che possono poi essere caricati come pipeline di apprendimento automatico (file serializzato -> tf.data.Dataset ). La serializzazione viene eseguita una sola volta. L'accesso successivo leggerà direttamente da quei file pre-elaborati.

La maggior parte della pre-elaborazione viene eseguita automaticamente. Ogni set di dati implementa una sottoclasse di tfds.core.DatasetBuilder , che specifica:

  • Da dove provengono i dati (cioè i suoi URL);
  • Che aspetto ha il set di dati (ovvero le sue caratteristiche);
  • Come i dati devono essere suddivisi (ad esempio, TRAIN e TEST );
  • e i singoli esempi nel set di dati.

Scrivi il tuo set di dati

Modello predefinito: tfds new

Utilizzare TFDS CLI per generare i file python modello richiesto.

cd path/to/project/datasets/  # Or use `--dir=path/to/project/datasets/` below
tfds new my_dataset

Questo comando genererà una nuova my_dataset/ cartella con la seguente struttura:

my_dataset/
    __init__.py
    my_dataset.py # Dataset definition
    my_dataset_test.py # (optional) Test
    dummy_data/ # (optional) Fake data (used for testing)
    checksum.tsv # (optional) URL checksums (see `checksums` section).

Cerca TODO(my_dataset) qui e modificare di conseguenza.

Esempio di set di dati

Tutti i set di dati sono implementati come tfds.core.GeneratorBasedBuilder , un sottoclassi di tfds.core.DatasetBuilder che si occupa della maggior parte boilerplate. Supporta:

  • Set di dati di piccole/medie dimensioni che possono essere generati su una singola macchina (questo tutorial).
  • Molto grandi serie di dati che richiedono la generazione distribuita (usando Apache fascio , vedere la nostra guida enorme set di dati )

Ecco un esempio minimo di classe dataset:

class MyDataset(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 tfds.core.DatasetInfo(
        builder=self,
        features=tfds.features.FeaturesDict({
            'image': tfds.features.Image(shape=(256, 256, 3)),
            'label': tfds.features.ClassLabel(names=['no', 'yes']),
        }),
    )

  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',
      }

Vediamo nel dettaglio i 3 metodi astratti per sovrascrivere.

_info : set di dati di metadati

_info restituisce il tfds.core.DatasetInfo contenente il metadati set di dati .

def _info(self):
  return tfds.core.DatasetInfo(
      builder=self,
      # Description and homepage used for documentation
      description="""
      Markdown description of the dataset. The text will be automatically
      stripped and dedent.
      """,
      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,
      # Bibtex citation for the dataset
      citation=r"""
      @article{my-awesome-dataset-2020,
               author = {Smith, John},}
      """,
  )

La maggior parte dei campi dovrebbe essere autoesplicativa. Alcune precisazioni:

  • features : Questa struttura di specificare il set di dati, forma, ... supporta i tipi di dati complessi (audio, video, sequenze nidificate, ...). Vedere le funzioni disponibili o la guida del connettore funzione per ulteriori informazioni.
  • disable_shuffling : Vedere la sezione Mantenere dataset ordine .
  • citation : Per trovare la BibText citazione:
    • Cerca nel sito Web del set di dati le istruzioni per la citazione (usalo in formato BibTex).
    • Per arXiv carte: trovare la carta e fare clic sul BibText link sul lato destro.
    • Trova la carta su Google Scholar e fare clic sul segno doppio citazione sotto il titolo e sulla comparsa, fare clic BibTeX .
    • Se non v'è associato carta (ad esempio, c'è solo un sito web), è possibile utilizzare l' BibTeX Online Editor per creare una voce BibTeX personalizzato (il menu a discesa ha una Online tipo di voce).

Mantieni l'ordine del set di dati

Per impostazione predefinita, i record dei dataset vengono rimescolati quando vengono archiviati in modo da rendere più uniforme la distribuzione delle classi nel dataset, poiché spesso i record appartenenti alla stessa classe sono contigui. Al fine di specificare che il set di dati deve essere ordinato per la chiave generata fornita dal _generate_examples campo disable_shuffling deve essere impostato su True . Di default è impostato su False .

def _info(self):
  return tfds.core.DatasetInfo(
    # [...]
    disable_shuffling=True,
    # [...]
  )

Tieni presente che disabilitare la riproduzione casuale ha un impatto sulle prestazioni poiché i frammenti non possono più essere letti in parallelo.

_split_generators : download e spaccature dei dati

Download ed estrazione dei dati di origine

La maggior parte dei set di dati deve scaricare dati dal Web. Questo viene fatto usando il tfds.download.DownloadManager argomento di input di _split_generators . dl_manager ha i seguenti metodi:

  • download : supporti http(s):// , ftp(s)://
  • extract : attualmente supporta .zip , .gz , e .tar file.
  • download_and_extract : come dl_manager.extract(dl_manager.download(urls))

Tutti questi metodi restituisce tfds.core.ReadOnlyPath , che sono pathlib.Path-come oggetti.

Quei supporta i metodi arbitrari struttura annidata ( 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 account di accesso), in questo caso, l'utente scaricherà manualmente i dati di origine e posizionarlo nella manual_dir/ (il valore predefinito è ~/tensorflow_datasets/downloads/manual/ ).

I file possono poi accedere attraverso 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 manual_dir posizione può essere personalizzato con tfds build --manual_dir= o utilizzando tfds.download.DownloadConfig .

Leggi l'archivio direttamente

dl_manager.iter_archive legge un archivio in sequenza senza estrarli. 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: (es fobj.read() )

Specificare le suddivisioni del set di dati

Se l'insieme di dati viene fornito con spaccature predefiniti (ad esempio MNIST ha train e test si divide), mantenere quelli. In caso contrario, specificare solo un singolo tfds.Split.TRAIN spaccatura. Gli utenti possono creare in modo dinamico i propri subsplits con l' API subsplit (ad esempio split='train[80%:]' ).

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 Esempio

_generate_examples genera gli esempi per ogni gruppo dei dati di origine.

Questo metodo sarà tipicamente leggere artefatti set di dati sorgente (ad esempio un CSV file) e resa (key, feature_dict) tuple:

  • key : identificatore Esempio. Utilizzato per deterministicamente mischiare gli esempi che utilizzano hash(key) o per ordinare in chiave quando rimescolamento è disattivato (vedere la sezione Mantenere dataset ordine ). Dovrebbe essere:
    • unico nel suo genere: Se due esempi utilizzano la stessa chiave, un'eccezione sarà sollevata.
    • deterministico: Qualora non dipende download_dir , os.path.listdir ordine, ... Generazione due volte i dati devono produrre la stessa chiave.
    • paragonabili: Se rimescolamento è disattivata la chiave verrà utilizzato per ordinare il set di dati.
  • feature_dict : Un dict contenente i valori di esempio.
    • La struttura dovrebbe corrispondere alla features= struttura definita in tfds.core.DatasetInfo .
    • I tipi di dati complessi (immagine, video, audio,...) verranno codificati automaticamente.
    • Ogni caratteristica accetta spesso più tipi di ingresso (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] , ...)
    • Consultare la guida del connettore funzione per ulteriori informazioni.
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, i dl_manager rendimenti pathlib-come oggetti direttamente compatibili con lo storage 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, utilizzare tf.io.gfile API invece di built-in per le operazioni di file:

Pathlib dovrebbe essere preferì tf.io.gfile (vedi razionale .

Dipendenze extra

Alcuni set di dati richiedono dipendenze Python aggiuntive solo durante la generazione. Ad esempio, gli usi SVHN set di dati scipy caricare alcuni dati.

Se si sta aggiungendo insieme di dati in repository TFDS, si prega di utilizzare tfds.core.lazy_imports per mantenere i tensorflow-datasets piccolo pacchetto. Gli utenti installeranno dipendenze aggiuntive solo se necessario.

Per utilizzare lazy_imports :

  • Aggiungere una voce per il set di dati in DATASET_EXTRAS in setup.py . Questo fa in modo che gli utenti possono fare, ad esempio, pip install 'tensorflow-datasets[svhn]' per installare le dipendenze extra.
  • Aggiungere una voce per l'importazione di LazyImporter e al LazyImportsTest .
  • Utilizzare tfds.core.lazy_imports per accedere alla dipendenza (ad esempio, tfds.core.lazy_imports.scipy ) nella vostra DatasetBuilder .

Dati corrotti

Alcuni set di dati non sono perfettamente puliti e contengono alcuni dati corrotti (ad esempio, le immagini sono in file JPEG ma alcuni sono JPEG non validi). Questi esempi dovrebbero essere saltati, ma lasciare 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 a coppie di oggetti ( cycle_gan/horse2zebra , cycle_gan/monet2photo , ...).

Questo viene fatto attraverso tfds.core.BuilderConfig s:

  1. Definire l'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)
    
  2. Definire il BUILDER_CONFIGS = [] membro della classe in MyDataset che le liste MyDatasetConfig s che espone 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
    
  3. Uso self.builder_config in MyDataset di generazione di dati di configurazione (ad esempio shape=self.builder_config.img_size ). Questo può includere impostando valori diversi in _info() o modificare l'accesso scaricare dati.

Appunti:

  • Ogni configurazione ha un nome univoco. Il nome completo di una configurazione è dataset_name/config_name (es coco/2017 ).
  • Se non specificato, il primo config nella BUILDER_CONFIGS verrà utilizzato (ad esempio tfds.load('c4') di default per c4/en )

Vedere anli per un esempio di un insieme di dati che utilizza BuilderConfig s.

Versione

La versione può riferirsi a due diversi significati:

  • La versione dei dati originali "esterni": ad es. COCO v2019, v2017,...
  • La versione "interna" TFDS codice: ad esempio funzione rinomina un in tfds.features.FeaturesDict , correggere un bug in _generate_examples

Per aggiornare un set di dati:

  • Per l'aggiornamento dei dati "esterno": più utenti potrebbero voler accedere contemporaneamente a uno specifico anno/versione. Questo viene fatto utilizzando uno tfds.core.BuilderConfig per ogni versione (ad esempio, coco/2017 , coco/2019 ) o di una classe per la versione (ad esempio Voc2007 , Voc2012 ).
  • Per l'aggiornamento del codice "interno": gli utenti scaricano solo la versione più recente. Qualsiasi aggiornamento codice dovrebbe aumentare la VERSION attributo di classe (ad esempio da 1.0.0 a VERSION = tfds.core.Version('2.0.0') ) a seguito delle versioni semantico .

Aggiungi un'importazione per la registrazione

Non dimenticate di importare il modulo dataset al progetto __init__ essere registrati automaticamente tfds.load , tfds.builder .

import my_project.datasets.my_dataset  # Register MyDataset

ds = tfds.load('my_dataset')  # MyDataset available

Ad esempio, se si sta contribuendo a tensorflow/datasets , aggiungere l'importazione modulo del suo sottodirectory __init__.py (ad esempio image/__init__.py .

Verifica i trucchi di implementazione comuni

Si prega di verificare per i trucchi di implementazione comuni .

Metti alla prova il tuo set di dati

Scaricare e preparare: tfds build

Per generare il set di dati, gestito tfds build dalla my_dataset/ directory:

cd path/to/datasets/my_dataset/
tfds build --register_checksums

Alcuni flag utili per lo sviluppo:

  • --pdb : Attivare la modalità di debug, se viene generata un'eccezione.
  • --overwrite : Eliminare i file esistenti se il set di dati è stato già generato.
  • --max_examples_per_split : generano solo i primi esempi X (default a 1), piuttosto che il set di dati completo.
  • --register_checksums : Registrare i checksum di URL scaricati. Dovrebbe essere usato solo durante lo sviluppo.

Vedere la documentazione di CLI per la lista completa delle bandiere.

Checksum

Si consiglia di registrare i checksum dei vostri set di dati per garantire il determinismo, aiuto con la documentazione, ... Questo è fatto da generare il set di dati con i --register_checksums (vedi paragrafo precedente).

Se si stanno rilasciando i dataset attraverso PyPI, non dimenticare di esportare i checksums.tsv file (ad esempio nel package_data del vostro setup.py ).

Testa l'unità del tuo set di dati

tfds.testing.DatasetBuilderTestCase è una base TestCase di esercitare pienamente un set di dati. Utilizza "dati fittizi" come dati di test che imitano la struttura del set di dati di origine.

  • I dati dei test dovrebbero essere messi in my_dataset/dummy_data/ directory e dovrebbero imitare gli artefatti fonte set di dati come scaricato ed estratto. 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 di prova non deve contenere alcun 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


class MyDatasetTest(tfds.testing.DatasetBuilderTestCase):
  """Tests for my_dataset dataset."""
  DATASET_CLASS = my_dataset.MyDataset
  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 dummy_data/my_dataset 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 a conoscenza dei problemi. Quali problemi, errori hai riscontrato durante la creazione del set di dati? C'era una parte che era confusa, standard o non funzionava la prima volta? Si prega di condividere il tuo feedback su GitHub .