关于tf.function简述

目录
本文主要粗浅的讲解tf.function的相关内容,主要分为两块内容,一是tf.function的作用(为什么要有tf.function)。二是在使用tf.function时需要注意的点(tf.function的一些特性)

tf.function的作用
通过对比 tf1.x 与 tf2.x eager 与 tf2.x tf.functon进行说明tf.function的作用

tf.1.x
首先从tf1.x的代码风格说起,在tf1.x中,我们需要自行创建一个graph,再把其加载进tf.Session中,最后使用tf.Session.run方法开始计算(下面的例子很清晰的说明了tf1.x中Graph的创建与计算流程)

with g.as_default():
a = tf.constant([[10,10],[11.,1.]])
x = tf.constant([[1.,0.],[0.,1.]])
y = tf.matmul(a, x) + b
init_op = tf.global_variables_initializer()

with tf.Session() as sess:
sess.run(init_op)
print(sess.run(y))
tf.2.x eager
但是在tf2.x中,默认的Eager execution代码风格发生了很大的变化,具体表现在:1)移除了关于graph的定义 ;2)移除了session执行;3)移除了变量初始化;4)移除了通过scope实现variable sharing;5)移除tf.control_dependencies以执行没有依赖关系连接的顺序操作。如下方代码所示:

a = tf.constant([[10,10],[11.,1.]])
x = tf.constant([[1.,0.],[0.,1.]])
y = tf.matmul(a, x) + b
print(y.numpy())
tf2.x tf.functon
tf.function本质上就是一个函数修饰器,它能够帮助将用户定义的python风格的函数代码转化成高效的tensorflow计算图(可以理解为:之前tf1.x中graph需要自己定义,现在tf.function能够帮助一起定义)。转换的这个过程称为AutoGraph。如下方代码所示:

@tf.function
def f():
a = tf.constant([[10,10],[11.,1.]])
x = tf.constant([[1.,0.],[0.,1.]])
y = tf.matmul(a, x)
return y
f()
我们可以先来简单的了解下tf.function修饰器具体做了哪些工作?

该函数被执行和跟踪(tracing). Eager模型被关闭禁用,所有的tf.api方法都被当做tf.Operation来构建Graph,并产生tf.Tensor output
AutoGraph被用于检测代码中是否存在能够被转换为graph的等价操作(while -> tf.while, for -> tf.for, if -> tf.cond, assert -> tf.assert, …)
经过上述两步后,为了保证graph中语句的执行顺序,tf.control_dependencies被自动加入到代码中,保证第i行执行完后执行第i+1行
创建tf.Graph对象,并根据函数名称和输入参数,创建与Graph相关联的唯一ID,并被加载进一个map中:map[id] = graph
对于任何一个函数的调用,都会重复调用cache中的graph
小结
通过上述的 tf1.x与tf2.x eager与tf2.x tf.functon的对比,我们已经大概知道了tf.function的具体作用(在保证代码易读以及易写的前提下提升执行效率)。接下来将简单介绍在使用tf.function时需要注意的一些点(帮助我们高效的使用tf.function,提升执行效率)

使用tf.function时需要注意的点
tf.variable只会被创建一次
首先来看下面一段代码:

@tf.function
def f():
a = tf.constant([[10,10],[11.,1.]])
x = tf.constant([[1.,0.],[0.,1.]])
b = tf.Variable(12.)
y = tf.matmul(a, x) + b
return y
f()

执行报错如下:

ValueError: tf.function-decorated function tried to create variables on non-first call.

为啥会报错呢?是因为tf.function可能会对一段python代码进行多次执行来进行graph的构建,在多次的执行过程中,Variable被创建了多次,而tensorflow 2.x文档中明确指出State (like tf.Variable objects) are only created the first time the function f is called.。所以就报错了。

因此我们在构建被tf.function修饰的函数时,一定要记得保证每一个tf.Variable变量只被创建一次,否则就有可能报错。那么关于上述报错代码,正确的写法应该是怎样呢?(如下)

class F():
def init(self):
self._b = None
@tf.function
def call(self):
a = tf.constant([[10, 10], [11., 1.]])
x = tf.constant([[1., 0.], [0., 1.]])
if self._b is None:
self._b = tf.Variable(12.)
y = tf.matmul(a, x) + self._b
print("PRINT: ", y)
tf.print("TF-PRINT: ", y)
return y
f = F()
f()

