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

Trucchi di implementazione comuni

Questa pagina descrive il trucco comune per l'implementazione durante l'implementazione di un nuovo set di dati.

Legacy SplitGenerator dovrebbe essere evitato

Il vecchio tfds.core.SplitGenerator API è obsoleto.

def _split_generator(...):
  return [
      tfds.core.SplitGenerator(name='train', gen_kwargs={'path': train_path}),
      tfds.core.SplitGenerator(name='test', gen_kwargs={'path': test_path}),
  ]

Dovrebbe essere sostituito da:

def _split_generator(...):
  return {
      'train': self._generate_examples(path=train_path),
      'test': self._generate_examples(path=test_path),
  }

Motivazione: La nuova API è meno prolisso e più esplicita. La vecchia API verrà rimossa nella versione futura.

I nuovi set di dati dovrebbero essere contenuti in una cartella

Quando si aggiunge un set di dati all'interno del tensorflow_datasets/ repository, assicurarsi di seguire il set di dati-as-cartella struttura (tutti i checksum, dati fittizi, codice di implementazione auto-contenuto in una cartella).

  • Vecchi dataset (cattivo): <category>/<ds_name>.py
  • Le nuove serie di dati (buono): <category>/<ds_name>/<ds_name>.py

Utilizzare il TFDS CLI ( tfds new , o gtfds new per Googler) per generare il modello.

Motivazione: vecchia struttura necessaria percorsi assoluti per checksum, dati falsi e stava distribuendo i file del set di dati in molti luoghi. Stava rendendo più difficile implementare set di dati al di fuori del repository TFDS. Per coerenza, la nuova struttura dovrebbe essere utilizzata ovunque ora.

Gli elenchi di descrizioni devono essere formattati come markdown

Il DatasetInfo.description str è formattato come Markdown. Gli elenchi Markdown richiedono una riga vuota prima del primo elemento:

_DESCRIPTION = """
Some text.
                      # << Empty line here !!!
1. Item 1
2. Item 1
3. Item 1
                      # << Empty line here !!!
Some other text.
"""

Motivazione: Descrizione Badly formattato creare artefatti visivi a nostra documentazione catalogo. Senza le righe vuote, il testo sopra sarebbe reso come:

Un po' di testo. 1. Voce 1 2. Voce 1 3. Voce 1 Altro testo

Nomi ClassLabel dimenticati

Quando si utilizza tfds.features.ClassLabel , cercare di fornire le etichette leggibili str con names= o names_file= (invece di num_classes=10 ).

features = {
    'label': tfds.features.ClassLabel(names=['dog', 'cat', ...]),
}

Motivazione: le etichette leggibili umani sono utilizzati in molti luoghi:

Dimenticato la forma dell'immagine

Quando si utilizza tfds.features.Image , tfds.features.Video , se le immagini hanno forma statica, dovrebbero essere esplicitamente specificato:

features = {
    'image': tfds.features.Image(shape=(256, 256, 3)),
}

Logica: Permette forma inferenza statica (es ds.element_spec['image'].shape ), Che è richiesto per il dosaggio (Dosaggio immagini di forma Sconosciuto richiederebbero loro ridimensionamento prima).

Preferisco più specifico tipo invece di tfds.features.Tensor

Quando possibile, preferiscono i tipi più specifici tfds.features.ClassLabel , tfds.features.BBoxFeatures , ... invece del generico tfds.features.Tensor .

Motivazioni: Oltre ad essere più semanticamente corretto, Caratteristiche specifiche fornisce metadati aggiuntivi per gli utenti e vengono rilevati da strumenti.

Importazioni pigre nello spazio globale

Le importazioni pigre non dovrebbero essere chiamate dallo spazio globale. Ad esempio quanto segue è sbagliato:

tfds.lazy_imports.apache_beam # << Error: Import beam in the global scope

def f() -> beam.Map:
  ...

Motivazione: Usando le importazioni pigri nel campo di applicazione globale sarebbe importare il modulo per tutti gli utenti TFDS, sconfiggendo lo scopo delle importazioni pigri.

Calcolo dinamico delle suddivisioni treno/test

Se il set di dati non fornisce suddivisioni ufficiali, nemmeno TFDS dovrebbe. Si dovrebbe evitare quanto segue:

_TRAIN_TEST_RATIO = 0.7

def _split_generator():
  ids = list(range(num_examples))
  np.random.RandomState(seed).shuffle(ids)

  # Split train/test
  train_ids = ids[_TRAIN_TEST_RATIO * num_examples:]
  test_ids = ids[:_TRAIN_TEST_RATIO * num_examples]
  return {
      'train': self._generate_examples(train_ids),
      'test': self._generate_examples(test_ids),
  }

Motivazione: TFDS cercare di fornire set di dati il più vicino i dati originali. L' API sub-split dovrebbe essere usato invece per consentire agli utenti di creare in modo dinamico le subsplits che vogliono:

ds_train, ds_test = tfds.load(..., split=['train[:80%]', 'train[80%:]'])

Guida allo stile Python

Preferisco usare l'API pathlib

Invece del tf.io.gfile API, è preferibile utilizzare l' API pathlib . Tutti dl_manager metodi rendimenti pathlib-come oggetti compatibili con GCS, S3, ...

path = dl_manager.download_and_extract('http://some-website/my_data.zip')

json_path = path / 'data/file.json'

json.loads(json_path.read_text())

Motivazione: pathlib API è un moderno orientato agli oggetti del file API che rimuovono boilerplate. Utilizzando .read_text() / .read_bytes() garantiscono anche i file vengono chiusi correttamente.

Se il metodo non utilizza self , dovrebbe essere una funzione

Se un metodo di classe non utilizza self , dovrebbe essere una semplice funzione (definita all'esterno della classe).

Motivazione: Lo rende esplicito al lettore che la funzione non hanno effetti collaterali, né nascosto di input / output:

x = f(y)  # Clear inputs/outputs

x = self.f(y)  # Does f depend on additional hidden variables ? Is it stateful ?