TensorFlow快速上手及TensorBoard使用

4.1  编程模型
TensorFlow的命名来源于本身的运行原理。Tensor(张量)意味着N维数组,Flow(流)意味着基于数据流图的计算。TensorFlow是张量从图像的一端流动到另一端的计算过程,这也是TensorFlow的编程模型。
4.1.1  了解模型的运行机制
TensorFlow的运行机制属于“定义”与“运行”相分离。从操作层面可以抽象成两种:模型构建和模型运行。
在模型构建过程中,需要先了解几个概念,见表4-1。

                                                  表4-1  模型构建中的概念

TensorFlow快速上手及TensorBoard使用

● 一个“图”代表一个计算任务。
● 在模型运行的环节中,“图”会在绘话(session)里被启动。
● session将图的 OP 分发到诸如CPU或GPU之类的设备上, 同时提供执行OP的方法。这些方法执行后,将产生的tensor返回。在Python语言中,返回的tensor是numpy ndarray对象;在C和C++语言中,返回的tensor是TensorFlow::Tensor实例。
如图4-1表示了session与图的工作关系。
TensorFlow快速上手及TensorBoard使用
                                                 图4-1 session与图
在实际环境中,这种运行情况会有三种应用场景,训练场景、测试场景与使用场景。在训练场景下图的运行方式与其他两种不同,具体介绍如下:
(1)训练场景:主要是实现模型从无到有的过程,通过对样本的学习训练,调整学习参数,形成最终的模型。其过程是将给定的样本和标签作为输入节点,通过大量的循环迭代,将图中的正向运算得到输出值,再进行反向运算更新模型中的学习参数。最终使模型产生的正向结果最大化的接近样本标签。这样就得到了一个可以拟合样本规律的模型。
(2)测试场景和使用场景:测试场景是利用图的正向运算得到结果比较与真实值的产别;使用场景也是利用图的正向运算得到结果,并直接使用。所以二者的运算过程是一样的。对于该场景下的模型与正常编程用到的函数特别相似。大家知道,在函数中,可以分为:实参、形参、函数体与返回值。同样在模型中,实参就是输入的样本,形参就是占位符,运算过程就相当于函数体,得到的结果相当于返回值。
另外session与图的交互过程中,还定义了两种数据的流向机制:
● 注入机制(feed):通过占位符向模式中传入数据;
● 取回机制(fetch):从模式中得到结果。
下面通过实例逐个演示session在各种情况下的用法。先从session的建立开始,接着演示session与图的交互机制,最后演示如何在session中指定GPU运算资源。
4.1.2  实例5:编写hello world演示session的使用
先从一个hello world开始来理解Session的作用。
案例描述
建立一个session,在session中输出helloworld。

代码4-1  sessionhello

TensorFlow快速上手及TensorBoard使用

运行代码4-1会得到如下输出:

TensorFlow快速上手及TensorBoard使用

tf.constant定义的是一个常量,hello的内容只有在session的run内才可以返回。
可以试着在2和3行之间加入print(hello)看一下效果,这时并不能输出hello的内容。
接下来换种写法,使用with语法来开启session。
4.1.3  实例6:演示with session的使用
With session的用法是最常见的了,它沿用了python中with的语法,即当程序介绍后会自动关闭session,而不需要在去写close。代码如下。
案例描述
使用with session方法建立session,并在session中计算两个变量(3和4)的相加与相乘。

代码4-2  with session

TensorFlow快速上手及TensorBoard使用

运行后得到如下输出:

TensorFlow快速上手及TensorBoard使用

4.1.4  实例7:演示注入机制
扩展上面代码:使用注入机制,将具体的实参注入到相应的placeholder中去。feed只在调用它的方法内有效,方法结束后feed就会消失。
案例描述
定义占位符,使用feed机制将具体数值(3和4)通过占位符传入,并进行运算它们相加和相乘。

代码4-3  withsessionfeed

TensorFlow快速上手及TensorBoard使用

运行代码,输出:

TensorFlow快速上手及TensorBoard使用

TensorFlow快速上手及TensorBoard使用

标记的方法是:使用tf.placeholder()为这些操作创建占位符,然后使用feed_dict来把具体的值放到站位符里。

注意:

关于feed中的feed_dict还有其他的方法,例如update等,在后文例子中用到时还会介绍。这里只是介绍最常用的方法。

4.1.5  建立session 的其他方法
建立session还有两种方式:
● 交互式session方式:一般在Jupiter环境下使用较多,具体用法与前面的with session类似。代码如下:
sess = tf.InteractiveSession()
● 使用Supervisor方式:该方式会更为高级一些,使用起来也更加复杂,可以自动来管理session中的具体任务,比如,载入/载出检查点文件、写入TensorBoard等,另外还支持分布式训练的部署(在本书的后文会有介绍)。
4.1.6  实例8:使用注入机制获取节点
在上例中,其实还可以一次将多个节点取出来。例如在最后一句加上如下代码:
案例描述
使用fetch机制将定义在图中的节点数值算出来。

代码4-3  withsessionfeed(续)

TensorFlow快速上手及TensorBoard使用

运行代码,输出:

TensorFlow快速上手及TensorBoard使用

4.1.7  指定GPU运算 
如果下载的是GPU版本,在运行过程中TensorFlow能自动检测。如果检测到GPU,TensorFlow会尽可能地利用找到的第一个GPU来执行操作。

如果机器上有超过一个可用的GPU,除第一个外的其他GPU默认是不参与计算的。为了让TensorFlow使用这些GPU,必须将OP明确指派给它们执行。with……Device语句用来指派特定的CPU或GPU执行操作:

