pytorch训练可视化包visdom的使用

Posted 高山莫衣

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了pytorch训练可视化包visdom的使用相关的知识,希望对你有一定的参考价值。

visdom的使用

一、简介

Visdom是一个基于Python的可视化工具包,可以用于PyTorch等深度学习框架中的实时数据可视化。它提供了一个Web界面,可以方便地创建图表、散点图和直方图等可视化元素。相比tensorboardrensorboardX具有更轻量、更便捷、更丰富、更快速等特点。

visdom的github主页:https://github.com/fossasia/visdom

visdom的中文参考文档:https://ptorch.com/news/77.html

visdom的优秀教程:https://blog.csdn.net/weixin_41010198/article/details/117853358

二、安装与启动

使用Visdom需要先安装visdom包,可以通过pip命令进行安装:

pip install visdom

接下来,在cmd或者Anaconda中使用python -m visdom.server启动服务。并在浏览器中输入提示的端口,并且需要保持黑框框cmdAnaconda)一直开启。


当你打开后,会呈现一个空白的界面,是因为目前还没有写入任何图形。

三、设计思路

假设你的电脑C盘中有很多文件夹,每个文件夹有很多文件,每个文件可以填入你想要的信息。

同样,visdom启动服务后,呈现出一个网页页面,会随时根据你电脑跑的程序中有关visdom的部分,呈现出可视化图。这个网页中,可以选择不同的文件夹进行存储,让你的图文件分门别类,比如程序A相关的图存在A文件夹中,程序B相关的图存在B文件夹下,当然也可以各个程序生成的图都存在C文件夹下。每个文件夹中可以画不同的图,每个图也可以画多个点、线、柱等等。

在每个文件夹下,可以存入视频图像文本等等

图像分为图片、以及生成的一些数据图,这里简单介绍一下生成的数据图,比如折线图

vis.scatter:2D或3D散点图
vis.line:线图
vis.stem:stem图
vis.heatmap:热图地块
vis.bar:条形图
vis.histogram:直方图
vis.boxplot:盒子
vis.surf:表面重复
vis.contour:等高线图
vis.quiver:颤抖的情节
vis.mesh:网格图
vis.dual_axis_lines:双y轴线图

四、在迭代训练中的绘图

首先创建一个可视化界面和文件夹:

import visdom

viz = visdom.Visdom(env='main-8')

其中env='main-8' 表示一个文件夹名称,main-8可以替换为其他名称,倘若不写该参数,则默认存储在env='main'中,接下来,我们使用viz进行操作,就意味着操作对应的图存在'main-8'中。
此时,打开网页,会看到有两个环境Environment,一个是“main”,一个是“main-8”

创建好文件夹后,接下来,我们在这个文件夹下面写一些图。
先打开网页,确保是“online”在线模式

为了模拟迭代过程,这里设计一个循环语句。执行代码

import visdom

viz = visdom.Visdom(env='main-8')

viz.line(X=[0.],  # x坐标
         Y=[0.],  # y值
        win="line1",  # 窗口id
        name="Adam梯度",  # 线条名称
        update='append',  # 以添加方式加入
        opts=
            'showlegend': True,  # 显示网格
            'title': "Demo line in Visdom",
            'xlabel': "x1",  # x轴标签
            'ylabel': "y1",  # y轴标签
        ,)

for i in range(10):
    viz.line(X=[i], Y=[i*2],name="Adam梯度", win='line1', update='append')

    viz.line(X=[i], Y=[i**2],name="SGD梯度", win='line1', update='append')

    viz.line(X=[i], Y=[5*i+2],name="GDM梯度", win='line1', update='append')

先看一下,生成的结果。打开网页

假设现在我想要在main-8文件夹下面,画另外一个图,执行程序

import visdom

vizs = visdom.Visdom(env='main-8')

vizs.line(X=[0.],  # x坐标
         Y=[0.],  # y值
        win="line2",  # 窗口id
        name="Adam梯度",  # 线条名称
        update='append',  # 以添加方式加入
        opts=
            'showlegend': True,  # 显示网格
            'title': "Demo line in Visdom-1",
            'xlabel': "x1",  # x轴标签
            'ylabel': "y1",  # y轴标签
        ,)

for i in range(10):
    vizs.line(X=[i], Y=[5*i**3],name="Adam梯度", win='line2', update='append')

    vizs.line(X=[i], Y=[i**2],name="SGD梯度", win='line2', update='append')

