visdom使用时需要打开server,可以通过在cmd中输入:
python -m visdom.server
#或者
py -m visdom.server
另外,也可以在cmd中直接输入:visdom。
同时还要在浏览器中输入网址:
http://localhost:8097
可以把打开网站操作通过程序实现:
import webbrowser
webbrowser.open('http://localhost:8097/')
下面结合https://github.com/fossasia/visdom/blob/master/example/demo.py官方给出的例子对常用操作逐一进行拆解,以方便使用。
其主要支持的api如下:
不常用操作(如stem、bar等)这里不进行描述。
以viz.text为例:
from visdom import Visdom
viz = Visdom()
textwindow = viz.text('Hello World!')
# close text window:
viz.close(win=textwindow)
查询该text窗口是否关闭:
viz.win_exists(textwindow)
见如下官方程序,可对某窗口win下的opts,layout属性进行更新。
具体例子可见 1.4.5 修改viz.scatter窗口的属性。
def update_window_opts(self, win, opts, env=None):
"""
This function allows pushing new options to an existing plot window
without updating the content
"""
data_to_send = {
'win': win,
'eid': env,
'layout': _opts2layout(opts),
'opts': opts,
}
return self._send(data_to_send, endpoint='update')
update模式 | 效果 |
---|---|
append | 在指定win中添加 |
remove | 在指定win中移除指定name的对象(如line) |
from visdom import Visdom
import numpy as np
viz = Visdom()
# line plots
# line updates
win = viz.line(
X=np.column_stack((np.arange(0, 10), np.arange(0, 10))),
Y=np.column_stack((np.linspace(5, 10, 10),
np.linspace(5, 10, 10) + 5)),
)
viz.line(
X=np.arange(1, 10),
Y=np.arange(11, 20),
win=win,
name='delete this',
update='append'
)
viz.line(X=None, Y=None, win=win, name='delete this', update='remove')
from visdom import Visdom
import numpy as np
viz = Visdom()
# image demo save as jpg
viz.image(
np.random.rand(3, 256, 256),
opts=dict(title='Random image as jpg!', caption='How random as jpg.', jpgquality=50),
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# image history demo
viz.image(
np.random.rand(3, 256, 256),
win='image_history',
opts=dict(caption='First random', store_history=True, title='Pick your random!'),
)
viz.image(
np.random.rand(3, 256, 256),
win='image_history',
opts=dict(caption='Second random!', store_history=True),
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# grid of images
```python
viz.images(
np.random.randn(20, 3, 64, 64),
opts=dict(title='Random images', caption='How random.')
)
正如官方程序中所述,Given a 4D tensor of shape (B x C x H x W), or a list of images all of the same size, makes a grid of images of size (B / nrow, nrow)。
def images(self, tensor, nrow=8, padding=2,
win=None, env=None, opts=None):
默认一行显示8张图片。
from visdom import Visdom
import numpy as np
viz = Visdom()
# line plots
viz.line(Y=np.random.rand(10), opts=dict(showlegend=True))
Y = np.linspace(-5, 5, 100)
viz.line(
Y=np.column_stack((Y * Y, np.sqrt(Y + 5))),
X=np.column_stack((Y, Y)),
opts=dict(markers=False),
)
from visdom import Visdom
import numpy as np
viz = Visdom()
win = viz.line(
X=np.column_stack((
np.arange(0, 10),
np.arange(0, 10),
np.arange(0, 10),
)),
Y=np.column_stack((
np.linspace(5, 10, 10),
np.linspace(5, 10, 10) + 5,
np.linspace(5, 10, 10) + 10,
)),
opts={
'dash': np.array(['solid', 'dash', 'dashdot']),
'linecolor': np.array([
[0, 191, 255],
[0, 191, 255],
[255, 0, 0],
]),
'title': 'Different line dash types'
}
)
viz.line(
X=np.arange(0, 10),
Y=np.linspace(5, 10, 10) + 15,
win=win,
name='4',
update='insert',
opts={
'linecolor': np.array([
[255, 0, 0],
]),
'dash': np.array(['dot']),
}
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# 2D scatter plot with custom colors per label:
viz.scatter(
X=np.random.rand(255, 2),
Y=(np.random.randn(255) > 0) + 1,
#Y=(np.random.rand(255) + 1.5).astype(int),
opts=dict(
markersize=10,
markercolor=np.floor(np.random.random((2, 3)) * 255),
markerborderwidth=0,
),
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# 2D scatter plot with text labels:
viz.scatter(
X=np.random.rand(6, 2),
Y=[1] * 2 + [2] * 3 + [3] * 1,
opts=dict(
xtickmin=0,
xtickmax=1,
legend=['A', 'B', 'C'],
textlabels=['Label %d' % (i + 1) for i in range(6)]
)
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# scatter plot example with various type of updates
colors = np.random.randint(0, 255, (2, 3,))
win = viz.scatter(
X=np.random.rand(5, 2),
Y=(np.random.rand(5) + 1.5).astype(int),
opts=dict(
markersize=10,
markercolor=colors,
legend=['1', '2']
),
)
viz.scatter(
X=np.random.rand(3),
Y=np.random.rand(3),
opts=dict(
markersize=10,
markercolor=colors[0].reshape(-1, 3),
),
name='3',
update='append',
win=win)
from visdom import Visdom
import numpy as np
viz = Visdom()
Y = np.random.rand(100)
# 3d scatterplot with custom labels and ranges
viz.scatter(
X=np.random.rand(100, 3),
Y=(Y + 1.5).astype(int),
opts=dict(
legend=['Men', 'Women'],
markersize=5,
xtickmin=0,
xtickmax=2,
xlabel='Arbitrary',
xtickvals=[0, 0.75, 1.6, 2],
ytickmin=0,
ytickmax=2,
ytickstep=0.5,
ztickmin=0,
ztickmax=1,
ztickstep=0.5,
)
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# scatter plots
Y = np.random.rand(100)
old_scatter = viz.scatter(
X=np.random.rand(100, 2),
Y=(Y[Y > 0] + 1.5).astype(int),
opts=dict(
legend=['Didnt', 'Update'],
xtickmin=-50,
xtickmax=50,
xtickstep=0.5,
ytickmin=-50,
ytickmax=50,
ytickstep=0.5,
markersymbol='cross-thin-open',
),
)
viz.update_window_opts(
win=old_scatter,
opts=dict(
legend=['Apples', 'Pears'],
xtickmin=0,
xtickmax=1,
xtickstep=0.5,
ytickmin=0,
ytickmax=1,
ytickstep=0.5,
markersymbol='cross-thin-open',
),
)
可以看出old_scatter窗口由于坐标轴的原因,显示极不合理,通过修改部分属性,update_window_opts后显示就完美了。
from visdom import Visdom
import numpy as np
viz = Visdom()
# heatmap
viz.heatmap(
X=np.outer(np.arange(1, 6), np.arange(1, 11)),
opts=dict(
columnnames=['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'],
rownames=['y1', 'y2', 'y3', 'y4', 'y5'],
colormap='Electric',
)
)
from visdom import Visdom
import numpy as np
viz = Visdom()
# contour
x = np.tile(np.arange(1, 101), (100, 1))
y = x.transpose()
X = np.exp((((x - 50) ** 2) + ((y - 50) ** 2)) / -(20.0 ** 2))
viz.contour(X=X, opts=dict(colormap='Viridis'))
from visdom import Visdom
viz = Visdom()
try:
import matplotlib.pyplot as plt
plt.plot([1, 23, 2, 4])
plt.ylabel('some numbers')
viz.matplot(plt)
except BaseException as err:
print('Skipped matplotlib example')
print('Error message: ', err)
安装(pip3 install graphviz)及使用过程都比较简单。
需要说明的是hiddenlayer主要使用了graphviz进行绘图,因此使用hiddenlayer ,必须首先安装graphviz。
具体方法可参考python graphviz安装。
以参考文献3中给出的模型为例,介绍下其使用过程,同时也方便比较hiddenlayer与Netron模型可视化的结果。
import torch
import torch.nn as nn
import torch.nn.functional as F
import hiddenlayer as hl
class model(nn.Module):
def __init__(self):
super(model, self).__init__()
self.block1 = nn.Sequential(
nn.Conv2d(64, 64, 3, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 32, 1, bias=False),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.Conv2d(32, 64, 3, padding=1, bias=False),
nn.BatchNorm2d(64)
)
self.conv1 = nn.Conv2d(3, 64, 3, padding=1, bias=False)
self.output = nn.Sequential(
nn.Conv2d(64, 1, 3, padding=1, bias=True),
nn.Sigmoid()
)
def forward(self, x):
x = self.conv1(x)
identity = x
x = F.relu(self.block1(x) + identity)
x = self.output(x)
return x
if __name__ == '__main__':
d = torch.rand(1, 3, 416, 416)
m = model()
o = m(d)
hl.build_graph(m, d)
产生的可视化结果:
需注意的是,在非jupyter_notebook环境下,需要使用命令行执行:
hl.build_graph(m, d)
python安装目录\Lib\site-packages\hiddenlayer\graph.py
文件class Graph()
中的rankdir变量:# rankdir="TD" 可视化自上而下top-down打印
# rankdir="LR" 可视化从左到右left-right打印
def _repr_svg_(self):
"""Allows Jupyter notebook to render the graph automatically."""
self.save("D:\\modle.gv")
return self.build_dot()
def save(self, path, format="pdf"):
# TODO: assert on acceptable format values
dot = self.build_dot()
dot.format = format
directory, file_name = os.path.split(path)
# Remove extension from file name. dot.render() adds it.
file_name = file_name.replace("." + format, "")
dot.render(file_name, directory=directory, view=True, cleanup=True,)
这里是拷贝了参考文献3 知乎 https://zhuanlan.zhihu.com/p/197737707的内容:
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.onnx
import netron
class model(nn.Module):
def __init__(self):
super(model, self).__init__()
self.block1 = nn.Sequential(
nn.Conv2d(64, 64, 3, padding=1, bias=False),
nn.BatchNorm2d(64),
nn.ReLU(inplace=True),
nn.Conv2d(64, 32, 1, bias=False),
nn.BatchNorm2d(32),
nn.ReLU(inplace=True),
nn.Conv2d(32, 64, 3, padding=1, bias=False),
nn.BatchNorm2d(64)
)
self.conv1 = nn.Conv2d(3, 64, 3, padding=1, bias=False)
self.output = nn.Sequential(
nn.Conv2d(64, 1, 3, padding=1, bias=True),
nn.Sigmoid()
)
def forward(self, x):
x = self.conv1(x)
identity = x
x = F.relu(self.block1(x) + identity)
x = self.output(x)
return x
if __name__ == '__main__':
d = torch.rand(1, 3, 416, 416)
m = model()
o = m(d)
onnx_path = "D:\\onnx_model_name.onnx"
torch.onnx.export(m, d, onnx_path)
netron.start(onnx_path)
结果会在网页http://localhost:8080/显示:
通过比较我们可以发现Netron是完全逐模块可视化的,而hiddenlayer内部则集成了子模块折叠的方法。
另外,Netron是从input开始可视化直至output,而hiddenlayer则默认从第一个模块开始。
如果提示下述错误:
RuntimeError: Unsupported: ONNX export of index_put in opset 11. Please try opset version 11.
可通过设置opset_version进行修改:
torch.onnx.export(model, d, onnx_path,opset_version=11)
[1] https://github.com/waleedka/hiddenlayer/blob/master/demos/pytorch_graph.ipynb
[2] https://github.com/lutzroeder/Netron
[3] https://zhuanlan.zhihu.com/p/197737707
[4] https://ptorch.com/news/77.html
[5] colab wandb pytorch/Simple_PyTorch_Integration
[6] github.com/wandb/examples