TensorFlow快速上手及TensorBoard使用

设备用字符串进行标识。目前支持的设备包括:
● cpu:0:机器的CPU。
● gpu:0:机器的第一个GPU,如果有的话。
● gpu:1:机器的第二个GPU,以此类推。
类似的还有通过tf.ConfigProto来构建一个config,在config中指定相关的gpu,并且在session中传入参数config=“自己创建的config”来指定gpu操作。
#tf.ConfigProto()的参数如下:
● log_device_placement=True:是否打印设备分配日志;
● allow_soft_placement=True:如果指定的设备不存在,允许TF自动分配设备。
使用举例:
config  =  tf.ConfigProto(log_device_placement=True,allow_soft_placement=True)
session = tf.Session(config=config, ...)
4.1.8  设置GPU使用资源
上文的tf.ConfigProto()生成config之后,还可以设置其属性来分配GPU的运算资源。如下代码就是按需分配的意思:
config.gpu_options.allow_growth = True
使用allow_growth option,刚一开始分配少量的GPU容量,然后按需慢慢的增加,由于不会释放内存,所以会导致碎片。
同样上述代码也可以放在config创建的时指定,举例:
gpu_options = tf.GPUOptions(allow_growth=True)
config=tf.ConfigProto(gpu_options=gpu_options)
如下代码还可以给GPU分配固定大小的计算资源。
gpu_options = tf.GPUOptions(per_process_gpu_memory_fraction=0.7)
代表分配给tensorflow的GPU显存大小为:GPU实际显存*0.7。
(该方法暂时用不到,读者在以后遇到这样的代码明白是什么意思就可以。)
4.1.9  保存和载入模型的方法介绍
一般而言,训练好的模型都是需要保存。这里将举例演示如何保存和载入模型。
1.保存模型

首先需要建立一个saver,然后在session中通过saver的save即可将模型保存起来。代码如下:

TensorFlow快速上手及TensorBoard使用

TensorFlow快速上手及TensorBoard使用

2.载入模型

将模型保存好以后,载入也比较方便。在session中通过调用saver的restore函数,会从指定的路径找到模型文件,并覆盖到相关参数中。如下所示:

TensorFlow快速上手及TensorBoard使用

4.1.10  实例9:保存/载入线性回归模型
案例描述
在代码“3-1线性回归.py”的基础上,添加模型的保存及载入功能。
通过扩展上一章的例子,来演示一下模型的保存及载入。在“代码3-1线性回归.py”中生成模拟数据之后,加入对图变量的重置,在session创建之前定义saver及保存路径,在session中训练结束后,保存模型。

代码4-4  线性回归模型保存及载入

TensorFlow快速上手及TensorBoard使用

TensorFlow快速上手及TensorBoard使用

运行上面代码可以看到,在代码的同级目录下log文件夹里生成了几个文件,如图4-2所示。
 TensorFlow快速上手及TensorBoard使用
再重启一个session,并命名为sess2,在代码里通过使用saver的restore函数,将模型载入。

代码4-4  线性回归模型保存及载入(续)

TensorFlow快速上手及TensorBoard使用


为了测试效果,可以将前面一个session注释掉,运行之后可以看到如下输出:

TensorFlow快速上手及TensorBoard使用

表明模型已经成功载入,并计算出正确的值了。
4.1.11  实例10:分析模型内容,演示模型的其他保存方法
下面再来详细介绍下关于模型保存的其他细节。
案例描述
将上一节生成的模型里面的内容打印出来,观察其存放的具体数据方式。同时演示将指定内容保存到模型文件中去。
1.模型内容
虽然模型已经保存了。但是仍然对我们不透明。现在通过编写代码来将模型里面的内容打印出来,看看到底保存了哪些东西,都是什么样子。

代码4-5  模型内容

TensorFlow快速上手及TensorBoard使用


运行上面代码,打印如下信息:

TensorFlow快速上手及TensorBoard使用

可以看到,这个tensor_name:后面跟的就是创建的变量名,接着是它的数值。
2.保存模型的其他方法
前面的例子中saver的创建比较简单,其实tf.train.Saver()里面开可以放参数来实现更高级的功能,可以指定存储变量名字与变量的对应关系。可以写成这样:
saver = tf.train.Saver({'weight': W, 'bias': b})
代表将w变量的值放到weight名字中去。类似的写法还有两种:
saver = tf.train.Saver([W, b]) # 放到一个list里.
saver = tf.train.Saver({v.op.name: v for v in [W, b]}) # 将op的名字当作key:
下面扩展一下上述的例子,给b和w指定个固定值,并将他们颠倒放置。

代码4-5  模型内容(续)

TensorFlow快速上手及TensorBoard使用

运行上面代码,输出如下信息:

TensorFlow快速上手及TensorBoard使用

例子中,W值设为1.0,b的值设为2.0。在创建saver时,我们将它们颠倒,可以看到保存的模型打印出来之后,bias变成了1.0,而weight变成了2.0。
4.1.12  检查点(Checkpoint)
模型的保存场景并不限于在训练之后,在训练之中更需要保存,因为TensorFlow训练模型时难免会出现中断的情况。我们自然就希望能够将辛辛苦苦得到的中间参数保留下来,不然下次又要重新开始。

这种在训练中保存模型,习惯上称之为保存检查点。

全部内容来源于《深入学习之TensorFlow:入门、原理与进阶实战》一书,欢迎支持