查看结果

上面的内容,还不具有一般性,下面给出部分代码示例和效果图,以满足实际中的复杂需求

背景:假设,现在有一批数据,数据来自总体一元线性方程,我们根据A、B、C三种梯度下降算法,在不同的采样率rate下,对比分析,三种梯度下降算法中的损失值w值b值

描述:
图1:loss损失图,横轴为采样比rate、纵轴为loss损失值,图中有3个折线,对应A(无梯度)、B(小梯度)、C(随机梯度)三种梯度下降方法
同理,图2为w值图,图3为b值图,其余类似。

生成文件夹下面的三个图窗口,生成图窗口只需要执行一次就行,放在env='main-9'文件夹中

name_1 = '无梯度'
name_2 = '小梯度'
name_3 = '随机梯度'



import visdom

viz = visdom.Visdom(env='main-9')


window_loss = viz.line(
        X=[0.1],  # x坐标
        Y=[0.],  # y值
        win="line_loss_1",  # 窗口id
        name= name_1,  # 线条名称
        update='append',  # 以添加方式加入
        opts=
            'showlegend': True,  # 显示网格
            'title': "loss",
            'xlabel': "rate",  # x轴标签
            'ylabel': "loss",  # y轴标签
        ,)

window_w = viz.line(
        X=[0.1],  # x坐标
         Y=[0.],  # y值
        win="line_w_1",  # 窗口id
        name=name_1,  # 线条名称
        update='append',  # 以添加方式加入
        opts=
            'showlegend': True,  # 显示网格
            'title': "W value",
            'xlabel': "rate",  # x轴标签
            'ylabel': "w",  # y轴标签
        ,)


window_b = viz.line(
        X=[0.1],  # x坐标
         Y=[0.],  # y值
        win="line_b_1",  # 窗口id
        name=name_1,  # 线条名称
        update='append',  # 以添加方式加入
        opts=
            'showlegend': True,  # 显示网格
            'title': "b value",
            'xlabel': "rate",  # x轴标签
            'ylabel': "b",  # y轴标签
        ,)

在迭代训练中,每次result生成的结果为([loss_A, loss_B, loss_C],[A_w,B_w, C_w],[A_b, B_b, C_b])


for i in range(9):
        va = 'append'
        if i == 0:
            va = "replace"

        rate += 0.1
        result = main()
        
        #result: ([loss_A, loss_B, loss_C],[A_w,B_w, C_w],[A_b, B_b, C_b])

        viz.line(X=[rate], Y=[result[0][0]],name=name_1, win=window_loss, update=va)
        viz.line(X=[rate], Y=[result[0][1]],name=name_2, win=window_loss, update=va)
        viz.line(X=[rate], Y=[result[0][2]],name=name_3, win=window_loss, update=va)
        viz.line(X=[rate], Y=[result[1][0]],name=name_1, win=window_w, update=va)
        viz.line(X=[rate], Y=[result[1][1]],name=name_2, win=window_w, update=va)
        viz.line(X=[rate], Y=[result[1][2]],name=name_3, win=window_w, update=va)
        viz.line(X=[rate], Y=[result[2][0]],name=name_1, win=window_b, update=va)
        viz.line(X=[rate], Y=[result[2][1]],name=name_2, win=window_b, update=va)
        viz.line(X=[rate], Y=[result[2][2]],name=name_3, win=window_b, update=va)

打开网页

倘若是在机器学习、深度学习中:

#训练模型
vis = visdom.Visdom(env='main')  # 设置环境窗口的名称,如果不设置名称就默认为main
opt = 
        'xlabel': 'epochs',
        'ylabel': 'loss_value',
        'title': 'SGD_loss'
    
loss_window = vis.line(
    X=[0],
    Y=[0],
    opts=opt
)

for epoch in range(400):
    y_pred = model(x_data)
    loss = criterion(y_pred, y_data)
    print(epoch, loss.item())

    #所有梯度归零化
    optimizer.zero_grad()
    #反向传播求出梯度
    loss.backward()
    #更新权重和偏置值,即w和b
    optimizer.step()

    vis.line(X=[epoch], Y=[loss.item()], win=loss_window, opts=opt, update='append')

五、一般绘图

放在“main”下面,可忽略参数。在jupyter notebook中执行代码:

import visdom
import numpy as np

vis = visdom.Visdom()

vis.text('Hello, world!')
vis.image(np.ones((3, 10, 10)))
import visdom
vis = visdom.Visdom()

trace = dict(x=[1, 2, 3], y=[4, 5, 6], mode="markers+lines", type='custom',
             marker='color': 'red', 'symbol': 104, 'size': "10",
             text=["one", "two", "three"], name='1st Trace')
layout = dict(title="First Plot", xaxis='title': 'x1', yaxis='title': 'x2')

vis._send('data': [trace], 'layout': layout, 'win': 'mywin')
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals

from visdom import Visdom
import numpy as np
import math
import os.path
import getpass
from sys import platform as _platform
from six.moves import urllib

viz = Visdom()
assert viz.check_connection()

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)
#单张
viz.image(
    np.random.rand(3, 512, 256),
    opts=dict(title='Random!', caption='How random.'),
)
#多张
viz.images(
    np.random.randn(20, 3, 64, 64),
    opts=dict(title='Random images', caption='How random.')
)

#画出随机的散点图
import time
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',
    ),
)

time.sleep(5)

#对窗口进行更新,包括标注,坐标,样式等
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',
    ),
)
## 通过update='new'添加新散点

import time
win = viz.scatter(
    X=np.random.rand(255, 2),
    opts=dict(
        markersize=10,
        markercolor=np.random.randint(0, 255, (255, 3,)),
    ),
)

# 判断窗口是否存在
assert viz.win_exists(win), 'Created window marked as not existing'
time.sleep(2)

# 向散点图中加入新的描述
viz.scatter(
    X=np.random.rand(255),
    Y=np.random.rand(255),
    win=win,
    name='new_trace',
    update='new'
)
# 2D散点图,分配不同颜色
viz.scatter(
    X=np.random.rand(255, 2),
    #随机指定1或者2
    Y=(np.random.rand(255) + 1.5).astype(int),
    opts=dict(
        markersize=10,
        ## 分配两种颜色
        markercolor=np.random.randint(0, 255, (2, 3,)),
    ),
)
#3D 散点图
viz.scatter(
    X=np.random.rand(100, 3),
    Y=(Y + 1.5).astype(int),
    opts=dict(
        legend=['Men', 'Women'],
        markersize=5,
    )
)
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 ??中间发现visdom安装的版本过低,导致发生了一些问题,后面更改了版本为最新版本0.1.8.8,所以可能会发现截图有些不同,但是功能不会有太多影响

 

 Visdom是Facebook专门为PyTorch开发的一款可视化工具,其开源于2017年3月。Visdom十分轻量级,但却支持非常丰富的功能,能胜任大多数的科学运算可视化任务。


Visdom可以创造、组织和共享多种数据的可视化,包括数值、图像、文本,甚至是视频,其支持PyTorch、Torch及Numpy。用户可通过编程组织可视化空间,或通过用户接口为生动数据打造仪表板,检查实验结果或调试代码。

Visdom中有两个重要概念:

  • envs:环境。不同环境的可视化结果相互隔离,互不影响,在使用时如果不指定env,默认使用main。不同用户、不同程序一般使用不同的env。
  • Panes:窗格。窗格可用于可视化图像、数值或打印文本等,其可以拖动、缩放、保存和关闭。一个程序中可使用同一个env中的不同pane,每个pane可视化或记录某一信息。Panes是保存在 envs 中的, envs的状态 存储在会话之间

 使用Visdom就是在env中的pane上画图。

 

1.envs

您可以使用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时可以使用的命令行参数有:

  1. -port : 指定运行服务的端口.
  2. -hostname : 指定运行服务的主机名.
  3. -base_url : 指定初始网址(default = /).
  4. -env_path : 指定序列会话重新下载的路径T
  5. -logging_level : 日志级别(default = INFO).同时接受标准文本和数字日志值
  6. -readonly : 标记再只读模式下开启服务
  7. -enable_login : 标记为服务设置权限,需要用户名和密码来登录服务
  8. -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文件:

存储了如下的信息:

技术图片View Code

 

Callbacks回调

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: 当前环境id
  • target: 该事件调用的环境id

额外的参数定义在下方

