主旨
可视化是深度学习神经网络开发、调试、应用中极为重要的手段。Tensorboard是Tensorflow提供的一个可视化工具,本文通过实际代码实验的方式说明使用TensorBoard实现记录变量,实现可视化调试的目的。
源代码
我的GitHub中TF_Graph项目, singleNerualNode.py
网络结构
为了简化情况,实验中使用单层神经网络,网络结构定义见笔者前一篇文章 [TensorFlow]理解Tensorboard Graph“案例1:单个神经元”
TensorBoard基本调用方法
- 网络结构定义中将所有输出到tf.summary的变量合并到一个Tensor
- 1
- 1
- 创建Writer
- 1
- 2
- 1
- 2
- 在训练中计算merged Tensor,并输出到writer
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
-
启动TensorBoard,在shell输入如下命令
tensorboard –logdir tf_writer
注:’tf_writer’是我的log_path, 实际使用中根据存储Log的位置调整 -
从浏览器中访问
打开浏览器访问http://192.168.1.100:6006/,其中’192.168.1.100’是运行Tensorboard的计算机IP地址,可以是本机,也可以是网络上的服务器,能访问到就行。
标量(Scalar)的输出
区别于矩阵和向量,标量可以认为只有1个维度的数值量。
在神经网络中,损失函数的值、模型预测准确率等都是典型的标量。如下是计算损失函数和模型预测准确率的代码。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 1
- 2
- 3
- 4
- 5
- 6
- 7
对于这些变量,我们最典型的需求是知道每一轮模型训练迭代中,其朝着哪个方向变化,是否达到收敛状态。使用Tensorboard,只要添加以下代码就可以实现
- 1
- 2
- 1
- 2
在Tensorboard中看到的结果如下,Accuracy和L2 Loss分别记录在两张图表中,每张图的横坐标表示迭代序号(第几次训练),纵坐标就是我们添加的标量结果
以Accuracy为例,放大观察
Tensorboard会记录每个点的名称、平滑后取值、原始值、Step(迭代序号)、时间戳和相对于训练开始过了多长时间。这些信息对于可视化的观察模型收敛情况非常有帮助。
多维张量(Tensor)的输出
标量(scalar)在Tensor Flow的神经网络中只占很少一部分,大部分变量是多维张量,即Tensor。由于一个Tensor有多个维度,无法像标量一样直接输出成曲线,在可视化时可以有以下几种方法:
- 将Tensor转化为标量输出
- 输出Tensor的分布直方图
- 如果Tensor本身是图形(即以[batch, height, weight, channel]格式的图片),以图片形式输出
第一种,在TensorBoard的官方教程中给出了清晰的示意代码。给定一个Tensor,如下函数从均值、标准差、最大值、最小值等多个角度转化为标量,从而可视化。由于标量的可视化效果前一节已经展示过了,这里不在重复。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
第二种,以直方图输出,输出方法非常简单,按照下列代码的方式调用tf.summary.histogram即可
- 1
- 2
- 3
- 4
- 5
- 1
- 2
- 3
- 4
- 5
问题的难点在于如何理解直方图的输出,直方图的输出形式如下
放大其中bias这张图
这张图垂直于屏幕的方向,即高亮的一行显示822则个数据所在的坐标轴,是迭代次数序号。随着训练迭代次数由0到最大迭代次数(这里设定为1000)训练,bias的分布由远及近画出来。
关键问题是“bias的分布”指的是什么,根据代码bias本身定义为1维Tensor:b = tf.Variable(tf.zeros([1]), name=’biases’),一个Batch定义为1000,那么b可以视为具有1000个元素的一维数组,上图每个横截面给出的是这1000个元素的概率分布。
带着这个结论,接下来考察更复杂的多维Tensor的直方图:weight
weight本身定义维2*1 Tensor,每个batch定义为1000个样本
W = tf.Variable(tf.random_normal([numberOfInputDims, 1]), name='weights')
则直方图代表的是总数为2*1*1000个取值的分布。
我们将W设计维2*1,是为了保存两个输入节点分别的权重:w_1和w_2。在上述直方图分布中,确实可以清晰的看到W的分布呈现双峰分布,这两个峰分别对应w_1和w_2。随着训练次数的增加,w_1和w_2相距越来越远,这和训练目标是实现线性分类是吻合的。
第三种,以图形形式输出,在TensorFlow API中有详细描述,由于这次我们选择的简单神经网络中不具备这样格式的Tensor,暂时无法通过例子说明。API文档链接如下
https://www.tensorflow.org/versions/master/api_docs/python/tf/summary/image
Embedding
除了前文描述的标量和Tensor输出之外,可视化还包括观察大量数据的分布。这里大量数据可以是输入、输出数据,也可以是网络中的任意参数。
Google对此有一篇专门的论文,其中Introduction对于Embedding的定义和作用有清晰的描述,笔者尝试翻译如下
embedding是从输入数据点到欧式空间中点的映射,为了理解模型的行为特征,机器学习的研发人员经常需要探索某个特定的Embedding。例如做音乐推荐系统的工程师创建了一个歌曲的embedding,他可能需要验证”Stairway to Heaven”这支歌曲最近的邻居包括“Whole Lotta Love”但不包括”Let it Go”. 对于这样的用户,从Embedding的几何结构获得理解就很关键。
具体到我们的案例,假定我想知道输入数据的几何分布,使用如下代码实现。
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
代码中inputData是1000*2的Tensor,表示1000个二维平面上的点。label.csv是包含了这1000个数据标签的文件,格式见如下文件
https://github.com/wangyaobupt/TF_Graph/blob/master/label.csv
Embedding还必须依赖于模型的保存,在定义网络结构中,需要定义saver如下
- 1
- 2
- 1
- 2
在模型训练中,必须保存训练结果
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
上述工作完成后,运行得到如下图形
从图形左侧逐一解释,首先左上部分要选择数据和颜色,我们整个网络中只添加了一个Embedding Tensor,因此不用特殊选定,颜色算则Label即可,即根据label文件不同的标签标识颜色。
左下部有三张选项卡,s_TNE/PCA/Custom,默认为PCA。这里使用PCA是为了把高维Tensor降低到3维,以方便可视化。但我们此次实验的数据,扣除表示batch的维度,只有2维,因此PCA的输出就是数据的X、Y坐标,同时不需要显示Z轴。
右侧是实际图形,图中可以清晰的看到训练数据的线性可分性质。
由于Tensorflow在Embedding的文档本身较少,笔者写作这一节内容时参考了大量网络资料,特别感谢以下这Link的回答者Ehsan和Albert X.W.