说明
本文将介绍如何向tensorboard中添加sclar的方法,但会先尽量简要介绍一下tensorflow的静态图机制,查看添加方法可以直接去这一部分
TensorFlow的静态计算图机制
关于并非众所周知的静态计算图,唯一能说的是,这肯定是TensorFlow不太容易上手的原因之一。与PyTorch的动态计算图的简洁直观不同,TensorFlow的静态图将计算图的定义与运行分开进行,导致读和写TF程序都很不直观。
整体流程为,先定义好网络结构,再分别定义好Loss函数和数据生成器(dataloader),然后再通过运行session的方法,向网络中送入数据并得到返回值;最后根据返回值计算Loss,并通过定义好的optimizer反传梯度(gradient),优化网络参数(weight)。
下面通过预测“超级英雄使用各自武器能完成到底多少任务”来简单讲一下静态计算图。
- 首先我们按照需求定义好我们想要的网络结构,如各种Conv层,激活层,dense层等等;下面伪代码,定义了三位超级英雄,通过使用各自的武器完成了各自的任务,返回的是任务的完成度:
class Avengers(object):
def __init__(self,a1,a2,a3):
self.ironman = a1
self.captain = a2
self.thor = a3
def __call__(self, suit, sheild, hammer):
"""similar to forward() function in PyTorch"""
task1 = assign_weapon_and_perform_task(self.ironman, suit)
task2 = assign_weapon_and_perform_task(self.captain, sheild)
task3 = assign_weapon_and_perform_task(self.thor, hammer)
return task1, task2, task3
def assign_weapon_and_perform_task(self, hero, weapon):
"""This layer defines how the hero use weapon to perform a task"""
# do some task, return percentage of the completion of the task
return percent
- 然后我们再组建一个复联队伍(将模型实例化):
def build_avengers_team(name1,name2, name3, w1, w2, w3):
founder_avengers = Avengers(name1, name2,name3)
task1, task2, task3 = founder_avengers(w1, w2, w3)
return task1, task2, task3
- 然后就可以在主函数中定义训练过程和Loss的计算。这里是静态图不直观的地方了,定义好的模型不是直接使用,而是通过运行session来送入数据和返回结果:
def Loss(task_pred, task_gt):
loss_value = some_method_to_compute_loss(task_pred, task_gt)
return loss_value
def train_avengers():
num_epochs = 10
w1, w2, w3, gt1, gt2, gt3 = predefined_data_iterator.get_next()
t1, t2, t3 = build_avengers_team(tony, steve, thor, w1, w2, w3)
loss1, loss2, loss3 = Loss(t1, gt1), Loss(task2, gt2), Loss(task3, gt3)
optimizer =
loss_backprobgate_and_optimizer(loss1+loss2+loss3)
with tf.Session() as sess:
for i in range(num_epochs):
t1, t2, t3 = sess.run(optimizer, t1, t2, t3, w1, w2, w3 )
...
可以发现, 所有的通过网络生成的数据就通过session的run取回了,后面可以再进行任何想要的操作。这里的session就是不直观的地方,原因就是建模型、数据生成和模型运行生成结果是分开的。
相当于,我们先在A地生产了汽车的外壳,在B地生产了轮胎,然后一起运送到C地组装并测试驾驶情况
Tensorboard中添加任意scalar
在TensorFlow 1.9
以前的版本不能很方便地直接添加自己想要的scalar,也是要像上面定义模型和模型的返回值一样,先定义好summary的数据,然后传入session并取回;
通过阅读相当不完整的官方文档,可以发现也有办法手动添加scalar(或者其他数据结构,如simple_value, image,histogram等), 方法为自己手动将想要添加到tensorboard中监控的数据转换为tf.Summary格式的数据:
# official method
tf.summary.scalar("loss1", loss1)
tf.summary.scalar("loss2", loss2)
# 将merged_summary送入session.run中可以返回需要的数据
merged_summary = tf.summary.merge_all()
train_writer = tf.summary.FileWriter("/log_dir",sess.graph)
...
...
merged_summary, other_data =sess.run([merged_summary, other_data], feed_dict = {...})
# 官方添加监控信息方法
train_writer.add_summary(merged_summary, global_step)
...
...
# 手动添加数据: 将数据转换为tf.Summary格式
train_writer.add_summary(tf.Summary(value=[tf.Summary.Value(tag='name_you_want',simple_value=data_you_want)]),global_step)
train_writer.flush() # 写入文件
其中数据格式(simple_value这里可供替换的数据格式)可以参考源代码定义,是的,要参考源代码定义…
在tensorboard中同时显示多组数据(如train和validation同时显示)
需要建立多个writer,并放在不同文件夹中,尤其需要注意,在val_writer中不要再加sess.graph
:
train_writer = tf.summary.FileWriter("/log_dir/tarin",sess.graph)
val_writer = tf.summary.FileWriter("/log_dir/val")
不同阶段产生的数据分开记录,比如training阶段产生的监控数据就用train_writer写入,validation同理;在查看监控数据的时候就在/log_dir
根目录下执行:
tensorboard --log_dir='/log_dir'
这样就会在最终tensorboard中出现两组分别为train
和val
的数据了,并且可以通过勾选,将相同名字的数据显示在同一个表格上。
其他参考