Tensorflow提供了一个可视化工具TensorBoard。TensorBoard可以有效的展示TensorFlow在运行过程中的计算图、各种指标随时间的变化趋势以及训练中使用到的图像等信息。
1. 命名空间
在TensorFlow的默认视图中,TensorFlow计算图中同一个命名空间下的所有节点会被缩成一个节点,只有顶层命名空间中的节点才会被显示在TensorBoard的可视化效果图上。其中命名空间可以由两个函数来管理:tf.variable_scope()
和tf.name_scope()
。两者的区别在tf.get_variable()
的使用上。
在tf.variable_scope()
中:
with tf.variable_scope('foo'):
a = tf.get_variable('a', [1])
b = tf.get_variable('b', [1])
print(a.name, b.name)
with tf.variable_scope('goo'):
a = tf.get_variable('a', [1])
b = tf.get_variable('b', [1])
print(a.name, b.name)
通过tf.get_variable()
函数可以获取名为a,b的变量,且在不同的命名空间下获取相同的变量并不冲突,因为他们 都会带上命名空间的前缀:
foo/a:0 foo/b:0
goo/a:0 goo/b:0
而在tf.name_scope()
中:
with tf.name_scope('c'):
a = tf.get_variable('a', [1])
b = tf.get_variable('b', [1])
print(a.name, b.name)
with tf.name_scope('d'):
a = tf.get_variable('a', [1])
b = tf.get_variable('b', [1])
print(a.name, b.name)
则会报错:
ValueError: Variable a already exists, disallowed. Did you mean to set reuse=True or reuse=tf.AUTO_REUSE in VarScope?
所以不能在tf.name_scope()
管理的命名空间下使用tf.name_scope()
获取相同的名称的变量。除此之外,其余的功能都差不多。
2. 如何开启TensorBoard
我们想要在TensorBoard中查看我们建立的模型结构图。首先我们需要先定义一个图,然后生成这个图,最后开启服务。如下所示:
import tensorflow as tf
# 定义变量
with tf.name_scope('a'):
a = tf.Variable([1., 2.], dtype=tf.float32, name='a-variable')
with tf.name_scope('b'):
b = tf.Variable([3., 4.], dtype=tf.float32, name='b-variable')
# 定义操作
with tf.name_scope('a_add_b'):
result = a + b
# 初始化变量
op_init = tf.global_variables_initializer()
# 开启会话
with tf.Session() as sess:
writer = tf.summary.FileWriter('logs/', sess.graph)
sess.run(op_init)
sess.run(result)
从上面的代码可以看出,我们对于每个我们关注的变量也好、操作也好,我们把他们放到了一个命名空间下面,这就相当于把他们装进了一个“盒子”中,最后在TensorBoard中呈现出来的就是这些“盒子”之间的一个”流程图“。所以在上面的代码中,我们猜测图应该会是盒子a与盒子b输入到盒子a_add_b中。
**生成图最关键的步骤: **
writer = tf.summary.FileWriter('logs/', sess.graph)
这句话将图生成一个文件,保存在logs/这个目录下面,程序运行完成之后,你会发现这个文件目录下面多了一个:events.out.tfevents.XXXXXXXX。到这里就成功了一半了。
然后我们打开命令窗口,进入到跟logs一级的目录中,输入tensorboard --logdir=logs/:
E:\python_project\TensroflowProject\06-TensorBoard>tensorboard --logdir=logs/
TensorBoard 1.12.2 at http://XXXXXXXXX:6006 (Press CTRL+C to quit)
这条命令会在你的电脑中启动一个服务,这个服务默认的端口为6006,然后复制这个网站到浏览器中,就可以打开TensorBoard了:
果然跟我们之前的猜测一样!
3. 一个简单的神经网络应用TensorBoard
接下来搭建一个简单的神经网络,并在TensorBoard中查看图、损失函数变化曲线、权值的更新曲线等。
import tensorflow as tf
import numpy as np
# 生成训练数据
x_data = np.linspace(-1, 1, 300)[:, np.newaxis] # 创建从-1到1之间的300个数据,并转换为列向量
noise = np.random.normal(0, 0.05, x_data.shape) # 生成噪声
y_data = np.square(x_data) - 0.5 + noise # x^2-0.5 + noise
# 定义输入与输出层
with tf.name_scope('inputs'):
xs = tf.placeholder(tf.float32, [None, 1], name='x-input')
ys = tf.placeholder(tf.float32, [None, 1], name='y-input')
# ---------------- 定义隐藏层 ---------------------
# 定义一个隐藏层, 神经元个数为10
with tf.name_scope('hidden_layer'):
# 定义权值w,并随机初始化
with tf.name_scope('weights'):
Weights1 = tf.Variable(tf.random_normal([1, 10]))
tf.summary.histogram('hidden_layer/weights', Weights1)
# 定义偏置b
with tf.name_scope('bias'):
bias1 = tf.Variable(tf.zeros([1, 10]) + 0.1)
tf.summary.histogram('hidden_layer/bias', bias1)
with tf.name_scope('wx_plus_b'):
Wx_plus_b1 = tf.matmul(xs, Weights1) + bias1
# 激活函数为relu
with tf.name_scope('hidden_layer/outputs'):
hidden_outputs = tf.nn.relu(Wx_plus_b1)
tf.summary.histogram('hidden_layer/outputs', hidden_outputs)
# ---------------- 定义输出层 ---------------------
with tf.name_scope('output_layer'):
# 定义权值w,并随机初始化
with tf.name_scope('weights1'):
Weights2 = tf.Variable(tf.random_normal([10, 1]))
tf.summary.histogram('output_layer/weights', Weights2)
# 定义偏置b
with tf.name_scope('bias1'):
bias2 = tf.Variable(tf.zeros([1, 1]) + 0.1)
tf.summary.histogram('output_layer/bias', bias2)
with tf.name_scope('predict'):
predict = tf.matmul(hidden_outputs, Weights2) + bias2
tf.summary.histogram('output_layer/predict', predict)
# ---------------- 定义损失函数 ---------------------
with tf.name_scope('loss'):
loss = tf.reduce_mean(tf.reduce_sum(tf.square(ys - predict), reduction_indices=[1]))
tf.summary.scalar('loss', loss)
with tf.name_scope('train'):
train = tf.train.GradientDescentOptimizer(0.3).minimize(loss)
# 初始化变量
init = tf.global_variables_initializer()
# ---------------- 开启会话开始训练 ---------------------
with tf.Session() as sess:
merged = tf.summary.merge_all()
writer = tf.summary.FileWriter('logs/', sess.graph)
sess.run(init)
for step in range(1000): # 开始训练,迭代1000轮
sess.run(train, feed_dict={xs: x_data, ys: y_data})
if step % 50 == 0:
print(step, 'loss=', sess.run(loss, feed_dict={xs: x_data, ys: y_data})) #
result = sess.run(merged, feed_dict={xs: x_data, ys: y_data})
writer.add_summary(result, step)
writer.close()
其实关于中间层参数的初始化,可以参考我上一篇文章TensorFlow学习笔记(2)-构建神经网络及其可视化中的函数。这里我将其展开了,所以程序就显得冗长了。
几个需要特别说明的点是:
1. tf.summary.histogram(name, values)
用于监视values为任意shape的数字型tensor。添加直方图用于观察数据的分布。我们在每个参数的定义的时候都添加了这条语句。最后在TensorBoard中会生成每个参数的Distribution和Histogram,方便观察这些参数的变化趋势。
2. tf.summary.scalar(name, tensor)
用于监视tensor为单一的标量如loss,学习率等。
3. tf.summary.merge_all()
合并默认图中所有的summaries。summary的操作对于整个图来说相当于是外设,因为tensorflow是由结果驱动的,而图的结果并不依赖于summary操作,所以summary操作需要被run。整个图经常需要检测许许多多的值,也就是许多值需要summary operation,一个个去run来启动太麻烦了,tensorflow为我们提供了这个函数,把图中所有的summary数据合并在一起,一个run就能启动所有的summary operations。
4. writer.add_summary(summary, global_step=None)
把每一次run的信息和得到的数据加到writer里面。
最后打开TensorBoard,就可以看到图、变量的分布、变化曲线,loss的变化曲线:
4. 其他summary函数
tf.summary.scalar(name, tensor, collections=None, family=None)
tensor为单一的标量。
tf.summary.histogram(name, values, collections=None, family=None)
values为任意shape的数字型tensor。
tf.summary.image(name, tensor, max_outputs=3, collections=None, family=None)
tensor的shape为[batch_size, height, width, channels],其中channels=1表示灰度图,3表示RGB,4表示RGBA。注意max_outputs默认为3表示每轮默认显示三张图。
tf.summary.audio( name, tensor, sample_rate, max_outputs=3, collections=None, family=None)
tensor为3D shape [batch_size, frames, channels],或者2D shape [batch_size, frames];sample_rate表示声音类型信号tensor的采样率,大小在[-1.0,1.0]之间。
tf.summary.text(name, tensor, collections=None)
将文本数据转换为string类型的tensor。
tf.summary.merge(inputs, collections=None, name=None)
将inputs里面的summary汇集在一起,其中inputs为string类型tensor的列表。
tf.summary.merge_all( key=tf.GraphKeys.SUMMARIES, scope=None)
把所有的summary汇集在一起。
tf.summary.FileWriter(logdir, sess.graph)
把summary protocol buffers 写进 tfevents文件里。
tf.summary.tensor_summary( name, tensor, summary_description=None, collections=None, summary_metadata=None, family=None, display_name=None)
将任意shape和类型的tensor序列化,并返回一个string类型的tensor。
参考资料
通俗易懂之Tensorflow summary类 & 初识tensorboard
TensorFlow 实战Google深度学习框架