学习TensorFlow,TensorBoard可视化网络结构和参数

在学习深度网络框架的过程中,我们发现一个问题,就是如何输出各层网络参数,用于更好地理解,调试和优化网络?针对这个问题,TensorFlow开发了一个特别有用的可视化工具包:TensorBoard,既可以显示网络结构,又可以显示训练和测试过程中各层参数的变化情况。本博文分为四个部分,第一部分介绍相关函数,第二部分是代码测试,第三部分是运行结果,第四部分介绍相关参考资料。

一. 相关函数

TensorBoard的输入是tensorflow保存summary data的日志文件。日志文件名的形式如:events.out.tfevents.1467809796.lei-All-Series 或 events.out.tfevents.1467809800.lei-All-Series。TensorBoard可读的summary data有scalar,images,audio,histogram和graph。那么怎么把这些summary data保存在日志文件中呢?

数值如学习率,损失函数用scalar_summary函数。tf.scalar_summary(节点名称,获取的数据)

accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))
tf.scalar_summary(‘accuracy‘, accuracy)

各层网络权重,偏置的分布,用histogram_summary函数

preactivate = tf.matmul(input_tensor, weights) + biases
tf.histogram_summary(layer_name + ‘/pre_activations‘, preactivate)

其他几种summary data也是同样的方式获取,只是对应的获取函数名称换一下。这些获取summary data函数节点和graph是独立的,调用的时候也需要运行session。当需要获取的数据较多的时候,我们一个一个去保存获取到的数据,以及一个一个去运行会显得比较麻烦。tensorflow提供了一个简单的方法,就是合并所有的summary data的获取函数,保存和运行只对一个对象进行操作。比如,写入默认路径中,比如/tmp/mnist_logs (by default)

merged = tf.merge_all_summaries()  

train_writer = tf.train.SummaryWriter(FLAGS.summaries_dir + ‘/train‘, sess.graph)  

test_writer = tf.train.SummaryWriter(FLAGS.summaries_dir + ‘/test‘)

SummaryWriter从tensorflow获取summary data,然后保存到指定路径的日志文件中。以上是在建立graph的过程中,接下来执行,每隔一定step,写入网络参数到默认路径中,形成最开始的文件:events.out.tfevents.1467809796.lei-All-Series 或 events.out.tfevents.1467809800.lei-All-Series。

for i in range(FLAGS.max_steps):
if i % 10 == 0:  # Record summaries and test-set accuracy
summary, acc = sess.run([merged, accuracy], feed_dict=feed_dict(False))
      test_writer.add_summary(summary, i)
 print(‘Accuracy at step %s: %s‘ % (i, acc))
 else: # Record train set summarieis, and train
      summary, _ = sess.run([merged, train_step], feed_dict=feed_dict(True))
      train_writer.add_summary(summary, i)



tensorflow 可视化

tensorflow的可视化是使用summarytensorboard合作完成的.

基本用法

首先明确一点,summary也是op.

输出网络结构

with tf.Session() as sess:
  writer = tf.summary.FileWriter(your_dir, sess.graph)
  • 1
  • 2
  • 1
  • 2

命令行运行tensorboard --logdir=your_dir,然后浏览器输入127.0.1.1:6006
这样你就可以在tensorboard中看到你的网络结构图了

可视化参数


#ops
loss = ...
tf.summary.scalar("loss", loss)
merged_summary = tf.summary.merge_all()

init = tf.global_variable_initializer()
with tf.Session() as sess:
  writer = tf.summary.FileWriter(your_dir, sess.graph)
  sess.run(init)
  for i in xrange(100):
    _,summary = sess.run([train_op,merged_summary], feed_dict)
    writer.add_summary(summary, i)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这时,打开tensorboard,在EVENTS可以看到loss随着i的变化了,如果看不到的话,可以在代码最后加上writer.flush()试一下,原因后面说明。

函数介绍

  • tf.summary.merge_all: 将之前定义的所有summary op整合到一起
  • FileWriter: 创建一个file writer用来向硬盘写summary数据,
  • tf.summary.scalar(summary_tags, Tensor/variable): 用于标量的 summary
  • tf.summary.image(tag, tensor, max_images=3, collections=None, name=None):tensor,必须4维,形状[batch_size, height, width, channels],max_images(最多只能生成3张图片的summary),觉着这个用在卷积中的kernel可视化很好用.max_images确定了生成的图片是[-max_images: ,height, width, channels],还有一点就是,TensorBord中看到的image summary永远是最后一个global step
  • tf.summary.histogram(tag, values, collections=None, name=None):values,任意形状的tensor,生成直方图summary
  • tf.summary.audio(tag, tensor, sample_rate, max_outputs=3, collections=None, name=None)

