Помогают защитить Большой Барьерный Риф с TensorFlow на Kaggle Присоединяйтесь вызов

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

В этом документе представлены советы по производительности, специфичные для TensorFlow Datasets (TFDS). Обратите внимание , что TFDS предоставляет наборы данных , как tf.data.Dataset объектов, поэтому совет от tf.data руководства все еще применяется.

Наборы контрольных данных

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

Убедитесь в том , чтобы указать batch_size= нормализовать результаты (например , 100 ИТЭР / сек -> 3200 ех / сек). Это работает с любой итерацией (например tfds.benchmark(tfds.as_numpy(ds)) ).

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

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

Все наборы данных TFDS хранить данные на диске в TFRecord формате. Для небольших наборов данных (например , MNIST, CIFAR-10 / -100), чтение из .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.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 авто кэширует (с ds.cache() ) наборов данных , которые удовлетворяют следующим условиям:

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

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

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

Если ваш набор данных умещается в памяти, вы также можете загрузить полный набор данных как один массив Tensor или NumPy. Можно сделать так, установив 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 , чтобы получить хорошее поведение перетасовки для больших наборов данных, которые sharded на несколько файлов. В противном случае эпохи будут читать осколки в одном и том же порядке, и поэтому данные не будут действительно рандомизированы.

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

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

Автоматическое сегментирование ваших данных между воркерами (TF)

При обучении на нескольких рабочих, вы можете использовать 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() оп применяется на этих файлах. Например, при использовании train[:50%] с num_input_pipelines=2 , каждый из 2 -х рабочих будет читать 1/4 данных.

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

Автоматическое разделение данных между воркерами (Jax)

С Jax, Вы можете использовать tfds.even_splits API для распространения данных по работникам. Смотрите руководство Раскол API .

splits = tfds.even_splits('train', n=jax.process_count(), drop_remainder=True)
# The current `process_index` load only `1 / process_count` of the data.
ds = tfds.load('my_dataset', split=splits[jax.process_index()])

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

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

  • При фильтрации примеров (с tf.data.Dataset.filter ), чтобы декодировать изображения после того, как образцы были отфильтрованы.
  • При обрезке изображения, использовать слитую tf.image.decode_and_crop_jpeg цит.

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

Пропустить неиспользуемые функции

Если вы используете только часть функций, можно полностью пропустить некоторые функции. Если в вашем наборе данных много неиспользуемых функций, отказ от их декодирования может значительно улучшить производительность. См https://www.tensorflow.org/datasets/decode#only_decode_a_sub-set_of_the_features