Cette page a été traduite par l'API Cloud Translation.
Switch to English

Conseils de performance

Ce document fournit des conseils de performance spécifiques à TFDS. Notez que TFDS fournit des ensembles de données sous tf.data.Dataset de tf.data.Dataset s, donc les conseils du guide tf.data s'appliquent toujours.

Ensembles de données de référence

Utilisez tfds.core.benchmark(ds) pour comparer tout objet tf.data.Dataset .

Assurez-vous d'indiquer le batch_size= pour normaliser les résultats (par exemple 100 iter / sec -> 3200 ex / sec).

ds = tfds.load('mnist', split='train').batch(32).prefetch()
# Display some benchmark statistics
tfds.core.benchmark(ds, batch_size=32)
# Second iteration is much faster, due to auto-caching
tfds.core.benchmark(ds, batch_size=32)

Petits ensembles de données (<Go)

Tous les ensembles de données TFDS stockent les données sur disque au format TFRecord . Pour les petits ensembles de données (par exemple Mnist, Cifar, ...), la lecture à partir de .tfrecord peut ajouter une surcharge importante.

Comme ces ensembles de données tiennent en mémoire, il est possible d'améliorer considérablement les performances en mettant en cache ou en préchargeant l'ensemble de données. Notez que TFDS met automatiquement en cache les petits ensembles de données (voir la section suivante pour plus de détails).

Mettre en cache l'ensemble de données

Voici un exemple de pipeline de données qui met explicitement en cache l'ensemble de données après avoir normalisé les images.

def normalize_img(image, label):
  """Normalizes images: `uint8` -> `float32`."""
  return tf.cast(image, tf.float32) / 255., label


ds, ds_info = tfds.load(
    'mnist',
    split='train',
    as_supervised=True,  # returns `(img, label)` instead of dict(image=, ...)
    with_info=True,
)
# Applying normalization before `ds.cache()` to re-use it.
# Note: Random transformations (e.g. images augmentations) should be applied
# after both `ds.cache()` (to avoid caching randomness) and `ds.batch()` (for
# vectorization [1]).
ds = ds.map(normalize_img, num_parallel_calls=tf.data.experimental.AUTOTUNE)
ds = ds.cache()
# For true randomness, we set the shuffle buffer to the full dataset size.
ds = ds.shuffle(ds_info.splits['train'].num_examples)
# Batch after shuffling to get unique batches at each epoch.
ds = ds.batch(128)
ds = ds.prefetch(tf.data.experimental.AUTOTUNE)

Lors de l'itération sur cet ensemble de données, la deuxième itération sera beaucoup plus rapide que la première grâce à la mise en cache.

Mise en cache automatique

Par défaut, TFDS met automatiquement en cache les ensembles de données qui satisfont les contraintes suivantes:

  • La taille totale du jeu de données (toutes les divisions) est définie et <250 Mio
  • shuffle_files est désactivé, ou un seul fragment est lu

Il est possible de désactiver la mise en cache automatique en passant try_autocaching=False à tfds.ReadConfig dans tfds.load . Jetez un œil à la documentation du catalogue de jeux de données pour voir si un jeu de données spécifique utilisera le cache automatique.

Chargement des données complètes comme un seul Tensor

Si votre ensemble de données tient dans la mémoire, vous pouvez également charger l'ensemble de données complet en tant que tableau Tensor ou NumPy unique. Il est possible de le faire en définissant batch_size=-1 pour batch_size=-1 tous les exemples dans un seul tf.Tensor . Utilisez ensuite tfds.as_numpy pour la conversion de tf.Tensor en np.array .

(img_train, label_train), (img_test, label_test) = tfds.as_numpy(tfds.load(
    'mnist',
    split=['train', 'test'],
    batch_size=-1,
    as_supervised=True,
))

Grands ensembles de données

Les grands ensembles de données sont fragmentés (divisés en plusieurs fichiers) et ne tiennent généralement pas dans la mémoire, ils ne doivent donc pas être mis en cache.

Mélange et entraînement

Pendant l'entraînement, il est important de bien mélanger les données; des données mal mélangées peuvent entraîner une précision d'entraînement inférieure.

En plus d'utiliser ds.shuffle pour mélanger les enregistrements, vous devez également définir shuffle_files=True pour obtenir un bon comportement de mélange pour des ensembles de données plus volumineux qui sont fragmentés en plusieurs fichiers. Sinon, les époques liront les fragments dans le même ordre, et les données ne seront donc pas vraiment aléatoires.

ds = tfds.load('imagenet2012', split='train', shuffle_files=True)

De plus, lorsque shuffle_files=True , TFDS désactivent options.experimental_deterministic , ce qui peut donner un coup de pouce légère performance. Pour obtenir un mélange déterministe, il est possible de désactiver cette fonctionnalité avec tfds.ReadConfig : soit en définissant read_config.shuffle_seed soit en écrasant read_config.options.experimental_deterministic .

Partage automatique de vos données entre les collaborateurs

Lors de la formation sur plusieurs input_context de tfds.ReadConfig , vous pouvez utiliser l'argument input_context de tfds.ReadConfig , afin que chaque collaborateur lise un sous-ensemble des données.

input_context = tf.distribute.InputContext(
    input_pipeline_id=1,  # Worker id
    num_input_pipelines=4,  # Total number of workers
)
read_config = tfds.ReadConfig(
    input_context=input_context,
)
ds = tfds.load('dataset', split='train', read_config=read_config)

Ceci est complémentaire de l'API subsplit. Tout d'abord, l'API subplit est appliquée (le train[:50%] est converti en une liste de fichiers à lire), puis une opération ds.shard() est appliquée sur ces fichiers. Exemple: lors de l'utilisation du train[:50%] avec num_input_pipelines=2 , chacun des 2 worker lira 1/4 des données.

Lorsque shuffle_files=True , les fichiers sont mélangés au sein d'un même worker, mais pas entre les workers. Chaque travailleur lira le même sous-ensemble de fichiers entre les époques.

Décodage d'image plus rapide

Par défaut, TFDS décode automatiquement les images. Cependant, il y a des cas où il peut être plus performant d'ignorer le décodage d'image avec tfds.decode.SkipDecoding et d'appliquer manuellement l'opération tf.io.decode_image :

  • Lors du filtrage d'exemples (avec ds.filter ), pour décoder des images après que les exemples ont été filtrés.
  • Lors du recadrage d'images, pour utiliser l'op tf.image.decode_and_crop_jpeg fusionné.

Le code des deux exemples est disponible dans le guide de décodage .