当前位置: 首页>>代码示例 >>用法及示例精选 >>正文


Python 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 种子。设置这些种子是必要的,以确保您的程序生成的任何随机数也是确定性的。

默认情况下,操作确定性未启用,因此操作在使用相同输入运行时可能会返回不同的结果。这些差异通常是由于在操作中使用异步线程不确定地更改浮点数相加的顺序造成的。大多数这些不确定性情况发生在 GPU 上,GPU 有数千个用于运行操作的硬件线程。启用确定性会指示此类操作使用不同的算法,该算法不会以不确定的方式使用线程。

不确定性的另一个潜在来源是基于tf.data 的数据处理。通常,由于在 Dataset.map 生成输入或以非确定性顺序运行有状态操作等方法中使用并行性,这可能会引入不确定性。启用确定性将消除这些非确定性的来源。

启用确定性可能会使您的模型或 tf.data 数据处理速度变慢。例如,当 map 函数具有随机操作或其他有状态操作时,Dataset.map 可能会变慢几个数量级。有关更多详细信息,请参阅下面的“确定性和 tf.data”部分。在未来的 TensorFlow 版本中,我们计划提高确定性的性能,尤其是对于常见场景,例如 Dataset.map

某些操作会引发UnimplementedError,因为它们还没有确定性的实现。此外,由于错误,某些操作可能是不确定的,不会引发 UnimplementedError 。如果您遇到此类操作,请提出问题。

下面是一个启用确定性的示例。 tf.nn.softmax_cross_entropy_with_logits op 运行多次,并且每次显示的输出都相同。如果未启用确定性,则此示例在 GPU 上运行时可能会失败,因为默认情况下 tf.nn.softmax_cross_entropy_with_logits 在 GPU 上使用非确定性算法。

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)

编写确定性模型

您可以通过启用操作确定性来使您的模型具有确定性。这意味着您可以训练模型并使用完全相同的可训练变量完成每次运行。这也意味着您的previously-trained 模型的推论在每次运行时都将完全相同。通常,可以通过简单地设置种子并启用操作确定性来使模型具有确定性,如上面的示例所示。但是,为了保证您的模型确定性地运行,您必须满足以下所有要求:

  • 如上所述,调用 tf.config.experimental.enable_op_determinism()
  • 如上所述,可重复地重置您正在使用的任何伪随机数生成器 (PRNG),例如通过在 TensorFlow、Python 和 NumPy 中设置默认 PRNG 的种子。请注意,某些较新的 NumPy 类(如 numpy.random.default_rng)会忽略全局 NumPy 种子,因此如果使用种子,则必须将种子显式传递给此类类。
  • 在每次运行中使用相同的硬件配置。
  • 在每次运行中使用相同的软件环境(操作系统、检查点、CUDA 和 TensorFlow 的版本、环境变量等)。请注意,不同版本的 TensorFlow 无法保证确定性。
  • 不要在 TensorFlow 之外使用不确定的构造,例如从 /dev/random 读取或以影响 TensorFlow 行为的方式使用多个线程/进程。
  • 确保您的输入管道是确定性的。如果您使用 tf.data ,这是自动完成的(以牺牲性能为代价)。有关详细信息,请参阅下面的“确定性和 tf.data”。
  • 不要使用 tf.compat.v1.Sessiontf.distribute.experimental.ParameterServerStrategy ,这会引入不确定性。除了 ops(包括 tf.data ops),这些是 TensorFlow 中唯一已知的潜在不确定性来源(如果您发现更多,请提出问题)。请注意,tf.compat.v1.Session 是使用 TF1 API 所必需的,因此在使用 TF1 API 时无法保证确定性。
  • 不要使用不确定的自定义操作。

有关确定性的其他详细信息

为了使有状态操作具有确定性,每次运行操作时系统的状态都必须相同。例如,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 在几个方掩码有确定性:

  1. 对于具有 deterministic 参数的数据集方法,例如 Dataset.mapDataset.batch ,无论其设置如何,deterministic 参数都会被覆盖为 True
  2. tf.data.Option.experimental_deterministic 选项被覆盖为 True 而不管其设置如何。
  3. Dataset.mapDataset.interleave 中,如果 map 或 interleave 函数具有状态随机操作或其他状态操作,则该函数将串行运行而不是并行运行。这意味着 mapinterleavenum_parallel_calls 参数被有效地忽略。
  4. 如果作为输入管道的一部分运行的任何函数具有某些有状态操作,则使用 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) 不同的是,当用户定义的函数中存在非随机状态操作时,每个 mapinterleave 数据集都会受到影响,而不仅仅是带有函数的 mapinterleave 数据集有状态操作。此外,prefetch 数据集和任何带有 num_parallel_calls 参数的数据集也会受到影响。

相关用法


注:本文由纯净天空筛选整理自tensorflow.org大神的英文原创作品 tf.config.experimental.enable_op_determinism。非经特殊声明,原始代码版权归原作者所有,本译文未经允许或授权,请勿转载或复制。