0%

tensorboard

0. 前言

新装pytorch之后,可视化工具visdom就不能用了,所以改用tensorboard,以下是tensorboard及其变体的使用命令。

1. 原理

tensorboard与visdom不同,前者是直接读取文件进行展示,需要程序先把要展示的内容保存成文件,然后tensorboard再读取文件进行展示,后者是代码直接展示,在程序中就直接传递给visdom了。

相同点是两者都需要在程序外面启动。

2. API以及使用流程

2.1 API

  • tf.summary.FileWriter——用于将汇总数据写入磁盘
  • tf.summary.scalar——对标量数据汇总和记录
  • tf.summary.histogram——记录数据的直方图
  • tf.summary.image——将图像写入summary
  • tf.summary.merge——对各类的汇总进行一次合并
  • tf.summary.merge_all——合并默认图像中的所有汇总

2.2 使用流程

  1. 添加记录节点:tf.summary.scalar/image/histogram()等
  2. 汇总记录节点:merged = tf.summary.merge_all()
  3. 运行汇总节点:summary = sess.run(merged),得到汇总结果
  4. 日志书写器实例化:summary_writer = tf.summary.FileWriter(logdir, graph=sess.graph),实例化的同时传入 graph 将当前计算图写入日志
  5. 调用日志书写器实例对象summary_writer的add_summary(summary, global_step=i)方法将所有汇总日志写入文件
  6. 调用日志书写器实例对象summary_writer的close()方法写入内存,否则它每隔120s写入一次, close() 之后就无法再次写入了,需要重新打开reopen(),这里可以替代为summary_writer.flush()。

tensorboard使用流程图

3. 启动

1
tensorboard --logdir /path/to/log

4. 初始化

1
2
3
4
5
6
7
8
9
10
11
12
import tensorflow as tf

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

writer = tf.summary.FileWriter("/path/to/log", sess.graph(), flush_secs = 2)

# or
writer = tf.summary.FileWriter("/path/to/log")

# or
writer = tf.summary.FileWriter("/path/to/log")
writer.add_graph(sess.graph())

其他常用API

  • add_event(event):Adds an event to the event file
  • add_graph(graph, global_step=None):Adds a Graph to the event file,Most users pass a graph in the constructor instead
  • add_summary(summary, global_step=None):Adds a Summary protocol buffer to the event file,一定注意要传入 global_step
  • close():Flushes the event file to disk and close the file
  • flush():Flushes the event file to disk
  • add_meta_graph(meta_graph_def,global_step=None)
  • add_run_metadata(run_metadata, tag, global_step=None)

备注:这个event还是没有看懂怎么使用。

5. scalar

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import tensorflow as tf
# 三个工具:writer用于指定路径,sess用于运行,summary_op用于执行。
summary_writer = tf.summary.FileWriter("/path/to/log")
sess = tf.Session()

tf.summary.scalar('accuracy', accuracy) # tag, value

summary_op = tf.summary.merge_all()
summary_str = sess.run(summary_op)
summary_writer.add_summary(summary_str, global_step) # y, x
# 备注:global_step总是int型,即使输入0.4,在图像显示也是0.

# or family
tf.summary.scalar('loss1', 1, family='loss')
tf.summary.scalar('loss2', 2, family='loss')
tf.summary.scalar('loss3', 2)
# 示意如下图

family

或者自定义数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import tensorflow as tf
# 两个工具 summary_writer: 用于连接路径, summary: 用于指定y值
summary_writer = tf.summary.FileWriter("/path/to/log")
summary = tf.Summary(value=[
tf.Summary.Value(tag='test2', simple_value=0),
tf.Summary.Value(tag='test3', simple_value=1),
])
summary_writer.add_summary(summary, global_step) # y, x

# or
summary_writer = tf.summary.FileWriter("/path/to/log")
summary = tf.Summary()
summary.value.add(tag='test4', simple_value=0)
summary.value.add(tag='test5', simple_value=1)
sumamry_writer.add_summary(summary, global_step)

6. histogram

1
tf.summary.histogram('layer'+str(i+1)+'weights',weights)

这里的weights可以是list型,也可以是pytorch的tensor型,其他类型没试,但可以推断,一般情况下的都可以,猜测会统一转换为numpy型。

7. image

1
2
3
4
5
6
7
tf.summary.image('input', x_image, max_outputs=3)

# or
tf.summary.image('test', tf.reshape(images, [-1, 28, 28, 1]), 10)

# or
tf.summary.image('test1', torch.rand(3, 256, 256, 3))

备注:x_image必须是uint8或者float32型的4-D Tensor[batch_size, height, width, channels],其中channels为1, 3 或者4

对于numpy

1
2
3
4
5
6
7
8
9
10
from PIL import Image
import tensorflow as tf
import torch
from torchvision import transforms as T
image_ = Image.open('path')
image_numpy = numpy.array(image_) # 271, 108, 3
tf.summary.image('test1', image_numpy.reshape(1, 271, 108,3))
summary_op = tf.summary.merge_all()
summary_str = sess.run(summary_op)
summary_writer.add_summary(summary_str, global_step)

对于pytorch

1
2
3
4
5
6
7
8
9

from PIL import Image
image_ = Image.open('path') # 3, 271, 108
image_tensor = T.ToTensor()(image_)
tf.summary.image('test9', image_tensor.permute(1,2,0).reshape(1, 271, 108,3))
# 备注:将permute改为reshape之后不知道为什么会展示9空格的相同的黑白图片
summary_op = tf.summary.merge_all()
summary_str = sess.run(summary_op)
summary_writer.add_summary(summary_str, global_step)

