主要介绍TensorFlow的基础语法及功能函数。学完后,TensorFlow代码对您来说将不再陌生,您可以很轻易看懂相关代码,并可以尝试写一些简单的模型或算法。
学习一个开发环境,应先从其内部入手,这样会起到事半功倍的效果。本章先从编程模型开始了解其运行机制,然后再介绍TensorFlow常用操作及功能函数,最后是共享变量、图和分布式部署。
编程模型
TensorFlow的命名来源于本身的运行原理。Tensor(张量)
意味着N维数组
,Flow(流)
意味着基于数据流图的计算。TensorFlow是张量从图像的一端流动到另一端的计算过程,这也是TensorFlow的编程模型。
了解模型的运行机制
TensorFlow的运行机制属于“定义”与“运行”相分离。从操作层面可以抽象成两种:模型构建和模型运行。在模型构建过程中,需要先了解几个概念,如图所示。
图中定义的内容都是在一个叫做“图”的容器中完成的。关于“图”,有以下几点需要理解。
一个“图”代表一个计算任务。
在模型运行的环节中,“图”会在会话(session)里被启动。
session将图的OP分发到如CPU或GPU之类的设备上,同时提供执行OP的方法。这些方法执行后,将产生的tensor返回。在Python语言中,返回的tensor是numpy ndarray对象;在C和C++语言中,返回的tensor是TensorFlow:Tensor实例。
在实际环境中,这种运行情况会有3种应用场景,分别是训练场景、测试场景与使用场景。在训练场景下图的运行方式与其他两种不同,具体介绍如下。
(1)训练场景:是实现模型从无到有的过程,通过对样本的学习训练,调整学习参数,形成最终的模型。其过程是将给定的样本和标签作为输入节点,通过大量的循环迭代,将图中的正向运算(从输入的样本通过OP运算得到输出的方向)得到的输出值,再进行反向运算(从输出到输入的方向),以更新模型中的学习参数,最终使模型产生的正向结果最大化地接近样本标签。这样就得到了一个可以拟合样本规律的模型。
(2)测试场景和使用场景:测试场景是利用图的正向运算得到的结果与真实值进行比较的差别;使用场景也是利用图的正向运算得到结果,并直接使用。所以二者的运算过程是一样的。对于该场景下的模型与正常编程用到的函数特别相似。在函数中,可以分为实参、形参、函数体与返回值。同样在模型中,实参就是输入的样本,形参就是占位符,运算过程就相当于函数体,得到的结果相当于返回值。另外,session与图的交互过程中还定义了以下两种数据的流向机制。
- 注入机制(feed):通过占位符向模式中传入数据。
- 取回机制(fetch):从模式中得到结果。
下面通过实例逐个演示session在各种情况下的用法。先从session的建立开始,接着演示session与图的交互机制,最后演示如何在session中指定GPU运算资源。
实例1,编写hello world
程序演示session
的使用
下面先从一个hello world开始来理解session的作用。
实例描述
建立一个session,在session中输出hello。
import tensorflow as tf
hello = tf.constant('Hello, TensorFlow!') #定义一个常量
sess = tf.Session() #建立一个session
print (sess.run(hello)) #通过session里面run函数来运行结果
sess.close() #关闭session
运行代码会得到如下输出:
b'Hello, TensorFlow!'
- tf.constant定义的是一个常量,hello的内容只有在session的run内才可以返回。
可以试着在2和3行之间加入print(hello)
看一下效果,这时并不能输出hello的内容。接下来换种写法,使用with语法来开启session。
实例2:演示with session
的使用
with session的用法是最常见的,它沿用了Python中with的语法,即当程序结束后会自动关闭session,而不需要再去写close。代码如下。
实例描述
使用with session方法建立session,并在session中计算两个变量(3和4)的相加与相乘值。
import tensorflow as tf
a = tf.constant(3) #定义常量3
b = tf.constant(4) #定义常量4
with tf.Session() as sess: #建立session
print ("相加: %i" % sess.run(a+b))
print( "相乘: %i" % sess.run(a*b))
运行后得到如下输出:
相加: 7
相乘: 12
实例3:演示注入机制
扩展上面代码:使用注入机制,将具体的实参注入到相应的placeholder中。feed只在调用它的方法内有效,方法结束后feed就会消失。
实例描述
定义占位符,使用feed机制将具体数值(3和4)通过占位符传入,并进行相加和相乘运算。
01 import tensorflow as tf
02 a = tf.placeholder(tf.int16)
03 b = tf.placeholder(tf.int16)
04 add = tf.add(a, b)
05 mul = tf.multiply(a, b) #a与b相乘
06 with tf.Session() as sess:
07 #计算具体数值
08 print ("相加: %i" % sess.run(add, feed_dict={a: 3, b: 4}))
09 print ("相乘: %i" % sess.run(mul, feed_dict={a: 3, b: 4}))
运行代码,输出如下:
相加:7
相乘:12
标记的方法是:使用tf.placeholder为这些操作创建占位符,然后使用feed_dict把具体的值放到占位符里。
注意: 关于feed中的feed_dict还有其他的方法,如update等,在后面的例子中用到时还会介绍,这里只是介绍最常用的方法。
建立session 的其他方法
建立session还有以下两种方式。
交互式session方式:一般在Jupyter环境下使用较多,具体用法与前面的with session类似。代码如下:
sess = tf.InteractiveSession()
使用
Supervisor
方式:该方式会更高级一些,使用起来也更加复杂,可以自动来管理session中的具体任务,例如,载入/载出检查点文件、写入TensorBoard等,另外该方法还支持分布式训练的部署(在本书的后面会有介绍)。
实例4:使用注入机制获取节点
在实例3中,其实还可以一次将多个节点取出来。例如,在最后一句可以加上以下代码:
实例描述
使用fetch机制将定义在图中的节点数值算出来。
10 ……
11 mul = tf.multiply(a, b)
12 with tf.Session() as sess:
13 #将op运算通过run打印出来
14 print ("相加: %i" % sess.run(add, feed_dict={a: 3, b: 4}))#将add节点打印出来
15 print ("相乘: %i" % sess.run(mul, feed_dict={a: 3, b: 4}))
16 print (sess.run([mul, add], feed_dict={a: 3, b: 4}))
运行代码,输出如下:
相加: 7
相乘: 12
[12, 7]