TensorFlow核心概念之计算图

什么是计算图

  什么计算图呢?计算图跟图计算不一样,图计算是对基于图数据的计算的统称。而计算图是对一系列计算和数据流转编排之后形成的有向无环图的描述。搞过大数据的应该都对大数据的调度及依赖任务编排比较熟悉,我们会将前后依赖的任务进配置,设置个任务间的依赖关系,然后形成了一个关于各种数据加工和依赖任务的有向无环图(DAG),在这个有向无环图中,图中的顶点(Vertex、Node)是一个个用于执行某种计算的任务,顶点直接的关系(Relationship也就是边,Edge)有的是数据流转,有的是任务依赖。其实TensorFlow中的计算图也基本上类似与这种有DAG图。
  通常一个机器学习任务的核心是定义模型和求解参数,在对模型定义和参数求解过程进行抽象之后,在确定了数据的流转方式、数据的计算方式以及各种计算之间的相互依赖关系之后,就可以确定一个唯一的计算执行逻辑,然后将这个计算执行逻辑用图表示,最后我们称这个有向无环图为计算图。
  TensorFlow中的计算图由点(nodes)和边(edges)组成,节点表示算子,边表示算子间的依赖或数据(一般是张量)的传递方向,其中实线表示有数据传递依赖,传递的数据即为张量;而虚线通常表示控制依赖,即执行先后顺序,不存在数据传递依赖。所有的节点都通过边连接,其中入度为0的节点没有前置依赖,可以立即执行;入度大于0的节点,要等待其前置依赖的所有节点执行结束之后才能执行。下图就是TensorFlow中一个简单的计算图示例:

Compute Graph

  计算图创建好了之后,TensorFlow就会需要启动Session去执行计算图,在TensorFlow中,一个Session可以执行多个计算图,每个计算图之间的执行相互独立。计算图的执行参考了拓扑排序的思想,关于拓扑排序,如果有不清楚的,可以参考我的另外一篇文章——直观理解:拓扑排序。计算图G的执行大体可以分为如下4个步骤:

  • a. 以节点id(node_id)作为key、入度(in_degree)作为value创建哈希表map,并将计算图G中的所有节点(nodes)加入map中。
  • b. 为计算图G创建一个可执行节点队列queue,将map中入度为0的节点加入queue,并从map中删除这些节点。
  • c. 依次执行queue中的每一个节点,执行成功之后将此节点输出指向的节点的入度减1,更新map中对应节点的入度。
  • d. 重复步骤b和c,直至queue为空。

  TensorFlow在发展过程中一共提供了三种计算图的构建方式,分别是静态计算图、动态计算图和AutoGraph。其中静态计算图的构建是TensorFlow在1.0提供的基础功能,但是原生的静态图构建这个功能在TensorFlow2.0之后被弃用,但为了保持对1.0版本的兼容,TensorFlow2.0在compat包中提供了兼容1.0版本的静态图构建方式。关于三种计算图的构建方式的优劣及不同,我们在后面按章节进行详细讲解。

静态计算图

  TensorFlow1.0是采用静态计算图的方式来构建计算图,需先用TensorFlow中的各种算子创建计算图,然后开启一个Session来显式地执行计算图。TensorFlow2.0为了保证对TensorFlow1.0项目的兼容性,在tf.compat.v1子模块中保留了对TensorFlow1.0提供的静态计算图构建方式的支持。但是在TensorFlow2.0中,这种静态图的构建方式已经不被推荐,后面渐渐可能会被舍弃。下面我们以兼容包里的静态计算图构建方式来展示静态计算图的构建方式。代码如下:

import tensorflow as tf

#定义静态计算图g
g = tf.compat.v1.Graph()
with g.as_default():
    #placeholder为占位符,会话执行的时候会填充具体的对象内容
    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=" ")

#开启一个session,执行计算图g
result = None
with tf.compat.v1.Session(graph=g) as sess:
    # fetches的结果非常像一个函数的返回值,而feed_dict中的占位符相当于函数的参数序列。
    result = sess.run(fetches=z, feed_dict={x:"Hello", y:"World!"})

#打印计算结果
tf.print(result)

结果如下:

b'Hello World!'

动态计算图

  动态计算图,也称之为Eager Execution,其和静态计算图最大的区别在于,动态计算图无需显式的定义计算图,然后开启个session来执行,在动态计算图中,默认开启session,所有的算子定义之后立即执行。示例代码如下:

# 动态计算图在每个算子构建后立即执行
x = tf.constant("Hello")
tf.print("x:", x)
y = tf.constant("World!")
tf.print("y:", y)

result = tf.strings.join([x, y], separator=" ")
tf.print("result:", result)

结果如下:

x: "Hello"
y: "World!"
result: "Hello World!"

另外,从模块化和函数化编程的角度出发,也可以将上述的动态计算图进行函数化封装,从而将计算图的输入和输出封装在一个函数里面,示例代码如下:

# 将x,y及result的输入输出关系封装成函数
def str_join(x,y):
    tf.print("x:", x)
    tf.print("y:", y)
    return tf.strings.join([x, y], separator=" ")

result = str_join(tf.constant("Hello"), tf.constant("World!"))
tf.print("result:", result)

结果如下:

x: "Hello"
y: "World!"
result: "Hello World!"

AutoGraph

  使用动态计算图(Eager Execution)的好处是方便代码调试,因为所有的中间过程可以在写代码过程中立即执行并显示结果。但是动态计算图的运行效率相对较低,因为Eager Execution会有许多次Python进程和TensorFlow的C++进程之间的通信。而静态计算图构建完成之后几乎全部在TensorFlow内核上使用C++代码执行,无需与Python进程频繁进行交互通信,因而效率更高。此外静态图会对计算步骤进行一定的优化,省略和结果无关的计算步骤。鉴于此,TensorFlow2.0提供了tf.function让算子从 Eager Execution 切换到静态计算图执行。可以使用@tf.function注解将普通Python函数转换成对应的TensorFlow计算图,而调用该函数就相当于在TensorFlow1.0中开启一个Session执行计算图。这种使用tf.function构建静态图的方式就叫做 Autograph。
  在TensorFlow2.0中,如果采用Autograph的方式使用计算图,第一步需要定义函数,第二步调用函数。无需显示定义计算图,然后显式地开启session去执行计算图,执行计算图变得跟Python中函数的定义和调用一样简单。下面用代码来展示采用Autograph的计算图执行方式,代码如下:

import tensorflow as tf

# 使用autograph构建静态图
@tf.function
def str_join(x, y):
    tf.print("x:", x)
    tf.print("y:", y)
    return tf.strings.join([x, y], separator=" ")

# 调用函数@tf.function装饰的函数,执行计算图
result = str_join(tf.constant("Hello"), tf.constant("World!"))
tf.print("result:", result)

结果如下:

hello world
tf.Tensor(b'hello world', shape=(), dtype=string)

三种计算图对比

  静态计算图,动态计算图和AutoGraph在执行效率和编程体验两方面各有取舍。原始的使用静态计算图需要严格分两步,第一步定义计算图,第二步在会话中执行计算图。而在TensorFlow2.0中,在兼容原始静态图构建方式的同时,新推出了采用Autograph的方式使用计算图,使得计算图的定义和使用分别变成了定义函数和调用函数,兼顾效率的同时,极大的提升了编程体验和效率。关于三种计算图的比较,分别从定义、执行和效率三个方面做了简单的总结:

  • 定义:静态计算图需要严格遵循先定义,后使用的原则,定义过程比较麻烦;而动态计算图和AutoGraph的计算图定义更接近普通的Python任务编程,定义过程比较简单。
  • 执行:静态计算图需要显示开启session后执行,比较麻烦;动态计算图无需显示执行,可以即刻执行并查看中间结果;AutoGraph调用函数即可执行,简单易用,调用后会在后台会按照静态图一样的方式执行。
  • 效率:静态计算图后台有优化策略,效率最高;AutoGraph装饰后的函数也按静态图的方式去执行;动态计算图由于Eager Execution,C++内核和Python内核需要进行频繁的交互,效率最低。
TensorFlow系列文章:
  1. TensorFlow核心概念之Tensor(1):张量创建
  2. TensorFlow核心概念之Tensor(2):索引切片
  3. TensorFlow核心概念之Tensor(3):变换拆合
  4. TensorFlow核心概念之Tensor(4):张量运算
  5. TensorFlow核心概念之计算图
  6. TensorFlow核心概念之Autograph
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,242评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,769评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,484评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,133评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,007评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,080评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,496评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,190评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,464评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,549评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,330评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,205评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,567评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,889评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,160评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,475评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,650评论 2 335

推荐阅读更多精彩内容