FileWriter

注意:add_summary仅仅是向FileWriter对象的缓存中存放event data。而向disk上写数据是由FileWrite对象控制的。下面通过FileWriter的构造函数来介绍这一点!!!

tf.summary.FileWriter.__init__(logdir, graph=None, max_queue=10, flush_secs=120, graph_def=None)

Creates a FileWriter and an event file.
# max_queue: 在向disk写数据之前,最大能够缓存event的个数
# flush_secs: 每多少秒像disk中写数据,并清空对象缓存
  • 1
  • 2
  • 3
  • 4
  • 5
  • 1
  • 2
  • 3
  • 4
  • 5

注意

  1. 如果使用writer.add_summary(summary,global_step)时没有传global_step参数,会使scarlar_summary变成一条直线。
  2. 只要是在计算图上的Summary op,都会被merge_all捕捉到, 不需要考虑变量生存空间问题!
  3. 如果执行一次,disk上没有保存Summary数据的话,可以尝试下file_writer.flush()

小技巧

如果想要生成的summary有层次的话,记得在summary外面加一个name_scope

with tf.name_scope("summary_gradients"):
    tf.summary.histgram("name", gradients)
  • 1
  • 2
  • 1
  • 2

这样,tensorboard在显示的时候,就会有一个sumary_gradients一集目录。


主旨

在TensorFlow中每开发一个模型,都可以使用可视化调试工具TensorBoard得到这个session的Graph,这张图的结构和内容都不同于机器学习教材上介绍的典型神经网络结构图。本文试图通过代码实验理解Graph的含义,用以指导日常调试。

代码和运行环境

代码:https://github.com/wangyaobupt/TF_Graph singleNerualNode.py

运行环境:
Python 2.7.12 (default, Nov 19 2016, 06:48:10)
[GCC 5.4.0 20160609] on linux2
>>> tf.__version__
‘1.0.0-rc2’

问题介绍

在TensorFlow开发中,TensorBoard是一项很有用的可视化调试工具。在TensorBoard中,除了开发者自定义输出的数据结构之外,还包括表征神经网络模型的GRAPH。

在常见的机器学习教材中,神经网络的结构一般通过类似于如下的图形表示,下图引用自http://www.extremetech.com/extreme/215170-artificial-neural-networks-are-changing-the-world-what-are-they

但是,TensorBoard生成的Graph与上述形态完全不同,我自己开发的某个神经网络生成的Graph如下图所示

如何理解这张图?本文试图通过代码实验做一些尝试。

案例1:单神经元

为了简化分析场景,我们设计一个由单个神经元构成的神经网络,这个神经元存在numberOfInputDims输入,神经元的每条输入边都有权重因子wi,此外神经元还有bias偏置项,激活函数为sigmoid. 这个结构可以用如下的结构图描述

在TensorFlow中,如下代码即可定义出满足上述结构的神经网络,其中a就是上图中的Y

  inputTensor = tf.placeholder(tf.float32, [None, numberOfInputDims], name=‘inputTensor‘)
  labelTensor=tf.placeholder(tf.float32, [None, 1], name=‘LabelTensor‘)
  W = tf.Variable(tf.random_uniform([numberOfInputDims, 1], -1.0, 1.0), name=‘weights‘)
  b = tf.Variable(tf.zeros([1]), name=‘biases‘)
  a = tf.nn.sigmoid(tf.matmul(inputTensor, W) + b, name=‘activation‘)
  • 1
  • 2
  • 3
  • 4
  • 5

使用TensorBoard生成的Graph如下图所示

问题1:Graph中的边(Edge)代表什么

根据TF官方文档对于Graph的说明,上图中实线表示数据依赖(tensor在运算符之间的流动关系),而虚线表示控制依赖关系,原文引用如下

TensorFlow graphs have two kinds of connections: data dependencies and control dependencies. Data dependencies show the flow of tensors between two ops and are shown as solid arrows, while control dependencies use dotted lines.

但是,我们得到的Graph中所有的实线都没有标出箭头方向,他们之间是谁依赖谁呢?

