前言:
本章将学习TensorFlow中最基本的一些概念。
一、TensorFlow的计算模型——计算图
1.1 计算图的概念
计算图是TensorFlow中最基本的一个概念,TensorFlow中的所有计算都会被转化为计算图上的节点。TensorFlow的名字中已经说明了它最重要的两个概念一Tensor和Flow。Tensor就是张量。在TensorFlow中,张量可以被简单地理解为多维数组,如果说TensorFlow的第一个词Tensor表明了它的数据结构,那么Flow则体现了它的计算模型。Flow翻译成中文就是“流”,它直观地表达了张量之间通过计算相互转化的过程。TensorFlow是一个通过计算图的形式来表述计算的编程系统。TensorFlow 中的每一个计算都是计算图上的一个节点,而节点之间的边描述了计算之间的依赖关系。下图展示了通过TensorBoard画出来的第2章中两个向量相加样例的计算图。
上图中的每一个节点都是一个运算,而每一条边代表了计算之间的依赖关系。如果一个运算的输入依赖于另一个运算的输出,那么这两个运算有依赖关系。在图中,a和b这两个常量不依赖任何其他计算。而add计算则依赖读取两个常量的取值。于是在图中可以看到有一条从a到add的边和一条从b到add的边。在图中,没有任何计算依赖 add的结果,于是代表加法的节点add没有任何指向其他节点的边。所有TensorFlow的程序都可以通过类似上图所示的计算图的形式来表示,这就是TensorFlow的基本计算模型。
1.2 计算图的使用
TensorFlow程序一般可以分为两个阶段 。在第一个阶段需要定义计算图中所有的计算。比如在向量加法样例程序中首先定义了两个输入,然后定义了一个计算来得到它们的和。第二个阶段为执行计算。以下代码给出了计算定义阶段的样例:
import tensorflow as tf a = tf.constant([1.0,2.0],name='a') b= tf.constant([2.0,3.0],name='b') result = a + b
Python中一般会采用”import tensorflow as tf“的形式来载入TensorFlow,这样可以使用“tf''来代替“tensorflow”作为模块名称,使得整个程序更加简洁。这是TensorFlow中非常常用的技巧。 在这个过程中, TensorFlow会自动将定义的计算转化为计算图上的节点。在TensorFlow程序中, 系统会自动维护一个默认的计算图,通过 tf.get_default_graph函数可以获取当前默认的计算图。以下代码示意了如何获取默认计算图以及如何査看一个运算所属的计算图:
#coding=gbk import tensorflow as tf a = tf.constant([1.0,2.0],name='a') b= tf.constant([2.0,3.0],name='b') result = a + b ### 通过*.graph可以查看张量所属的计算图。因为没有特意指定,所以这个计算图应该等于当前默认的计算图 print(a.graph) print(b.graph) print(result.graph) print(tf.get_default_graph()) print(result.graph is tf.get_default_graph() )
结果如下:
二、TensorFlow的数据模型——张量
从TensorFlow的名字就可以看出张量(tensor)是一个很重要的概念。在TensorFlow程序中,所有的数据都通过张量的形式来表示。从功能的角度上看,张量可以被简单理解为多维数组。其中零阶张量表示标量(scalar),也就是一个数;第一阶张量为向量(vector),也就是一个一维数组; 第 n阶张量可以理解为一个 n维数组。但张量在TensorFlow中的实现并不是直接采用数组的形式,它只是对TensorFlow中运算结果的引用。在张量中并没有真正保存数字,它保存的是如何得到这些数字的计算过程。还是以向量加法为例,当运行如下代码时,并不会得到加法的结果, 而会得到对结果的一个引用:
#coding=gbk import tensorflow as tf a = tf.constant([1.0,2.0],name='a') b= tf.constant([2.0,3.0],name='b') #在传统的程序操作中,定义了t的运算,在运行时就执行了,并输出17。 #而在Tensorflow中,计算图中的节点,实际上对应的是Tensorflow API中的一个操作,并没有真正去运行 result0 = 8 + 9 print(result0) result1 = tf.add(a,b,name="add") print(result1) #也可以写成下面这种形式,它们是等价的 result2 = a + b print(result2)
运行程序,结果如下:
从上面的代码可以看出TensorFlow中的计算的结果不是一个具体的数字,而且一个张量的结构。从上面代码的运行结果可以看出, 一个张量中主要保存了三个属性:名字(name)、维度(shape)和类型(type)。
(1)张量的第一个属性名字不仅是一个张量的唯一标识符,它同样也给出了这个张量是如何计算出来的。TensorFlow的计算都可以通过计算图的模型来建立,而计算图上的每一个节点代表了一个计算,计算的结果就保存在张量之中。所以张量和计算图上节点所代表的计算结果是对应的。这样张量的命名就可以通过“ node:src_output“的形式来给出。其中 node为节点的名称, src_output表示当前张量来自节点的第几个输出。比如上面代码打出来的“add:0“就说明了result这个张量是计算节点“add”输出的第一个结果(编号从0开始)。
(2)张量的第二个属性是张量的维度(shape)。这个属性描述了一个张量的维度信息。比如上面样例中 shape(2, )说明了张量 result是一个一维数组,这个数组的长度为2。维度是张量一个很重要的属性, 围绕张量的维度TensorFlow也给出了很多有用的运算。
(3) 张量的第三个属性是类型(type),每一个张量会有一个唯一的类型。TensorFlow会对参与运算的所有张量进行类型的检査, 当发现类型不匹配时会报错 。
如果将第一个加数a指定成整数类型“ a= tf.constant([1, 2], name="a", dtype==tf.int32)”,那么两个加数的类型不相同就会报错了。如果不指定类型,TensorF1ow会给出默认的类型,比如不带小数点的数会被默认为int32,带小数点的会默认为float32。因为使用默认类型有可能会导致潜在的类型不匹配问题,所以一般建议通过指定dtype来明确指出变量或者常量的类型。TensorFlow支持14种不同的类型,主要包括了:
实数(tf.float32、tf.f1oat64)、整数(tf.int8、tf.int16、tfint32、tf.int64、tf.uint8)、布尔型(tf.bool)和复数(tf.complex64、tf.complexl28 ) 。
三、TensorFlow的运行模型——会话
本节将介绍如何使用TensorFlow中的会话(session)来执行定义好的运算。会话拥有并管理TensorFlow程序运行时的所有资源。当所有计算完成之后需要关闭会话来帮助系统回收资源,否则就可能出现资源泄漏的问题。启动计算图的第一步是创建一个Session对象,会话(Session)提供在计算图中执行操作的一些方法。一般的模式是,建立会话,此时会生成一张空图,在会话中添加节点和边,形成一张图,然后执行。TensorFlow 中使用会话的模式一般有两种,第一种模式需要明确调用会话生成函数和关闭会话函数,这种模式的代码流程如下:
#coding=gbk import tensorflow as tf a = tf.constant([1.0,2.0],name='a') b= tf.constant([2.0,3.0],name='b') #而在Tensorflow中,计算图中的节点,实际上对应的是Tensorflow API中的一个操作,并没有真正去运行 #首先创建一个会话 sess = tf.Session() #使用这个创建好的会话来得到关心的运算的结果,比如可以调用sess.run(result), #来得到张量result的取值 result = tf.add(a,b,name="add") print(sess.run(result)) #关闭会话使得本次运行中使用到的资源可以被释放 sess.close()
运行程序,结果如下:
使用这种模式时,在所有计算完成之后,需要明确调用Session.close函数来关闭会话并释放资源。然而,当程序因为异常而退出时, 关闭会话的函数可能就不会被执行从而导致资源泄漏。为了解决异常退出时资源释放的问题,TensorF1ow可以通过Python的上下文管理器来使用会话。以下代码展示了如何使用这种模式:
#coding=gbk import tensorflow as tf a = tf.constant([1.0,2.0],name='a') b= tf.constant([2.0,3.0],name='b') #而在Tensorflow中,计算图中的节点,实际上对应的是Tensorflow API中的一个操作,并没有真正去运行 #首先创建一个会话,并通过python中的上下文管理器来管理这个会话 with tf.Session() as sess: result = tf.add(a,b,name="add") print(sess.run(result)) # 这中模式不需要调用“Session.close()”函数来关闭会话 # 当上下文退出时会话关闭和资源释放也自动完成了
python上下文管理器的机制,只要将所有的计算放在“with”的内部就可以。当上下文管理器退出时候会自动释放所有资源。这样既解决了因为异常退出时资源释放的同题,同时也解决了忘记调用 Session.c1ose函数而产生的资源泄。
参考文献:
[1] 郑泽宇编 《TensorFlow实战Google深度学习框架》