使用教程,参考:javascript
https://github.com/facebookresearch/visdom前端
https://www.pytorchtutorial.com/using-visdom-for-visualization-in-pytorch/java
https://www.pytorchtutorial.com/pytorch-visdom/python
⚠️中间发现visdom安装的版本太低,致使发生了一些问题,后面更改了版本为最新版本0.1.8.8,因此可能会发现截图有些不一样,可是功能不会有太多影响git
Visdom是Facebook专门为PyTorch开发的一款可视化工具,其开源于2017年3月。Visdom十分轻量级,但却支持很是丰富的功能,能胜任大多数的科学运算可视化任务。github
Visdom能够创造、组织和共享多种数据的可视化,包括数值、图像、文本,甚至是视频,其支持PyTorch、Torch及Numpy。用户可经过编程组织可视化空间,或经过用户接口为生动数据打造仪表板,检查实验结果或调试代码。web
Visdom中有两个重要概念:正则表达式
main
。不一样用户、不一样程序通常使用不一样的env。使用Visdom就是在env中的pane上画图。编程
1.envsjson
您可使用envs对可视化空间进行分区。默认地,每一个用户都会有一个叫作main的envs。
1)建立新环境
能够经过编程或UI建立新的envs。envs的状态是长期保存的。
修改env的名字后点击fork,保存当前env的状态至改名后的env
而后就会生成该新命名的环境:
而后可见在$HOME/.visdom/文件中也生成了相应的json文件:
您能够经过http://localhost:8097/env/test访问特定的env。若是您的服务器是被托管的,那么您能够将此url分享给其余人,那么其余人也会看到您的可视化结果。
在初始化服务器的时候,您的 envs 默认经过$HOME/.visdom/ 加载。您也能够将自定义的路径看成命令行参数传入。若是您移除了$HOME/.visdom/文件夹下的.json文件,那么相应的环境也会被删除。
使用命令python -m visdom.server开启visdom时可使用的命令行参数有:
-port
: 指定运行服务的端口.-hostname
: 指定运行服务的主机名.-base_url
: 指定初始网址(default = /).-env_path
: 指定序列会话从新下载的路径T-logging_level
: 日志级别(default = INFO).同时接受标准文本和数字日志值-readonly
: 标记再只读模式下开启服务-enable_login
: 标记为服务设置权限,须要用户名和密码来登陆服务-force_new_cookie
: 标记重置服务使用的安全cookie,禁用当前的登陆cookie。须要和-enable_login
一块儿使用
2)清除和保存
点击clear按钮能够清空当前env的全部pane,点击save按钮可将当前env保存成json文件,保存路径位于~/.visdom/
目录下。
新版本为:
新版本的clear为:
2.Panes
UI刚开始是个白板–您能够用图像,图片,文本填充它。这些填充的数据出如今 Panes 中,您能够这些Panes进行 拖放,删除,调整大小和销毁操做。Panes是保存在 envs 中的, envs的状态存储在会话之间。您能够下载Panes中的内容–包括您在svg中的绘图。
举例:
import visdom
import numpy as np vis = visdom.Visdom() #默认使用的env是main vis.text('Hello, world') #打印些字符 vis.image(np.ones((3,10,10))) #复制上面的图
返回:
'pane_3738d21f24c328'
图示:
而后点击save,可见终端命令为:
from web client: {"cmd":"save","data":{"pane_3738d212484eec":null,"pane_3738d21f1f0050":null,"pane_3738d21f24c328":null},"prev_eid":"main","eid":"main"}
而后查看json文件:
存储了以下的信息:
python Visdom实现支持窗口上的回调。演示以可编辑文本pad的形式展现了一个示例。这些回调的功能容许Visdom对象接收并响应前端发生的事件。
您能够经过使用您的handler处理程序和窗口id调用viz.register_event_handler(handler, win_id)来为你想要订阅的窗口id向事件handler处理程序字典添加一个函数来订阅窗口到事件中。多个handler处理程序能够注册到同一个窗口。您可使用viz.clear_event_handlers(win_id)从窗口中删除全部事件handler处理程序。当事件发生在该窗口时,您的callback回调将调用一个包含如下内容的dict:
event_type
: 某个下面事件类型pane_data
: 该窗口的全部存储内容,包括布局和内容。eid
: 当前环境idtarget
: 该事件调用的环境id额外的参数定义在下方
如今支持以下的三个回调事件:
Close
- 当窗口关闭时触发,返回只有上述字段的dict字典。KeyPress
- 按键时触发。包含额外的参数:key
- 按键的字符串表示(应用状态修饰符,如SHIFT)key_code
- 按键的javascript事件键码(没有修饰符)PropertyUpdate
- 在属性窗格中更新属性时触发propertyId
- 更改的属性在属性列表中的位置value
- 新属性的值Tip: 您可使用浏览器的放大缩小功能来调整UI的大小。
3.State
一旦您建立了一些可视化,状态是被保存的。服务器自动缓存您的可视化–若是您从新加载网页,您的可视化会从新出现。
4.Filter
您可使用filter动态筛选env中出现的窗口——只需提供一个正则表达式来匹配要显示的窗口标题。这在涉及具备多个窗口的env的用例中颇有用,例如在系统地检查实验结果时。
如:
5.Views
能够简单地经过拖拽窗口顶部来管理视图,可是还存在其余功能来保持视图的组织和保存公共视图。视图管理对于在windows的多个公共组织之间保存和切换很是有用。
Saving/Deleting Views
使用文件夹图标,将打开一个对话框窗口,其中视图能够以与env相同的方式分叉。保存视图将保留给定环境中全部窗口的位置和大小。视图保存在$HOME/.visdom/view/layout中。visdom文件路径中的json。
好比:
import numpy as np from visdom import Visdom viz = Visdom() viz.image( np.random.rand(3, 512, 256), #随机生成一张图 opts = dict(title = 'Random!', caption = 'how random'), )
图示:
而后将该views保存为views1,而后点击fork:
而后到相应的文件夹下面就可以看见生成了layouts.json文件
注意:保存的视图是静态的,编辑保存的视图会将视图复制到当前视图,在当前视图中能够进行编辑。
使用repack图标(9个框),visdom将尝试以最适合的方式打包窗口,同时保留行/列的顺序。
注意:因为依赖行/列排序和ReactGridLayout,最终的布局可能与预期略有不一样。咱们正在努力改善这种体验,或提供更多的替代方案,以实现更精确的控制。
使用视图下拉框能够选择之前保存的视图,将当前环境中全部窗口的位置和大小恢复到上次保存视图时的位置。
6.API
下面测试须要导入的包:
from __future__ import absolute_import from __future__ import division from __future__ import print_function from __future__ import unicode_literals from visdom import Visdom import argparse import numpy as np import math import os.path import time import tempfile from six.moves import urllib DEFAULT_PORT = 8097 DEFAULT_HOSTNAME = "http://localhost"
而后设置:
viz = Visdom(port=DEFAULT_PORT, server=DEFAULT_HOSTNAME)
1)visdom参数(python only)
当客户端使用命令调用visdom时,写法相似:
viz = visdom.Visdom() #使用参数进行设置
可使用的参数有:
2)基本可视化函数
vis.image
: 图片vis.images
: 图片列表vis.text
: 抽象HTMLvis.properties
: 属性网格vis.audio
: 音频vis.video
: 视频vis.svg
: SVG对象vis.matplot
: matplotlib图vis.save
: 序列化状态服务端
如下opts选项是通用的,由于它们对于全部可视化都是相同的(除了plot.image, plot.text, plot.video, and plot.audio):
opts.title
: 图标题opts.width
: 图宽opts.height
: 图高opts.showlegend
: 显示图例 (true
or false
)opts.xtype
: x轴的类型 ('linear'
or 'log'
)opts.xlabel
: x轴的标签opts.xtick
: 显示x轴上的刻度 (boolean
)opts.xtickmin
: 指定x轴上的第一个刻度 (number
)opts.xtickmax
: 指定x轴上的最后一个刻度 (number
)opts.xtickvals
: x轴上刻度的位置(table
of number
s)opts.xticklabels
: 在x轴上标记标签 (table
of string
s)opts.xtickstep
: x轴上刻度之间的距离 (number
)opts.xtickfont
:x轴标签的字体 (dict of font information)opts.ytype
: type of y-axis ('linear'
or 'log'
)opts.ylabel
: label of y-axisopts.ytick
: show ticks on y-axis (boolean
)opts.ytickmin
: first tick on y-axis (number
)opts.ytickmax
: last tick on y-axis (number
)opts.ytickvals
: locations of ticks on y-axis (table
of number
s)opts.yticklabels
: ticks labels on y-axis (table
of string
s)opts.ytickstep
: distances between ticks on y-axis (number
)opts.ytickfont
: font for y-axis labels (dict of font information)opts.marginleft
: 左边框 (in pixels)opts.marginright
:右边框 (in pixels)opts.margintop
: 上边框 (in pixels)opts.marginbottom
: 下边框 (in pixels)其余选项是具体于某些可视化的,并在下面的函数文档中进行了描述。
1》vis.image
该函数绘制一张img图。它将输入设置为一个包含图像的大小为CxHxW的tensor img
支持的opts有:
opts.jpgquality
: JPG 质量 (number
0-100; default = 100)opts.caption
: 图片标题⚠️能够在图像窗格上使用alt查看光标的x/y坐标。您还能够ctrl-scroll来缩放,alt- scroll来垂直平移,alt-shift来水平平移。双击窗格内,将图像恢复为默认值。
举例:
# image demo
viz.image(
np.random.rand(3, 512, 256), opts=dict(title='Random!', caption='How random.'), )
图示:
回调函数:
底图为:
viz = Visdom()
assert viz.check_connection(timeout_seconds=3), \ 'No connection could be formed quickly' # image callback demo def show_color_image_window(color, win=None): image = np.full([3, 256, 256], color, dtype=float) return viz.image( image, opts=dict(title='Colors', caption='Press arrows to alter color.'), win=win ) image_color = 0 callback_image_window = show_color_image_window(image_color)
设置回调:
def image_callback(event): global image_color if event['event_type'] == 'KeyPress': if event['key'] == 'ArrowRight': image_color = min(image_color + 0.2, 1) if event['key'] == 'ArrowLeft': image_color = max(image_color - 0.2, 0) show_color_image_window(image_color, callback_image_window) viz.register_event_handler(image_callback, callback_image_window)
图示:
而后能够经过左右键来调节该图的颜色,直至白色,调到中间可见变为:
2》vis.images
该函数绘制一列图。它取一个输入为B x C x H x W大小的张量或一组大小相同的图像。它生成一个大小为(B / nrow, nrow)的图像网格。
支持的opts有:
nrow
: 一行图像的数量padding
: 图像四周的边距,等于4条边的边距opts.jpgquality
: JPG质量 (number
0-100; default = 100)opts.caption
: 图片标题举例:
# grid of images
viz.images(
np.random.randn(20, 3, 64, 64), opts=dict(title='Random images', caption='How random.') )
图示:
设置行数nrow:
# grid of images
viz.images(
np.random.randn(20, 3, 64, 64), opts=dict(title='Random images', caption='How random.'), nrow=5 )
图示:
3》vis.text
该函数在box中打印文本。您可使用它来嵌入任意的HTML。输入是一个文本string。目前没有具体支持的opts
举例:
viz = Visdom(port=DEFAULT_PORT, server=DEFAULT_HOSTNAME)
assert viz.check_connection(timeout_seconds=3), \ 'No connection could be formed quickly' textwindow = viz.text('Hello World!') #生成一个窗口,里面带文本Hello World! #生成另外一个窗口,里面带文本Hello World! More text should be here updatetextwindow = viz.text('Hello World! More text should be here') #断言查看updatetextwindow窗口对象是否存在 assert updatetextwindow is not None, 'Window was none' #窗口存在的话,就在该窗口中添加下面的文本,win指定添加到的窗口对象,append指定进行的操做是在元原有的基础上添加 viz.text('And here it is', win=updatetextwindow, append=True)
返回生成的窗口编号:
'window_373974331dca16'
图示:
带有回调的操做:
#带Callbacks回调的文本窗口
txt = 'This is a write demo notepad. Type below. Delete clears text:<br>' callback_text_window = viz.text(txt) #声明回调时调用的函数,这个函数使得窗口可以被编辑 def type_callback(event): #首先判断是否是在窗口处进行了按键操做 if event['event_type'] == 'KeyPress': #若是是,那就将如今的窗口的数据内容做为curr_txt变量的值 curr_txt = event['pane_data']['content'] #若是输入的是回车,就会在变量curr_txt中添加一个换行符,这样在窗口中的文本就会换行 if event['key'] == 'Enter': curr_txt += '<br>' #若是输入的是删除键,就使用索引[:-1]删除最后一个值 elif event['key'] == 'Backspace': curr_txt = curr_txt[:-1] #若是输入的是删除键,mac中是fn+Backspace,那么就返回原始状态 elif event['key'] == 'Delete': curr_txt = txt #若是只是添加一些内容:字符数字等的操做,就直接添加在curr_txt后面便可 elif len(event['key']) == 1: curr_txt += event['key'] #而后根据上面对curr_txt的操做,再在callback_text_window窗口对象中覆盖内容curr_txt实现编辑 viz.text(curr_txt, win=callback_text_window) #而后将该处理程序和窗口链接起来 viz.register_event_handler(type_callback, callback_text_window)
图示:
4》vis.properties
该函数在窗口中显示可编辑的属性。属性是一个字典的列表,以下所示:
properties = [
{'type': 'text', 'name': 'Text input', 'value': 'initial'}, {'type': 'number', 'name': 'Number input', 'value': '12'}, {'type': 'button', 'name': 'Button', 'value': 'Start'}, {'type': 'checkbox', 'name': 'Checkbox', 'value': True}, {'type': 'select', 'name': 'Select', 'value': 1, 'values': ['Red', 'Green', 'Blue']}, ]
支持的type属性有:
value
:可选值的id (从0开始)values
: 可能值的列表当属性值更新时callback被调用:
event_type
: 这个命令的类型为"PropertyUpdate"
propertyId
: 更新的值在属性列表中的位置value
: 更新的新值目前没有具体支持的opts
举例:
首先要实现text的回调,不然在下面更改number input的内容时会报错:
ERROR:websocket:error from callback <function Visdom.setup_socket.<locals>.on_message at 0x1039c2488>: name 'callback_text_window' is not defined
text回调为:
# text window with Callbacks
txt = 'This is a write demo notepad. Type below. Delete clears text:<br>' callback_text_window = viz.text(txt) def type_callback(event): if event['event_type'] == 'KeyPress': curr_txt = event['pane_data']['content'] if event['key'] == 'Enter': curr_txt += '<br>' elif event['key'] == 'Backspace': curr_txt = curr_txt[:-1] elif event['key'] == 'Delete': curr_txt = txt elif len(event['key']) == 1: curr_txt += event['key'] viz.text(curr_txt, win=callback_text_window) viz.register_event_handler(type_callback, callback_text_window)
实现:
# Properties window
properties = [ {'type': 'text', 'name': 'Text input', 'value': 'initial'}, {'type': 'number', 'name': 'Number input', 'value': '12'}, {'type': 'button', 'name': 'Button', 'value': 'Start'}, {'type': 'checkbox', 'name': 'Checkbox', 'value': True}, {'type': 'select', 'name': 'Select', 'value': 1, 'values': ['Red', 'Green', 'Blue']}, ] properties_window = viz.properties(properties)
返回:
实现回调:
#这样就可以对表格中的属性进行更改
def properties_callback(event): if event['event_type'] == 'PropertyUpdate': prop_id = event['propertyId'] value = event['value'] #更改Text input的内容,并在后面添加进_updated if prop_id == 0: new_value = value + '_updated' #更改Number input,改为更改的值并在后面添加0 elif prop_id == 1: new_value = value + '0' #更改Button,点击使其在start和stop中更改 elif prop_id == 2: new_value = 'Stop' if properties[prop_id]['value'] == 'Start' else 'Start' #当更改的是checkbox和Select时 else: new_value = value properties[prop_id]['value'] = new_value viz.properties(properties, win=properties_window) viz.text("Updated: {} => {}".format(properties[event['propertyId']]['name'], str(event['value'])), win=callback_text_window, append=True) viz.register_event_handler(properties_callback, properties_window)
返回:
可见当我将Text input的内容改为change once后回车,改处的值就变成了:
当我更改Number input处为13,就可见其后面添加了一个0:
固然我还进行了一些其余的操做,一些相应的更改信息会写在text窗口中:
5》vis.audio
该函数播放音频。它将音频文件的文件名或包含波形的N张量做为输入(立体声音频使用Nx2矩阵)。该函数不支持任何特定plot的opts选项。
支持的opts有:
opts.sample_frequency
: 采样频率 (integer
> 0; default = 44100)已知问题:Visdom使用scipy将张量输入转换为wave文件。Chrome的一些版本不播放这些wave文件(Firefox和Safari运行良好)。
运行:
# audio demo:
tensor = np.random.uniform(-1, 1, 441000) viz.audio(tensor=tensor, opts={'sample_frequency': 441000})
返回:
但好像并不能真正播放
使用真正的音频文件 :
# audio demo:
# download from http://www.externalharddrive.com/waves/animal/dolphin.wav try: audio_url = 'http://www.externalharddrive.com/waves/animal/dolphin.wav' audiofile = os.path.join(tempfile.gettempdir(), 'dolphin.wav') urllib.request.urlretrieve(audio_url, audiofile) if os.path.isfile(audiofile): viz.audio(audiofile=audiofile) except BaseException: print('Skipped audio example')
图示:
而且真正能播放声音
6》vis.video
该函数播放视频。它以视频文件的文件名或包含视频全部帧的LxHxWxC大小的张量做为输入。该函数不支持任何特定plot的选项。
支持的opts有:
opts.fps
: 视频的FPS (integer
> 0; default = 25)注意:使用张量输入须要安装ffmpeg并使其工做。您播放视频的能力可能取决于您使用的浏览器:您的浏览器必须在OGG容器中支持Theano编解码器(Chrome支持这一点)。
举例:
使用tensor
video = np.empty([256, 250, 250, 3], dtype=np.uint8) for n in range(256): video[n, :, :, :].fill(n) viz.video(tensor=video)
运行时会出错:
ModuleNotFoundError: No module named 'cv2'
解决办法:
(deeplearning) userdeMBP:~ user$ pip install opencv-python
...
Successfully installed opencv-python-4.0.0.21
可是仍是会出现问题:
local variable 'fourcc' referenced before assignment
这是由于安装的opencv版本在4及以上的缘由,由于源码 /anaconda3/envs/deeplearning/lib/python3.6/site-packages/visdom/__init__.py 中:
elif cv2.__version__.startswith('3'): # OpenCV 3 ,指定使用版本3 fourcc = cv2.VideoWriter_fourcc( chr(ord('T')), chr(ord('H')), chr(ord('E')), chr(ord('O')) ) writer = cv2.VideoWriter( videofile, fourcc, opts.get('fps'), (tensor.shape[2], tensor.shape[1]) )
解决办法是将上面的命令改为:
elif cv2.__version__.startswith(('3', '4')):
可是我好像没有起效果,因此后面我把opencv-python改为3版本:
pip install opencv-python==3.4.5.20
记住,必定要重启visdom ,最后返回,该视频可播放:
使用已有视频文件
try: # video demo: # download video from http://media.w3.org/2010/05/sintel/trailer.ogv video_url = 'http://media.w3.org/2010/05/sintel/trailer.ogv' videofile = os.path.join(tempfile.gettempdir(), 'trailer.ogv') urllib.request.urlretrieve(video_url, videofile) if os.path.isfile(videofile): #使用opts设定窗口的大小 viz.video(videofile=videofile, opts={'width': 864, 'height': 480}) except BaseException: print('Skipped video file example')
须要等待一段时间,而后就会返回一个窗格,点击该窗格就会开始播放视频:
7》vis.svg
该函数绘制一个SVG对象。它接受SVG字符串svgstr或SVG文件svgfile的名称做为输入。该函数不支持任何特定的选项。
举例:
# SVG plotting
svgstr = """ <svg height="300" width="300"> <ellipse cx="80" cy="80" rx="50" ry="30" style="fill:red;stroke:purple;stroke-width:2" /> Sorry, your browser does not support inline SVG. </svg> """ viz.svg( svgstr=svgstr, opts=dict(title='Example of SVG Rendering') )
图示:
8》vis.matplot
该函数绘制Matplotlib图。该函数支持一个特定于场景的选项:resizable
⚠️当resizable设置为True时,将使用窗格调整绘图的大小。您须要安装beautifulsoup4和lxml包来使用此选项。
⚠️matplot不是使用与plotly图相同的后端呈现的,并且效率略低。使用太多matplot窗口可能会下降visdom性能。
举例:
# matplotlib demo:
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)
图示:
9》vis.plotlyplot
这个函数绘制一个图形对象。它并不像它假设您已经显式配置了图形的布局那样显式地接受选项。
⚠️必须安装了plotly Python包才能使用此函数。它一般能够经过运行pip install来安装。
10》vis.save
这个函数保存了在visdom服务器上活动的env。它接受要保存的env id的输入列表(在python中)或表(在lua中)做为输入。
好比你想要保存如今在环境'main'上的数据,否则它是不会记录到其相应的main.json文件中的:
vis.save(['main'])
⚠️环境名参数envs是list