uint8或者float32型的4-D Tensor[batch_size, height, width, channels],其中channels为1, 3 或者4

8. 多个event的可视化

如果 logdir 目录的子目录中包含另一次运行时的数据(多个 event),那么 TensorBoard 会展示所有运行的数据(主要是scalar),这样可以用于比较不同参数下模型的效果,调节模型的参数,让其达到最好的效果!

这个还有待测试

9. tensorboard_logger

tensorboard_logger可以暂时理解成简化版的tensorboard,或者是tensorboard的高级API。

tensorboard_logger依赖于tensorboard。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 安装
pip install tensorboard_logger
# 启动
tensorboard --logdir /path/to/log --port /port # 实际还是通过tensorboard来使用

# 初始化
from tensorboard_logger import Logger
logger = Logger(logdir='./logs', flush_secs=2)
# logger.logdir = './logs2' # 可以修改,尝试着修改了一下,发现没用,暂时用不着。
# logger.flush_secs = 3 # 可以修改
# API
logger.log_value('loss', 10, step=3) # step 可以不写,推荐写
# image_path = 'test.jpg'
# image_ = Image.open(image_path)
# image_numpy = np.array(image_)
logger.log_images('images', image_numpy.reshape(1,271,168,3), step=2) # 规则同上
logger.log_histogram('weights', torch.rand(2,3)+10, step=10)

# 函数tensorboard_logger.configure, tensorboard_logger.log_value与tensorboard_logger.Logger可以达到一样的效果
from tensorboard_logger import configure, log_value
configure("runs/run-1234", flush_secs=5)
log_value('v1', v1, step)

10. tensorboardX

https://github.com/lanpa/tensorboardX

tensorboardX也依赖于tensorflow和tensorboard。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 安装
pip install tensorboardX
# 启动
tensorboard --logdir /path/to/log --port /port

# 初始化
from tensorboardX import SummaryWriter
writer = SummaryWriter(logdir = 'tensorboard7', comment = 'test1', flush_secs = 1)
# 当有logdir时,comment被忽略,
# 当没有logdir时,只有comment(writer = SummaryWriter(comment = 'tensorboard7_test1', flush_secs = 1))会作为补充自动生成这样的文件目录:
# ./runs/Jan17_11-24-12_zbp-PowerEdge-T630tensorboard7_test1/events....
# 此外,任意tf.summary.FileWriter的参数都可以加上去。
writer.close()
# 没有writer.flush()

另一种写法

1
2
with SummaryWriter(logdir = 'tensorboard7') as w:
w.add_something()

不推荐with的写法,会自动重新创建一个文件,乱。

10.1 add_scalar

1
2
3
4
5
# API
writer.add_scalar('loss1', 2, global_step=2)
writer.add_scalars('loss', {'loss1':2, 'loss2':3}, global_step=2)
# 示例如下图,add_scalars可以将多个loss显示同一个图上,实现类似visdom的功能。
# add_scalars(main_tag,tag_scalar_dict,global_step=None)

add_scalar&add_scalars

备注::

  1. SummaryWriter以及之前的类似Writer都可以自动创建文件夹
  2. tensorboard —logdir /path/to/log会自动迭代该文件下的所有文件夹和文件,将event展示出来,并且将同名字的scalar放在一起,可以用于对比修改前后的结果

10.2 add_image

1
2
3
4
5
6
7
8
9
10
writer.add_image(tag, img_tensor, global_step=None)
# img_tensor: 图像数据,shape(3,H,W) 配合torchvision.utils.make_grid使用
# writer.add_image(tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'),
# dataformats: 'CHW', 'HWC', 'HW'

image_path = 'test.jpg'
image_ = Image.open(image_path)
image_tensor = T.ToTensor()(image_)
writer.add_image('test1', image_tensor, global_step=2)
writer.add_image('test2', torchvision.utils.make_grid(torch.rand(16, 3, 256,256), nrow=8, padding=20), global_step=2)

10.3 add_histogram

1
2
3
4
5
6
writer.add_histogram(tag,values,global_step=None,bins='tensorflow')
# bins: (string): one of {'tensorflow','auto', 'fd', ...}, this determines
# how the bins are made. You can find other options in:
# https://docs.scipy.org/doc/numpy/reference/generated/numpy.histogram.html
writer.add_histogram('test1', torch.rand(16, 3, 256,256), global_step=3)
# 感觉 bins 这个参数也差不多么

10.4 add_graph

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
from torch import nn
import torch

class Net1(nn.Module):
def __init__(self):
super(Net1, self).__init__()
self.conv1 = nn.Conv2d(3, 10, kernel_size=3, padding=0)
self.fc1 = nn.Linear(10, 100)
def forward(self, x ):
x = self.conv1(x)
x = x.view(-1, 10)
x = self.fc1(x)
x = torch.nn.functional.softmax(x, dim=1)
return x

input = torch.rand(4, 3, 3, 3)
model = Net1()
writer.add_graph(model, (input,))

add_graph(model, input_to_model, verbose=False)
# verbose 用于是否print

add_graph

终于pytorch也能显示graph了,不容易,应该提前熟悉这些API的。

11. 结论

综上所述,我觉得:

  • tensorboardX最适合非tensorflow的深度学习框架
  • tensorboard适合tensoflow
  • tensorboard_logger也适合非tensorflow的深度学习框架,可以看成简化版的tensorboardX
  • tensorboardX和tensorboard_logger可以互相替换
  • 开始使用tensorboardX作为我的新的可视化工具。

不太懂tensorboardX和tensorboard_logger之间的区别,难道是开发的人不一样?