tf.config.experimental.enable_op_determinism
Настраивает выполнение операций TensorFlow в детерминированном режиме.
tf.config.experimental.enable_op_determinism()
Когда детерминизм операций включен, операции TensorFlow выполняются детерминированно. Это означает, что при многократном выполнении операции с одинаковыми входными данными на одном и том же оборудовании каждый раз будут получаться в точности одинаковые выходные данные. Это полезно для отладки моделей. Обратите внимание: детерминизм в целом достигается ценой снижения производительности, поэтому при включенном детерминизме операций модель может работать медленнее.
Чтобы программа TensorFlow выполнялась детерминированно, поместите следующий код в начало программы.
tf.keras.utils.set_random_seed(1) tf.config.experimental.enable_op_determinism()
Вызов tf.keras.utils.set_random_seed задает начальное значение генератора для Python, NumPy и TensorFlow. Задать эти начальные значения необходимо, чтобы все случайные числа, генерируемые программой, также были детерминированными.
По умолчанию детерминизм операций не включен, поэтому при повторном выполнении с одинаковыми входными данными операции могут возвращать разные результаты. Такие различия часто вызваны тем, что асинхронные потоки внутри операции недетерминированно меняют порядок сложения чисел с плавающей запятой. Большинство таких случаев недетерминизма возникает на графических процессорах, в которых тысячи аппаратных потоков используются для выполнения операций. Включение детерминизма заставляет такие операции использовать другой алгоритм, который не использует потоки недетерминированным образом.
Еще одним потенциальным источником недетерминизма является обработка данных на основе tf.data. Как правило, недетерминизм может возникать из-за использования параллелизма в таких методах, как Dataset.map, при подготовке входных данных или выполнении операций с состоянием в недетерминированном порядке. Включение детерминизма устраняет такие источники недетерминизма.
Включение детерминизма, скорее всего, замедлит работу модели или обработку данных с помощью tf.data. Например, Dataset.map может стать на несколько порядков медленнее, если функция map содержит случайные операции или другие операции с состоянием. Подробнее см. в разделе «Детерминизм и tf.data» ниже. В будущих выпусках TensorFlow мы планируем повысить производительность детерминированного выполнения, особенно в распространенных сценариях, например при использовании Dataset.map.
Некоторые операции вызовут UnimplementedError, поскольку для них пока не реализовано детерминированное выполнение. Кроме того, из-за ошибок некоторые операции могут быть недетерминированными и не вызывать UnimplementedError. Если вы столкнетесь с такими операциями, сообщите об ошибке.
Ниже приведен пример включения детерминизма. Операция tf.nn.softmax_cross_entropy_with_logits выполняется несколько раз, и показано, что каждый раз результат одинаков. Вероятно, этот пример завершился бы неудачно при запуске на графическом процессоре, если бы детерминизм не был включен, поскольку по умолчанию tf.nn.softmax_cross_entropy_with_logits на графических процессорах использует недетерминированный алгоритм.
labels = tf.random.normal((1, 10000))
logits = tf.random.normal((1, 10000))
output = tf.nn.softmax_cross_entropy_with_logits(labels=labels,
logits=logits)
for _ in range(5):
output2 = tf.nn.softmax_cross_entropy_with_logits(labels=labels,
logits=logits)
tf.debugging.assert_equal(output, output2)
Создание детерминированных моделей
Вы можете сделать модели детерминированными, включив детерминизм операций. Это означает, что обучение модели при каждом запуске будет завершаться получением в точности одинаковых обучаемых переменных. Также это означает, что результаты инференса ранее обученной модели будут в точности одинаковыми при каждом запуске. Как правило, чтобы сделать модели детерминированными, достаточно задать начальные значения генераторов и включить детерминизм операций, как в примере выше. Однако, чтобы гарантировать детерминированную работу модели, необходимо выполнить все следующие требования:
- Вызовите
tf.config.experimental.enable_op_determinism(), как указано выше. - Сбрасывайте используемые генераторы псевдослучайных чисел (PRNG) воспроизводимым образом, например задавая начальные значения для генераторов по умолчанию в TensorFlow, Python и NumPy, как указано выше. Обратите внимание, что некоторые новые классы NumPy, например
numpy.random.default_rng, игнорируют глобальное начальное значение NumPy, поэтому при их использовании необходимо явно передавать таким классам начальное значение. - Используйте одну и ту же конфигурацию оборудования при каждом запуске.
- Используйте одну и ту же программную среду при каждом запуске (ОС, контрольные точки, версии CUDA и TensorFlow, переменные среды и т. д.). Обратите внимание, что детерминизм не гарантируется для разных версий TensorFlow.
- Не используйте недетерминированные конструкции вне TensorFlow, например чтение из
/dev/randomили использование нескольких потоков/процессов таким образом, который влияет на поведение TensorFlow. - Обеспечьте детерминированность конвейера ввода. При использовании
tf.dataэто выполняется автоматически (за счет снижения производительности). Дополнительные сведения см. в разделе «Детерминизм и tf.data» ниже. - Не используйте
tf.compat.v1.Sessionиtf.distribute.experimental.ParameterServerStrategy, которые могут внести недетерминизм. Помимо операций (в том числе операцийtf.data), это единственные известные потенциальные источники недетерминизма в TensorFlow (если вы обнаружите другие, сообщите об ошибке). Обратите внимание, что для использования API TF1 необходимtf.compat.v1.Session, поэтому при использовании API TF1 детерминизм гарантировать нельзя. - Не используйте недетерминированные пользовательские операции.
Дополнительные сведения о детерминизме
Для детерминированного выполнения операций с состоянием состояние системы должно быть одинаковым при каждом запуске операции. Например, результат tf.Variable.sparse_read (очевидно) зависит как от значения переменной, так и от параметра функции indices. При включенном детерминизме побочные эффекты операций с состоянием являются детерминированными.
Случайные операции TensorFlow, например tf.random.normal, вызовут RuntimeError, если детерминизм включен, а начальное значение генератора не задано. Однако попытка сгенерировать недетерминированные случайные числа с помощью Python или NumPy не вызовет таких ошибок. Не забудьте задать начальные значения генераторов для Python и NumPy. Вызов tf.keras.utils.set_random_seed — простой способ задать все три начальных значения.
Обратите внимание, что включение детерминизма операций не делает детерминированными задержку, потребление памяти, пропускную способность и другие характеристики производительности. Детерминированными становятся только выходные данные операций и их побочные эффекты. Кроме того, из-за недетерминированного потребления памяти модель может недетерминированно вызвать ошибку tf.errors.ResourceExhaustedError из-за нехватки памяти.
Детерминизм и tf.data
Включение детерминированного выполнения операций обеспечивает детерминированность tf.data несколькими способами:
- Для методов набора данных с аргументом
deterministic, таких какDataset.mapиDataset.batch, аргументdeterministicпринудительно устанавливается в значениеTrueнезависимо от его исходного значения. - Параметру
tf.data.Option.experimental_deterministicпринудительно присваивается значениеTrueнезависимо от его исходного значения. - В методах
Dataset.mapиDataset.interleave, если функция map или interleave содержит случайные операции с состоянием или другие операции с состоянием, она будет выполняться последовательно, а не параллельно. Это означает, что аргументnum_parallel_callsдляmapиinterleaveфактически игнорируется. - Предварительная выборка с помощью
Dataset.prefetchбудет отключена, если какая-либо функция, выполняемая в составе конвейера ввода, содержит определенные операции с состоянием. Аналогичным образом любой метод набора данных с аргументомnum_parallel_callsбудет выполняться последовательно, если какая-либо функция в конвейере ввода содержит такие операции с состоянием. Устаревшие случайные операции, напримерtf.random.normal, не приведут к изменению таких наборов данных, однако большинство других операций с состоянием приведут.
К сожалению, из-за пункта (3) производительность может значительно снизиться при использовании операций с состоянием в Dataset.map, поскольку функция map перестает выполняться параллельно. Распространенный пример использования операций с состоянием в Dataset.map — случайные операции, например tf.random.normal, которые обычно используются для искажения данных. Один из способов обойти это ограничение — использовать вместо них случайные операции без состояния. Также можно вынести все случайные операции в отдельный вызов Dataset.map, сделав исходный вызов Dataset.map не имеющим состояния и тем самым избежав необходимости последовательно выполнять его.
Пункт (4) также может привести к снижению производительности, но это происходит реже, чем в случае с пунктом (3), поскольку устаревшие случайные операции не приводят к применению пункта (4). Однако, в отличие от пункта (3), при наличии в пользовательской функции операций с состоянием, не связанных со случайными числами, затрагиваются все наборы данных map и interleave, а не только набор данных map или interleave, в функции которого есть операции с состоянием. Кроме того, затрагиваются наборы данных prefetch и любые наборы данных с аргументом num_parallel_calls.
© 2022 The TensorFlow Authors. All rights reserved.
Licensed under the Creative Commons Attribution License 4.0.
Code samples licensed under the Apache 2.0 License.
https://www.tensorflow.org/api_docs/python/tf/config/experimental/enable_op_determinism