回答这个问题需要回到代码中,从代码可以知道:weight是由tf.random_uniform([numberOfInputDims, 1]初始化得到的;weight和inputTensor做矩阵乘法得到中间变量;中间变量再加上bias得到激活函数的输入;以此类推。

因此,TensorBoard Graph的上下方位代表了数据依赖的方向:数据总是从下方的节点流向上方的节点,上方节点依赖于下方节点

接下来讨论控制依赖。

上图中weight和bias节点都存在依赖于init运算的虚线,这说明weight和bias节点都需要初始化。虚线指向的运算符(op)是被依赖的运算符(op)

问题2:Graph中的节点代表什么

官方文档对于Graph的说明给出了如下图例表格

从中可以看出,不考虑summary node的情况下,节点要么是常数Constant,要么是运算符Operation Node,要么是前两者的组合。

回到我们这个具体问题,random_uniform/weight/bias就是组合节点,而其他节点就是运算符。注意:从上图可以看到,inputTensor也是被视作一个独立的运算符。

放大其中一个节点weights,我们可以看到其内部结构如下,包含:赋值(assign)运算符、(weight)运算符、读取(read)运算符

结合上述实验和分析,可以初步判断运算符Operation Node包含以下情况

  • 具体的运算操作:例如矩阵乘法(上图中的matmul),赋值(assign),读取(read)
  • 某个Tensor本身:例如上图中的inputTensor和(weights)节点

关于Operation Node代表常量的情况,在本文的案例2中会有体现

案例2:单神经元+损失函数+误差反向传播梯度下降调整参数

案例1中的神经网络只包含了前向计算逻辑,作为神经网络,其最主要的功能在于被训练满足某一目标,因此损失函数和误差反向传播梯度下降调整参数是必不可少的。

在此前的代码基础上新增如下两行就可以实现上述功能。这里损失函数使用预测值与目标值的L2距离

  loss = tf.nn.l2_loss(a - labels, name=‘L2Loss‘)
  train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)
  • 1
  • 2

加入这两个功能后,新生成的Graph如下所示

对比上图和案例1中的Graph,在案例2 Graph的Main View(图像左侧)新增了如下信息

  • 节点

    • 常量y:代表label
    • sub运算符
    • L2Loss Tensor
    • gradient命名空间,这个命名空间与除了bias/add/L2Loss之外所有节点都有数据依赖
    • Weights和Bias都新增了对Adam节点的控制依赖

接下来重点讨论Gradient(梯度)和Adam(寻优算法)节点的内部结构

Gradient(梯度)节点

Gradient(梯度)节点内部是一个链式结构,分为对L2Loss求导、对减法求导、对激活函数求导……
总结起来,这就是数学上求导数的链式法则的图形化表示,我们的最终目的是求出损失函数对某个参数的导数,那么根据链式法则,只要从损失函数L2Loss出发,将每一层求导结果相乘就可以得到,笔者前一个系列利用Python实现神经网络中也使用了类似的求导方法

Adam(寻优算法)节点

Adam算法本身的原理和实现可以参阅笔者此前的文章:Python实现神经网络Part 2: 训练单个神经元找到最优解
上述图形就是根据Adam算法原理,使用梯度、beta1\beta2,结合每一轮训练中weights和bias的原始值,计算weight和bias的更新值,通过控制依赖关系进一步调节weights和bias

总结

TensorBoard中的Graph不同于一般的神经网络结构图,它是一种计算图。图中每个节点要么是Tensor本身,要么是运算符,每一条边要么代表Tensor的流动,要么代表控制关系。这张图完备的表达了通过代码定义的神经网络中所有计算步骤,可以据此说明前向计算、误差反相传播、梯度下降调整参数等过程。

在实际工作中,理解了上述含义,就可以将Graph利用起来,在Debug过程中可视化的发现网络计算流程中的问题。复杂程序的调试总是困难的,引入可视化工具对于调试效率会非常有帮助。




参考文献:

http://www.360doc.com/content/17/0414/13/10408243_645540404.shtml

http://blog.csdn.net/helei001/article/details/51842531

原文地址:https://www.cnblogs.com/yifdu25/p/8270849.html

时间: 2024-10-09 14:24:28

学习TensorFlow,TensorBoard可视化网络结构和参数的相关文章

TensorFlow——TensorBoard可视化

