TensorFlow2 Eager Execution与AutoGraph模式

导入tensorflow2.6版本

import tensorflow as tf

TensorFlow2 Eager Execution与AutoGraph模式

Eager Execution模式

Eager Execution 介绍:
TensorFlow 的 Eager Execution 模式是一种命令式编程(imperative programming),这和原生
Python 是一致的,当你执行某个操作时,可以立即返回结果的。

Graph 模式介绍:
TensorFlow1.0 一直是采用 Graph 模式,即先构建一个计算图,然后需要开启 Session,喂进实际的
数据才真正执行得到结果。

Eager Execution 模式下,我们可以更容易 debug 代码,但是代码的执行效率更低。
下面我们在 Eager Execution 和 Graph 模式下,用 TensorFlow 实现简单的乘法,来对比两个模式
的区别。

x = tf.ones((2, 2), dtype=tf.dtypes.float32)
y = tf.constant([[1, 2],
 [3, 4]], dtype=tf.dtypes.float32)
z = tf.matmul(x, y)
print(z)
tf.Tensor(
[[4. 6.]
 [4. 6.]], shape=(2, 2), dtype=float32)

在 TensorFlow 2 版本中使用 1.X 版本的语法;可以使用 2.0 中的 v1 兼容包来沿用 1.x 代码,并在代码中关闭 eager运算。

import tensorflow.compat.v1 as tf
tf.disable_eager_execution()
#创建 graph,定义计算图
a = tf.ones((2, 2), dtype=tf.dtypes.float32)
b = tf.constant([[1, 2],
 [3, 4]], dtype=tf.dtypes.float32)
c = tf.matmul(a, b)
#开启绘画,进行运算后,才能取出数据。
with tf.Session() as sess:
    print(sess.run(c))
[[4. 6.]
 [4. 6.]]

首先重启一下 kernel,使得 TensorFlow 恢复到 2.0 版本并打开 eager execution 模式。
EagerExecution 模式的另一个优点是可以使用 Python 原生功能,比如下面的条件判断:

import tensorflow as tf
thre_1 = tf.random.uniform([], 0, 1)
x = tf.reshape(tf.range(0, 4), [2, 2])
print(thre_1)
if thre_1.numpy() > 0.5:
    y = tf.matmul(x, x)
else:
    y = tf.add(x, x)
tf.Tensor(0.15016186, shape=(), dtype=float32)

这种动态控制流主要得益于 eager 执行得到 Tensor 可以取出 numpy 值,这避免了使用 Graph 模式
下的 tf.cond 和 tf.while 等算子。

AutoGraph模式

当使用 tf.function 装饰器注释函数时,可以像调用任何其他函数一样调用它。它将被编译成图,这意味
着可以获得更高效地在在 GPU 或 TPU 上运行。此时函数变成了一个 TensorFlow 中的 operation。
我们可以直接调用函数,输出返回值,但是函数内部是在 graph 模式下执行的,无法直接查看中间变量
数值

@tf.function
def simple_nn_layer(w,x,b):
    print(b)
    return tf.nn.relu(tf.matmul(w, x)+b)
w = tf.random.uniform((3, 3))
x = tf.random.uniform((3, 3))
b = tf.constant(0.5, dtype='float32')
simple_nn_layer(w,x,b)
Tensor("b:0", shape=(), dtype=float32)





<tf.Tensor: shape=(3, 3), dtype=float32, numpy=
array([[1.2551397, 1.4473171, 1.2038846],
       [1.7371726, 2.2272415, 1.8278842],
       [1.6092094, 2.0444825, 1.3084849]], dtype=float32)>

通过输出结果可知,无法直接查看函数内部 b 的数值,而返回值可以通过.numpy()查看。
通过相同的操作(执行一层 lstm 计算),比较 graph 和 eager execution 模式的性能。

#timeit 测量小段代码的执行时间
import timeit
#创建一个卷积层。
CNN_cell = tf.keras.layers.Conv2D(filters=100,kernel_size=2,strides=(1,1))
#利用@tf.function,将操作转化为 graph。
@tf.function
def CNN_fn(image):
    return CNN_cell(image)
image = tf.zeros([50, 200, 200, 3])
#比较两者的执行时间
CNN_cell(image)
CNN_fn(image)
#调用 timeit.timeit,测量代码执行 10 次的时间
print("eager execution 模式下做一层 CNN 卷积层运算的时间:", timeit.timeit(lambda: CNN_cell(image),
number=10))
print("graph 模式下做一层 CNN 卷积层运算的时间:", timeit.timeit(lambda: CNN_fn(image), number=10))
eager execution 模式下做一层 CNN 卷积层运算的时间: 0.005434300000160874
graph 模式下做一层 CNN 卷积层运算的时间: 0.006525300000021161

通过比较,我们可以发现 graph 模式下代码执行效率要高出许多。
因此我们以后,可以多尝试用@tf.function 功能,提高代码运行效率。

内容来自于华为HCIA AI 3.0实验手册

猜你喜欢

转载自blog.csdn.net/weixin_63936336/article/details/128191996
今日推荐