返回介绍

3.4 练习:综合运用各种组件

发布于 2024-02-05 23:12:36 字数 7420 浏览 0 评论 0 收藏 0

下面通过一个综合运用了之前讨论过的所有组件——Tensor对象、Graph对象、Op、Variable对象、占位符、Session对象以及名称作用域的练习来结束本章。还会涉及一些TensorBoard汇总数据,以使数据流图在运行时能够跟踪其状态。练习结束后,读者将能够自如地搭建基本的TensorFlow数据流图并在TensorBoard中对其进行研究。

本质上,本练习所要实现的数据流图与我们接触的第一个基本模型对应相同类型的变换。

但与之前的模型相比,本练习中的模型更加充分地利用了TensorFlow:

输入将采用占位符,而非tf.constant节点。

模型不再接收两个离散标量,而改为接收一个任意长度的向量。

使用该数据流图时,将随时间计算所有输出的总和。

将采用名称作用域对数据流图进行合理划分。

每次运行时,都将数据流图的输出、所有输出的累加以及所有输出的均值保存到磁盘,供TensorBoard使用。

现可直观感受一下本练习中的数据流图。

在解读该模型时,有一些关键点需要注意:

注意每条边的附近都标识了[None]或[]。它们代表了流经各条边的张量的形状,其中None代表张量为一个任意长度的向量,[]代表一个标量。

节点d的输出流入“update”环节,后者包含了更新各Variable对象以及将数据传入TensorBoard汇总所需的Op。

用一个独立的名称作用域包含两个Variable对象。这两个Variable对象中一个用于存储输出的累加和,另一个用于记录数据流图的运行次数。由于这两个Variable对象是在主要的变换工作流之外发挥作用的,因此将其放在一个独立的空间中是完全合理的。

TensorBoard汇总数据有一个专属的名称作用域,用于容纳tf.scalar_summary Op。我们将它们放在“update”环节之后,以确保汇总数据在Variable对象更新完成后才被添加,否则运算将会失控。

下面开始动手实践吧!打开代码编辑器或交互式Python环境。

3.4.1 构建数据流图

我们要做的第一件事永远是导入TensorFlow库:

下面显式创建一个Graph对象加以使用,而非使用默认的Graph对象,因此需要用Graph类的构造方法tf.Graph():

接着在构造模型时,将上述新Graph对象设为默认Graph对象:

在我们的模型中有两个“全局”风格的Variable对象。第一个是“global_step”,用于追踪模型的运行次数。在TensorFlow中,这是一种常见的范式,在整个API中,这种范式会频繁出现。第二个Variable对象是“total_ouput”,其作用是追踪该模型的所有输出随时间的累加和。由于这些Variable对象本质上是全局的,因此在声明它们时需要与数据流图中的其他节点区分开来,并将它们放入自己的名称作用域。

请注意,这里使用了trainable=False设置,这并不会对模型造成影响(因为并没有任何训练的步骤),但该设置明确指定了这些Variable对象只能通过手工设置。

接下来,将创建模型的核心变换部分。我们会将整个变换封装到一个名称作用域“transformation”中,并进一步将它们划分为三个子名称作用域——“input”、“intermediate_layer”和“output”。

除少量关键之处不同外,上述代码与为之前的模型所编写的代码高度相似:

输入节点为tf.placeholder Op,它可接收一个任意长度(因为shape=[None])的向量。

对于乘法和加法运算,这里并未使用tf.mul()和tf.add(),而是分别使用了tf.reduce_prod()和tf.reduce_sum(),这样便可以对整个输入向量实施乘法和加法运算,而之前的Op只能接收两个标量作为输入。

经过上述变换计算,需要对前面定义的两个Variable对象进行更新。下面通过创建一个“update”名称作用域来容纳这些变化:

total_output和global_step的递增均通过Variable.assign_add()Op实现。output的值被累加到total_output中,因为希望随时间将所有的输出进行累加。对于global_step,只是将其简单地增1。

这两个Variable对象更新完毕后,便可创建我们感兴趣的TensorBoard汇总数据,可将它们放入名为“summaries”的名称作用域中:

在该环节中,所做的第一件事是随时间计算输出的均值。幸运的是,可以获取当前全部输出的总和total_output(使用来自update_total的输出,以确保在计算avg之前更新便已完成)以及数据流图的总运行次数global_step(使用increment_step的输出,以确保数据流图有序运行)。一旦获得输出的均值,便可利用各个tf.scalar_summary对象将ouput、update_total和avg保存下来。

