Эта страница была переведа с помощью Cloud Translation API.
Switch to English

Советы по производительности

В этом документе представлены советы по производительности для TFDS. Обратите внимание, что TFDS предоставляет наборы данных как tf.data.Dataset s, поэтому совет из руководства tf.data прежнему применим.

Контрольные наборы данных

Используйте tfds.core.benchmark(ds) для тестирования любого объекта tf.data.Dataset .

Обязательно укажите batch_size= чтобы нормализовать результаты (например, 100 т / сек -> 3200 экс / сек).

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)

Небольшие наборы данных (<ГБ)

Все наборы данных TFDS хранят данные на диске в формате TFRecord . Для небольших наборов данных (например, Mnist, Cifar, ...) чтение из .tfrecord может привести к значительным накладным расходам.

Поскольку эти наборы данных умещаются в памяти, можно значительно повысить производительность за счет кэширования или предварительной загрузки набора данных. Обратите внимание, что TFDS автоматически кэширует небольшие наборы данных (подробности см. В следующем разделе).

Кэширование набора данных

Вот пример конвейера данных, который явно кэширует набор данных после нормализации изображений.

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)

При итерации по этому набору данных вторая итерация будет намного быстрее первой благодаря кешированию.

Авто-кеширование

По умолчанию TFDS автоматически кэширует наборы данных, которые удовлетворяют следующим ограничениям:

  • Общий размер набора данных (все разбиения) определен и составляет <250 МБ
  • shuffle_files отключен, или читается только один шард

Можно отказаться от автоматического кэширования, передав try_autocaching=False в tfds.ReadConfig в tfds.load . Посмотрите документацию каталога наборов данных, чтобы узнать, будет ли определенный набор данных использовать автоматическое кеширование.

Загрузка полных данных как одного тензора

Если ваш набор данных умещается в памяти, вы также можете загрузить полный набор данных как один массив Tensor или NumPy. Это можно сделать, установив batch_size=-1 чтобы batch_size=-1 все примеры в один tf.Tensor . Затем используйте tfds.as_numpy для преобразования из tf.Tensor в 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,
))

Большие наборы данных

Большие наборы данных сегментируются (разбиваются на несколько файлов) и обычно не помещаются в памяти, поэтому их не следует кэшировать.

Перемешивание и обучение

Во время обучения важно хорошо перемешать данные; плохо перемешанные данные могут привести к снижению точности обучения.

Помимо использования ds.shuffle для перемешивания записей, вы также должны установить shuffle_files=True чтобы получить хорошее поведение при перемешивании для больших наборов данных, которые сегментированы в несколько файлов. В противном случае эпохи будут читать осколки в одном и том же порядке, и поэтому данные не будут действительно рандомизированы.

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

Кроме того, когда shuffle_files=True , TFDS отключает options.experimental_deterministic , что может немного повысить производительность. Чтобы получить детерминированное перемешивание, можно отказаться от этой функции с помощью tfds.ReadConfig : либо установив read_config.shuffle_seed либо перезаписав read_config.options.experimental_deterministic .

Автоматически распределяйте данные между воркерами

При обучении нескольких input_context вы можете использовать аргумент input_context в tfds.ReadConfig , чтобы каждый воркер считывал подмножество данных.

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)

Это дополнение к API-интерфейсу subplit. Сначала применяется subplit API ( train[:50%] преобразуется в список файлов для чтения), затем к этим ds.shard() применяется ds.shard() . Пример: при использовании train[:50%] с num_input_pipelines=2 каждый из 2 рабочих будет читать 1/4 данных.

Когда shuffle_files=True , файлы перетасовываются внутри одного рабочего, но не между рабочими. Каждый рабочий будет читать одно и то же подмножество файлов между эпохами.

Более быстрое декодирование изображений

По умолчанию TFDS автоматически декодирует изображения. Однако бывают случаи, когда может быть более эффективным пропустить декодирование изображения с помощью tfds.decode.SkipDecoding и вручную применить tf.io.decode_image op:

  • При фильтрации примеров (с помощью ds.filter ) для декодирования изображений после фильтрации примеров.
  • При обрезке изображений использовать объединенный tf.image.decode_and_crop_jpeg op.

Код для обоих примеров доступен в руководстве по декодированию .