TensorFlow提供了一个可视化工具TensorBoard,它能够将训练过程中的各种绘制数据进行展示出来,包括标量,图片,音频,计算图,数据分布,直方图等,通过网页来观察模型的结构和训练过程中各个参数的变化. Tensorboard通过一个日志展示系统进行数据可视化,在session运行图的时候,将各类的数据汇总并输出到日志文件中.然后启动Tensorboard服务,Tensorboard读取日志文件,并开启6006端口提供web服务.让用户可以在浏览器中查看数据. 相关的API函数如下;

Tensorflow学习笔记3:TensorBoard可视化学习

TensorBoard简介 Tensorflow发布包中提供了TensorBoard,用于展示Tensorflow任务在计算过程中的Graph.定量指标图以及附加数据.大致的效果如下所示, TensorBoard工作机制 TensorBoard 通过读取 TensorFlow 的事件文件来运行.TensorFlow 的事件文件包括了你会在 TensorFlow 运行中涉及到的主要数据.关于TensorBoard的详细介绍请参考TensorBoard:可视化学习.下面做个简单介绍. Tensorf

Tensorflow实战 手写数字识别(Tensorboard可视化)

一.前言 为了更好的理解Neural Network,本文使用Tensorflow实现一个最简单的神经网络,然后使用MNIST数据集进行测试.同时使用Tensorboard对训练过程进行可视化,算是打响学习Tensorflow的第一枪啦. 看本文之前,希望你已经具备机器学习和深度学习基础. 机器学习基础可以看我的系列博文: https://cuijiahua.com/blog/ml/ 深度学习基础可以看吴恩达老师的公开课: http://mooc.study.163.com/smartSpec/

吴裕雄--天生自然 神经网络人工智能项目:基于深度学习TensorFlow框架的图像分类与目标跟踪报告(续一)

1.3 项目计划 第一周:深入学习和了解神经网络的工作原理,学习卷积的相关理论. 第二周:使用python的TensorFlow库,编写神经网络深度学习代码,搭建神经网络层,并且了解其工作原理和相关的计算.相关参数的传递等,到htttps://www.kaggle.com/moltean/fruits下载fruits压缩包,对数据进行初步的处理. 第三周:使用TensorFlow搭建卷积神经网络,采用训练集数据对测试集数据进行预测:完成数据可视化,显示每个文件夹中第5张图片.使用Tensorbo

tensorboard可视化遇到的问题

由于 TensorFlow版本差异,经常会报模块对象没有某属性的错误,先把tensorboard可视化过程遇到的几个报错解决方案记录如下: 1. AttributeError: 'module' object has no attribute 'histogram_summary' histogram_summary 改为:tf.summary.histogram 2. AttributeError: 'module' object has no attribute 'scalar_summar

R语言学习笔记 之 可视化地研究参议员相似性

基于相似性聚类 很多时候,我们想了解一群人中的一个成员与其他成员之间有多么相似.例如,假设我们是一家品牌营销公司,刚刚完成了一份挂怒有潜力新品牌的研究调查问卷.在这份调查问卷中,我们向一群人展示了新品牌的几个特征,并且要求他们对这个新品牌的每个特征按五分制打分.同时也收集了目标人群的社会经济特征,例如:年龄.性别.种族.住址的邮编以及大概的年收入. 通过这份调查问卷,我们想搞清楚品牌如何吸引不同社会经济特征的人群.最重要的是,我们想要知道这个品牌是否有很大的吸引力.换个角度想这个问题,我们想看看

学习Tensorflow的LSTM的RNN例子

学习Tensorflow的LSTM的RNN例子 基于TensorFlow一次简单的RNN实现 极客学院-递归神经网络 如何使用TensorFlow构建.训练和改进循环神经网络

【web开发学习笔记】Structs2 Result学习笔记(三)带参数的结果集

Result学习笔记(三)带参数的结果集 第一部分:代码 //前端 <head> <meta http-equiv="Content-Type" content="text/html; charset=GB18030" /> <title>Insert title here</title> </head> <body> <ol> <li><a href="

gcp上使用gpu来学习tensorflow

1080ti显卡实在是太贵了,8k一张的价格,让我感到无耐.还好,有gcp的gpu来训练,最有意思的是,他还提供300美元,让你挥霍. 1.当然是申请gcp的账号. 2.登录后,左侧->"IAM和管理"->"配额" 3.在"指标"->"全不选"->搜索框输入"k80",选中"Nvidia K80 GUPs". 4.这时列表为可用单位,在"位置"