执行结果如下

<tf.Tensor: shape=(2, 2), dtype=float32, numpy=array([[22., 22.], [23., 13.]], dtype=float32)>

参数类型与参数值决定是否创建新的graph
tf.function的最终会创建一个具有唯一标识ID的graph,如下代码所示:

@tf.function
def f(x):
return x + 1

1为传入f(x)的参数值

isinstance(f.get_concrete_function(1).graph, tf.Graph)

执行结果如下

True

通常被修饰的函数的参数类型与参数值会决定是否创建新的graph。我们可以分为传入参数类型是tf.Tensor与原始python类型两种情况讨论。

当传入参数类型是tf.Tensor时
当传入不同类型、相同shape、相同参数值的tf.Tensor值时
@tf.function
def f(x):
return x + 1
vector = tf.constant([1], dtype=tf.int32)
matrix = tf.constant([1.0], dtype=tf.float32)
f.get_concrete_function(vector) is f.get_concrete_function(matrix)

执行结果如下

False

当传入相同类型、不同shape、相同参数值的tf.Tensor值时
@tf.function
def f(x):
return x + 1
vector = tf.constant([1.0], dtype=tf.float32)
matrix = tf.constant([[1.0]], dtype=tf.float32)
f.get_concrete_function(vector) is f.get_concrete_function(matrix)

执行结果如下

False

当传入相同类型、相同shape、不同参数值的tf.Tensor值时
@tf.function
def f(x):
return x + 1
vector = tf.constant([1.0], dtype=tf.float32)
matrix = tf.constant([3.0], dtype=tf.float32)
f.get_concrete_function(vector) is f.get_concrete_function(matrix)

执行结果如下

True

因此当传入参数类型是tf.Tensor时,我们可以得出结论:类型与shape决定了新建还是复用graph

  1. 当传入参数类型是原始python时

传入不同类型、相同shape、相同参数值时
@tf.function
def f(x):
return tf.abs(x)
f1 = f.get_concrete_function(1)
f2 = f.get_concrete_function(1.0)
f1 is f2

执行结果如下

True

传入相同类型、不同shape、相同参数值时
@tf.function
def f(x):
return tf.abs(x)
f1 = f.get_concrete_function([1])
f2 = f.get_concrete_function(1)
f1 is f2

执行结果如下

False

传入相同类型、相同shape、不同参数值时
@tf.function
def f(x):
return tf.abs(x)
f1 = f.get_concrete_function(1)
f2 = f.get_concrete_function(2)
f1 is f2

执行结果如下

False

因此当传入参数类型是原始python类型时,我们可以得出结论,值与shape决定了新建还是复用graph

建议:在使用tf.function时,要本着尽可能复用graph的原则,因为新建graph耗时且耗资源

  1. 每一次trace的过程(即tf.function创建graph的过程),python风格语句只会被执行一次

在被tf.function修饰的函数体中,代码可以大概分为两类,其一为python风格的代码(比如print()),其二为tensorflow风格的代码(比如tf.print)。对于python风格的语句,只有在新建graph的过程才会被执行一次(复用graph时则不会被执行)。如下代码所示:

@tf.function
def f(a, b):
print(‘this runs at trace time; a is’, a, ‘and b is’, b)
return b

f(1, tf.constant(1))

执行结果如下

this runs at trace time; a is 1 and b is Tensor(“b:0”, shape=(), dtype=int32)

<tf.Tensor: shape=(), dtype=int32, numpy=1>

f(1, tf.constant(2))

执行结果如下

<tf.Tensor: shape=(), dtype=int32, numpy=2>

f(2, tf.constant(1))

执行结果如下

this runs at trace time; a is 2 and b is Tensor(“b:0”, shape=(), dtype=int32)

<tf.Tensor: shape=(), dtype=int32, numpy=1>

f(2, tf.constant(2))

执行结果如下

<tf.Tensor: shape=(), dtype=int32, numpy=2>

