TensorFlow函数和图

def cube(x):
    return x**3
cube(2)
8
import tensorflow as tf
cube(tf.constant(2.0))
<tf.Tensor: shape=(), dtype=float32, numpy=8.0>

现在用tf.function()函数将此Python函数转化为TensorFlow函数

tf_cube=tf.function(cube)
tf_cube
<tensorflow.python.eager.def_function.Function at 0x23900209dc0>

现在可以像原Python函数一样使用此TF函数,并且会返回相同的结果(但作为张量)

tf_cube(2)
<tf.Tensor: shape=(), dtype=int32, numpy=8>
tf_cube(tf.constant(2.0))
<tf.Tensor: shape=(), dtype=float32, numpy=8.0>

在后台,tf.function()分析了cube()函数执行的计算,并生成等效的计算图。另外可以使用tf.function()作为装饰器。

@tf.function
def tf_cube(x):
    return x**3

如果有需要可以通过TF函数的python_function属性使用原Python函数

tf_cube.python_function(2)
8

TensorFlow 可以优化计算图,修建未使用的节点,简化表达式(例如将1+2替换为),等等。准备好优化的图,TF函数会以适当的顺序(并在可能时并行执行)有效地执行图中的操作。因此TF通道函数通常比原始的Python函数运行得更快,尤其是在执行复杂计算的情况下。大多数情况下,不用真正了解很多:
当想要增强Python函数时,只需要将其转换为TF函数即可。

此外,编写的自定义函数、自定义损失、自定义层或任何其他自定义函数,并在Keras模型中使用它,Keras会自动将自定义函数转换为TF函数——不需要使用tf.function()。因此大多数情况,这些处理都是100%透明的。

也可以在创建自定义层或自定义模型时设置dynamic=True来告诉Keras不要将Python函数转换为TF函数。或者可以在调用模型的compile()方法时设置run_eagerly=True

默认情况下,TF函数会为每个不同的输入形状和数据类型集生成一个新图形,并将其缓存以供后续调用。例如,如果调用tf_cube(tf.constant(10))),将形状为[]的int32张量生成图形。如果调用tf_cube(tf.constant(20)),则会重用相同的图。但是如果随后调用tf_cube(tf.constant([10,20])),则会为形状为[2]的int32张量生成一个新图。这就是TF函数处理多态(即变换的参数类型和形状)的方式。但是这仅适用于张量参数:如果将Python数值传递给TF函数,则将为每个不同的值生成一个新图:例如调用tf_cube(10)和tf_cube(20)将生成两个图

如果不同的Python数值多次调用TF函数,则会生成许多图,这会降低程序的运行速度并消耗大量RAM(必须删除TF函数才能释放它)。Python值应该保留给很少有唯一值的参数,例如每层神经元的数量那样的超参数,这使TensorFlow可以更好地优化模型的每个变体。

TF函数规则

大多数情况下,将实行TensorFlow操作的Python函数转换为TF函数很简单,用@tf.function修饰它或让Keras处理。但是有一些规则需要遵守:

  • 如果调用任何外部库,包括NumPy库甚至标准库,此调用将仅在跟踪过程中运行。它不会成为图表的一部分,实际上,TensorFlow图只能包含TensorFlow构造(张量、运算、变量、数据集等)。因此需要使用tf.reduce_sum()函数代替np.sum(),使用tf.sort()代替内置的sorted()函数,以此类推。
  • 如果定义了一个返回np.random.rand()函数的TF函数f(x),则仅在跟踪该函数时才会生成随机数,因此f(tf.constant(2.))和f(tf.constant(3.))将返回相同的随机数,但f(tf.constant([2.,3.]))将返回不同的随机数。如果把np.random.rand()替换为tf.random.uniform([]),则每次操作都会生成一个新的随机数,因为该操作将成为图形的一部分
  • 如果非TensorFlow代码具有副作用(例如记录某些内容或更新Python计数器),那么每次调用TF函数不会发生这些副作用,因为它们只会在跟踪该函数时发生
  • 可以在tf.py_function()操作中包装任何Python代码,但这样会降低性能,因为TensorFlow无法对此代码进行任何图优化。这也会降低可移植性,因为该图仅可在安装了Python(并且安装了正确的库)的平台上运行
  • 可以调用其他Python函数或TF函数,但它们应遵循相同的规则,因为TensorFlow会在计算图中捕捉它们的操作。这些函数不需要@tf.function修饰。
  • 如果该函数创建了一个TensorFlow变量(或任何其他有状态的TensorFlow对象,例如数据集或队列),则必须在第一次调用时这样做,否则会得到一个异常。通常最好在TF函数(例如在自定义层的build()方法中)外部创建变量。如果要为变量分配一个新值,确保调用它的assign方法,而不要使用=运算符
  • Python函数的源代码应可用于TensorFlow。如果源代码不可用(如果,如果在Python shell中定义函数,而该函数不提供对源代码的访问权,或者仅将已编译的*.pyc Python文件部署到环境中),则生成图的过程会失败或功能受限。
  • TensorFlow只能捕获在张量或数据集上迭代的for循环,。因此确保使用for i in tf.range(x),而不是for i in range(x),否则这个循环不会在图中被捕捉。相反它会在跟踪过程中运行。
  • 出于性能原因,应尽可能使用向量化实现,而不是使用循环。
posted @ 2021-10-24 18:41  里列昂遗失的记事本  阅读(73)  评论(0编辑  收藏  举报