03_TensorFlow2计算图:揭秘AI大脑背后的‘织梦师’,让数据跳舞的魔法秘籍!

在这里插入图片描述

1. 计算图

图是 TensorFlow 最基本的结构,一切计算都是基于图结构运行的,图结构包含张量(Tensor)和操作(Operation)。TensorFlow 1.x 采用的是静态计算图,需要先创建计算图,然后再开启会话 Session,显式执行计算图。在 TensorFlow 2.0 中,采用的是动态计算图,即每使用一个算子后,该算子会被动态加入到默认计算图中即执行,无需开启 Session。

使用动态计算图即 Eager Excution 的优势是方便程序调试。使用动态计算图的缺点是运行效率相对会低一些。因为使用动态图会有许多次 Python 进程和 TensorFlow 的 C++ 进程之间的通信。而静态计算图构建完成之后几乎全部在 TensorFlow 内核上使用 C++ 代码执行,效率更高。此外静态图会对计算步骤进行一定的优化,剪去与结果无关的计算步骤。

如果需要在 TensorFlow 2.0 中使用静态图,可以使用 @tf.function 装饰器将普通 Python 函数转换成对应的 TensorFlow 计算图构建代码。运行该函数就相当于在 TensorFlow 1.x 中使用 Session 执行代码。使用 tf.function 构建静态图的方式叫做 Autograph。

计算图由节点(nodes)和线(edges)组成。节点表示操作符 Operator,线表示计算间的依赖关系。实线表示有数据传递依赖,传递的数据即张量。虚线通常可以表示控制依赖,即执行先后顺序。

在这里插入图片描述

2. 静态计算图

静态计算图:静态计算则意味着程序在编译执行时将先生成神经网络的结构,然后再执行相 应操作。从理论上讲,静态计算这样的机制允许编译器进行更大程度的优化,但是这也意味 着你所期望的程序与编译器实际执行之间存在着更多的代沟。这也意味着,代码中的错误将 更加难以发现(比如,如果计算图的结构出现问题,你可能只有在代码执行到相应操作的时 候才能发现它)。

import tensorflow as tf

g = tf.compat.v1.Graph()

with g.as_default():
    x = tf.compat.v1.placeholder(name='x', shape=[], dtype=tf.string)
    y = tf.compat.v1.placeholder(name='y', shape=[], dtype=tf.string)
    z = tf.strings.join([x,y], name='join', separator=" ")
    
with tf.compat.v1.Session(graph=g) as sess:
    # fetches的结果非常像一个函数的返回值,而feed_dict中的占位符相当于函数的参数序列。
    result = sess.run(fetches = z,feed_dict = {x:"hello",y:"world"})
    print(result) 
b'hello world'

3. 动态计算图

动态计算图:动态计算意味着程序将按照我们编写命令的顺序进行执行。这种机制将使得调试更加容易,并且也使得我们将大脑中的想法转化为实际代码变得更加容易。

# 动态计算图在每个算子处都进行构建,构建后立即执行
x = tf.constant("hello")
y = tf.constant("world")
z = tf.strings.join([x,y], separator=" ")
tf.print(z)
hello world

4. AutoGraph

TensorFlow 2.0主要使用的是动态计算图和Autograph。而Autograph机制可以将动态图转换成静态计算图,兼收执行效率和编码效率之利。动态计算图易于调试,编码效率较高,但执行效率偏低。静态计算图执行效率很高,但较难调试。而Autograph机制通过@tf.function装饰器,可以将动态图转换成静态计算图,达到兼顾执行效率和编码效率的目的。AutoGraph将Python控制流转换为TensorFlow表达式,允许用户在装饰有tf.function的函数中编写常规Python,例如while,if,break,continue和return,支持嵌套。这意味着可以在while和if语句的条件下使用Tensor表达式,或者在for循环中迭代Tensor。当然Autograph机制能够转换的代码并不是没有任何约束的,有一些编码规范需要遵循,否则可能会转换失败或者不符合预期,在使用过程中有以下三个注意事项:

  • 使用tf内部函数,避免直接使用python函数,因为无法嵌入进计算图;
  • 避免定义 tf.Variable, 以为它是动态的,每次迭代都会更新;
  • 不可以修改列表字典等数据结构
import tensorflow as tf
import numpy as np 
 
@tf.function(autograph=True)
def myadd(a,b):
    for i in tf.range(3):
        tf.print(i)
    c = a+b
    print("tracing")
    return c

程序运行会经历两个步骤:

第一步,会创建一个静态计算图,跟踪执行一遍函数体中的Python代码,确定各个变量的Tensor类型,并根据执行顺序将算子添加到计算图中。 在这个过程中,如果开启了autograph=True(默认开启),会将Python控制流转换成TensorFlow图内控制流。主要是将if语句转换成tf.cond算子表达,将while和for循环语句转换成tf.while_loop算子表达,并在必要的时候添加tf.control_dependencies指定执行顺序依赖关系。

第二步,执行计算图。

# 第一次调用函数
myadd(tf.constant("hello"),tf.constant("world"))
tracing
0
1
2





<tf.Tensor: shape=(), dtype=string, numpy=b'helloworld'>
# 第二次调用函数,只进行第二步,执行计算图。因此打印结果中没有"tracing"。
myadd(tf.constant("hello"),tf.constant("world")) 
0
1
2





<tf.Tensor: shape=(), dtype=string, numpy=b'helloworld'>
# 第三次调用函数,由于输入参数的类型已经发生变化,已经创建的计算图不能够再次使用。需要重新创建新的计算图、执行计算图。
myadd(tf.constant(1),tf.constant(2))   
tracing
0
1
2





<tf.Tensor: shape=(), dtype=int32, numpy=3>
# 如果调用被@tf.function装饰的函数时输入的参数不是Tensor类型,则每次都会重新创建计算图。
myadd("hello","world")  
tracing
0
1
2





<tf.Tensor: shape=(), dtype=string, numpy=b'helloworld'>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

腾飞开源

你的鼓励将是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值