总结
本文主要从tf.function的作用以及tf.function的一些特性两个方面进行简单讲解。事实上关于使用tf.function进行Autograph的创建是一个比较的复杂的过程,还包括tf.function具体是如何修饰函数的(过程细节)、以及如何高效的利用tf.function等多个需要探讨的点

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: tf.function 是 TensorFlow 中的一个装饰器,用于将 Python 函数转换为 TensorFlow 图中的计算。这个装饰器可以帮助提高 TensorFlow 模型的性能,并且还可以让代码更加简洁。使用 tf.function 时,TensorFlow 会将函数内的 Python 代码编译成高效的机器代码,并将其存储在图中,以便在训练或预测时快速调用。这样可以大大提高模型的运行效率,尤其是在使用 GPUs 或 TPUs 时。 例如,你可以这样使用 tf.function: ``` import tensorflow as tf @tf.function def add(a, b): return a + b print(add(tf.ones([2, 2]), tf.ones([2, 2]))) # [[2., 2.], [2., 2.]] ``` 在这个例子中,add 函数被装饰为 tf.function,并且它将输入张量 a 和 b 相加。使用 @tf.function 装饰器后,TensorFlow 会将 add 函数编译成图中的计算。调用 add 函数时,TensorFlow 会直接在图中执行这个计算,而不是调用 Python 代码。这样可以大大提高运行效率。 ### 回答2: `tf.function` 是 TensorFlow 中的一个装饰器,可以用来将 Python 函数转换为 TensorFlow 图形计算函数。通过使用 `tf.function`,可以将函数转换为优化的图形计算表示形式,以提高计算效率。 使用它的主要目的是为了利用 TensorFlow 的 Autograph 机制,将普通的 Python 代码转换为 TensorFlow 的图计算代码。通过将 Python 函数转换为 TensorFlow 图计算图,可以获得更高的计算速度和更好的分布式计算能力。 使用 `tf.function` 可以带来以下优势: 1. 基于图计算的加速:由于图计算可以提前定义运算逻辑,优化和决定计算顺序,所以相对于直接执行 Python 代码,图计算能够提供更高效的计算速度。 2. 自动跟踪:`tf.function` 可以自动跟踪函数的执行,以获得函数的计算流程,并将其转换为对应的 TensorFlow 图计算图。这意味着我们可以在 Python 函数中使用循环、条件语句等控制流结构,而不需要手动转换为 TensorFlow 的控制流函数。 3. 分布式计算的支持:通过将函数转换为 TensorFlow 图计算图,可以方便地在分布式计算环境中运行函数,以提高计算效率和性能。 以下是 `tf.function` 的基本用法: ```python import tensorflow as tf @tf.function def my_function(x): y = tf.square(x) return y x = tf.constant([1, 2, 3]) result = my_function(x) print(result) ``` 在上述代码中,我们定义了一个函数 `my_function`,并使用 `tf.function` 将其转换为 TensorFlow 图计算函数。然后,我们传入一个 TensorFlow 常量 `x`,并调用 `my_function` 来执行计算。最后,我们打印出计算结果。 ### 回答3: tf.function是TensorFlow 2.0引入的一个重要功能,用于将Python函数转换为TensorFlow的计算图,从而提高模型训练和推理的性能。 tf.function使用了Autograph技术,可以动态地将Python函数转换为可以在TensorFlow计算图中运行的图形化表示。通过使用@tf.function装饰器,可以将普通的Python函数转变为高效的TensorFlow计算图函数。 使用tf.function可以带来多个优点。首先,通过将计算过程转换为计算图的方式,可以减少函数调用之间的Python解释器开销,提高代码的执行效率。 其次,tf.function还提供了TensorFlow运算的自动并行化功能。TensorFlow可以在计算图中自动识别并行化的机会,例如将独立计算的子图并行运行,从而充分利用了现代GPU的并行计算能力,提高计算效率。 此外,通过将函数转换为计算图的格式,tf.function还提供了模型的序列化和导出的功能,使得模型可以在不同的环境中进行轻松部署和共享。 然而,使用tf.function也有一些限制。由于计算图需要静态展开,因此在使用tf.function时,函数中不支持使用Python的动态控制流程,例如if条件语句和for/while循环等。此外,由于计算图需要满足静态类型规则,因此函数的输入参数和返回值类型必须是固定的。 综上所述,tf.function是TensorFlow中的一个重要工具,可以将Python函数转换为高效的TensorFlow计算图函数,从而提高模型训练和推理的性能。然而,在使用tf.function时需要注意一些限制,并且合理使用tf.function可以获得最佳的性能提升效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值