为完成数据流图的构建,还需要创建Variable对象初始化Op和用于将所有汇总数据组织到一个Op的辅助节点。下面将它们放入名为“global_ops”的名称作用域:

读者可能会有一些疑惑,为什么将tf.merge_all_summaries()Op放在这里,而非“summaries”名称作用域?虽然两者并无明显差异,但一般而言,将merge_all_summaries()与其他全局Op放在一起是最佳做法。我们的数据流图只为汇总数据设置了一个环节,但这并不妨碍去想象一个拥有Variable对象、Op和名称作用域等的不同汇总数据的数据流图。通过保持merge_all_summaries()的分离,可确保用户无需记忆放置它的特定“summary”代码块,从而比较容易找到该Op。

以上便是构建数据流图的全部内容,但要使这个数据流图能够运行,还需要完成一些设置。

3.4.2 运行数据流图

打开一个Session对象,并加载已经创建好的Graph对象,也可打开一个tf.trian.SummaryWriter对象,便于以后利用它保存汇总数据。下面将./improved_graph作为保存汇总数据的目标文件夹:

Session对象启动后,在做其他事之前,先对各Variable对象进行初始化:

为运行该数据流图,需要创建一个辅助函数run_graph(),这样以后便无需反复输入相同的代码。我们希望将输入向量传给该函数,而后者将运行数据流图,并将汇总数据保存下来:

下面对run_graph()函数逐行进行解析:

1)首先创建一个赋给Session.run()中feed_dict参数的字典,这对应于tf.placeholder节点,并用到了其句柄a。

2)然后,通知Session对象使用feed_dict运行数据流图,我们希望确保output、increment_step以及merged_summaries Op能够得到执行。为写入汇总数据,需要保存global_step和merged_summaries的值,因此将它们保存到Python变量step和summary中。这里用下划线“_”表示我们并不关心output值的存储。

3)最后,将汇总数据添加到SummaryWriter对象中。global_step参数非常重要,因为它使TensorBoard可随时间对数据进行图示(稍后将看到,它本质上创建了一个折线图的横轴)。

下面来实际使用这个函数,可变换向量的长度来多次调用run_graph()函数:

上述调用可反复进行。数据填充完毕后,可用SummaryWriter.flush()函数将汇总数据写入磁盘:

最后,既然SummaryWriter对象和Session对象已经使用完毕,我们将其关闭,以完成一些清理工作:

以上便是全部的TensorFlow代码!虽然与之前的数据流图相比代码量略大,但还不至于过多。下面打开TensorBoard,看看可以得到什么结果。启动终端,导航至运行上述代码的目录(请确保“improved_graph”目录在该路径下),并运行下列命令:

与之前一样,该命令将在6006端口启动一个TensorBoard服务器,并托管存储在“improved_graph”中的数据。在浏览器中键入“localhost:6006”,观察所得到的结果。首先检查“Graph”标签页。

可以看到,上图与之前所绘制的非常吻合。我们的变换运算流入update方框,后者又同时为summaries和variables名称作用域提供输入。上图与之前所绘制的图表的主要区别体现在“global_ops”名称作用域上,它包含了一些对于主要的变换计算并不十分关键的运算。

可将各个方框展开,以便在更细的粒度上观察它们的结构。

现在可以看到输入层、中间层和输出层是彼此分离的。对于像本例这样的简单模型,这样的划分可能有些小题大做,但这种类型的划分方法是极为有用的。请观察该数据流图的其余部分。当准备好后,请切换到“Events”页面。

当打开“Events”页面后,可以看到3个依据我们赋予各scalar_summary对象的标签而命名的折叠的标签页。单击任意一个标签页,便可看到一个精美的折线图,展示了不同时间点上值的变化。单击该图表左下方的蓝色矩形,它们会像上图一样展开。

仔细检查汇总数据的结果,对其进行比较,确保它们都是有意义的,然后向自己表示祝贺!本练习至此就全部结束了,希望读者能够熟练掌握如何基于虚拟草图创建TensorFlow数据流图,以及如何利用TensorBoard做一些基础的数据汇总工作。

本练习的完整代码如下:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文