现在支持如下的三个回调事件:

  1. Close - 当窗口关闭时触发,返回只有上述字段的dict字典。
  2. KeyPress - 按键时触发。包含额外的参数:
    • key - 按键的字符串表示(应用状态修饰符,如SHIFT)
    • key_code - 按键的javascript事件键码(没有修饰符)
  3. PropertyUpdate - 在属性窗格中更新属性时触发
    • propertyId - 更改的属性在属性列表中的位置
    • value - 新属性的值

Tip: 您可以使用浏览器的放大缩小功能来调整UI的大小。

 

 3.State

一旦您创建了一些可视化,状态是被保存的。服务器自动缓存您的可视化–如果您重新加载网页,您的可视化会重新出现。

  • Save: 你可以手动的保存env通过点击save按钮。它会首先序列化env的状态,然后以json文件的形式保存到硬盘上,包括窗口的位置。 同样,您也可以通过编程来实现env的保存。当面对一些十分复杂的可视化,例如参数设置非常重要,这中保存env状态的方法是十分有用的。例:数据丰富的演示,模型的训练dashboard, 或者系统实验。这种设计依旧可以使这些可视化十分容易分享和复用。
  • Fork: 有过您输入了一个新的env 名字,saving会建立一个新的env – 有效的forking(复制)之前的状态。

 

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文件

 技术图片技术图片

 

 注意:保存的视图是静态的,编辑保存的视图会将视图复制到当前视图,在当前视图中可以进行编辑。

 

Re-Packing

使用repack图标(9个框),visdom将尝试以最适合的方式打包窗口,同时保留行/列的顺序。

注意:由于依赖行/列排序和ReactGridLayout,最终的布局可能与预期略有不同。我们正在努力改善这种体验,或提供更多的替代方案,以实现更精确的控制。 

 

Reloading Views重载视图

使用视图下拉框可以选择以前保存的视图,将当前环境中所有窗口的位置和大小恢复到上次保存视图时的位置。

 技术图片

 

 

 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() #使用参数进行设置

可以使用的参数有:

  • server: 指定要调用的visdom服务端的主机名(default: ‘http://localhost‘)
  • port: 指定调用的visdom服务端的端口 (default: 8097)
  • base_url: 指定初始调用的服务端url (default: /)
  • env: 当没有提供环境时,要plot到的默认环境 (default: main)
  • raise_exceptions: 失败时抛出异常,而不是打印异常 (default: True (soon))
  • log_to_filename: 如果为None,则将所有绘图和更新事件记录到给定的文件中(append模式),以便稍后可以使用replay_log重播这些事件 (default: None)
  • use_incoming_socket: 启用套接字来接收来自web客户机的事件,允许用户注册回调 (default: True)
  • http_proxy_host: 弃用。使用proxy参数获得完整的代理支持.
  • http_proxy_port: 弃用。使用proxy参数获得完整的代理支持.
  • username: 如果服务器以-enable_login启动,则使用username进行身份验证 (default: None)
  • password: 如果服务器以-enable_login启动,则使用password进行身份验证 (default: None)
  • proxies: 字典映射协议到每个请求上使用的代理的URL(例如{http: foo.bar:3128}). (default: None)
  • offline: 标记为在脱机模式下运行visdom,其中所有请求都记录到文件中,而不是记录到服务器。需要设置log_to_filename。在脱机模式下,所有不创建或更新图的visdom命令将返回True. (default: False)

 

2)基本可视化函数

  • vis.image : 图片
  • vis.images : 图片列表
  • vis.text : 抽象HTML
  • vis.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 numbers)
  • opts.xticklabels : 在x轴上标记标签 (table of strings)
  • 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-axis
  • opts.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 numbers)
  • opts.yticklabels : ticks labels on y-axis (table of strings)
  • 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属性有:

  • text: 字符串
  • number: 十进制数
  • button: 带有 "value"标签的按钮
  • checkbox: 将布尔值呈现为复选框
  • select: 多值选择框
    • 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_windowis 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 = Stopif properties[prop_id][value‘] == Startelse 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中)作为输入。

 

以上是关于pytorch训练可视化包visdom的使用的主要内容,如果未能解决你的问题,请参考以下文章

Pytorch可视化--Visdom使用(持续更新)

PyTorch学习笔记 6.可视化工具visdom

PyTorch学习笔记 6.可视化工具visdom

Pytorch-Visdom可视化工具

PyTorch中的可视化工具

[Pytorch系列-70]:开发环境 - 可视化工具visdom安装与使用方法