使用教程,參考: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