目錄
- TensorBoard
-
- Create a summary writer
- General api format
-
- Add scalar
-
- `add_scalar`
- `add_scalars`
- Add graph (visualize a model)
- Add histogram
- Add image
-
- add_image
-
- torchvision.utils.make_grid
- add_images
- Add figure
- Add video
- Add audio
- Add text
- Add embedding(高次元張量可視化/降維)
- Add P-R curve (R:召回率 P:準确率)
- Add hyperparameters
- 檢視資料可視化效果
- 官方 demo
- 示例:可視化 loss 及 graph
- Visdom
-
- 安裝
- 啟動服務
- 基本概念
-
- Windows / Panes(窗格)
-
- Callbacks
- Environments(環境)
-
- Comparing Environments
- Managing Environments
- State
- Filter
- Views
-
- Saving/Deleting Views
- Re-Packing
- Reloading Views
- 實驗
-
- 可以參考的實驗
- 官方demo
- API
-
- Basics
-
- vis.image
- vis.images
- vis.text
- vis.video
- vis.matplot
- Plotting
-
- vis.scatter
- vis.line
- Generic Plots
- Customizing plots
- Others
- vis.stem
- vis.heatmap
- vis.bar
- vis.histogram
- vis.boxplot
- vis.surf
- vis.contour
- vis.quiver
- vis.svg
- vis.mesh
TensorBoard
Ref
- Pytorch 使用 tensorboardX 可視化, 《Tensorflow: 實戰 Google 深度學習架構》
- tutorial (包括 API 介紹): tensorboardX, tensorboard (目前 Pytorch 中已經內建了 tensorboard)
- TensorBoard 可以通過 TensorFlow / Pytorch 程式運作過程中輸出的日志檔案可視化程式的運作狀态。TensorBoard 和 TensorFlow / Pytorch 程式跑在不同的程序中,TensorBoard 會自動讀取最新的日志檔案,并呈現目前程式運作的最新狀态
- This package currently supports logging scalar, image, audio, histogram (直方圖), text, embedding (嵌入向量), and the route of back-propagation.
Create a summary writer
- Before logging anything, we need to create a
instance.writer
torch.utils.tensorboard.writer.SummaryWriter(log_dir=None, comment='',
purge_step=None, max_queue=10, flush_secs=120, filename_suffix='')
- The class updates the file contents asynchronously. This allows a training program to call methods to add data to the file directly from the training loop, without slowing down training.
-
(log_dir
) – Save directory location.string
isDefault
, which changes after each run.runs/CURRENT_DATETIME_HOSTNAME
- Use hierarchical folder structure to compare between runs easily. e.g. pass in ‘
’, ‘runs/exp1
’, etc. for each new experiment to compare across them.runs/exp2
- Use hierarchical folder structure to compare between runs easily. e.g. pass in ‘
-
(comment
) – Commentstring
suffix appended to the defaultlog_dir
. Iflog_dir
is assigned, this argument has no effect.log_dir
-
(purge_step
) – When logging crashes at step T + X T+X T+X and restarts at step T T T , any events whoseint
larger or equal to T T T will be purged and hidden from TensorBoard. Note that crashed and resumed experiments should have the sameglobal_step
.log_dir
-
(max_queue
) – Size of the queue for pending events and summaries before one of the ‘int
’ calls forces a flush to disk. Default is ten items.add
-
(flush_secs
) – How often, in seconds, to flush the pending events and summaries to disk. Default is every two minutes.int
-
(filename_suffix
) – Suffix added to all event filenames in thestring
directory. More details on filename construction inlog_dir
.tensorboard.summary.writer.event_file_writer.EventFileWriter
-
Methods
-
:Flushes the event file to disk. Call this method to make sure that all pending events have been written to disk.flush()
-
close()
from torch.utils.tensorboard import SummaryWriter
#SummaryWriter encapsulates everything
#log_dir參數為生成的檔案所放的目錄,預設為./runs/,comment參數為檔案名稱
writer = SummaryWriter('runs/exp-1')
#creates writer object. The log will be saved in 'runs/exp-1'
writer2 = SummaryWriter()
#creates writer2 object with auto generated file name, the dir will be something like 'runs/Aug20-17-20-33'
writer3 = SummaryWriter(comment='3x learning rate')
#creates writer3 object with auto generated file name, the comment will be appended to the filename. The dir will be something like 'runs/Aug20-17-20-33-3xlearning rate'
- Each subfolder will be treated as different experiments in tensorboard. Each time you re-run the experiment with different settings, you should change the name of the sub folder such as
,runs/exp2
so that you can easily compare different experiment settings.runs/myexp
General api format
- Lots of information can be logged for one experiment. To avoid cluttering the UI and have better result clustering, we can group plots by naming them hierarchically.
- For example, “Loss/train” and “Loss/test” will be grouped together, while “Accuracy/train” and “Accuracy/test” will be grouped separately in the TensorBoard interface.
writer = SummaryWriter()
for n_iter in range(100):
writer.add_scalar('Loss/train', np.random.random(), n_iter)
writer.add_scalar('Loss/test', np.random.random(), n_iter)
writer.add_scalar('Accuracy/train', np.random.random(), n_iter)
writer.add_scalar('Accuracy/test', np.random.random(), n_iter)
Add scalar
add_scalar
add_scalar
- Mostly we save the loss value of each training step, or the accuracy after each epoch. Sometimes I save the corresponding learning rate as well.
-
(tag
) – Data identifierstring
-
(scalar_value
orfloat
/string
) – Value to saveblobname
-
(global_step
) – Global step value to recordint
-
(walltime
) – Optional override default walltime (time.time()) with seconds after epoch of eventfloat
Note that the program complains if you feed a PyTorch tensor. Remember to extract the scalar value byif
x.item()
is a torch scalar tensor.
x
add_scalars
add_scalars
Adds many scalar data to summary.
-
(main_tag
) – The parent name for the tagsstring
-
(tag_scalar_dict
) – Key-value pair storing the tag and corresponding valuesdict
Note that this function also keeps logged scalars in memory. In extreme case it explodes your RAM.
import numpy as np
from torch.utils.tensorboard import SummaryWriter
# The log will be saved in 'runs/exp-1'
writer = SummaryWriter(log_dir='runs/exp-1')
for epoch in range(100):
writer.add_scalar('scalar/test', np.random.rand(), epoch)
writer.add_scalars('scalar/scalars_test', {'xsinx': epoch * np.sin(epoch),
'xcosx': epoch * np.cos(epoch)}, epoch)
writer.close()
注:可以使用左下角的檔案選擇你想顯示的某個或者全部圖檔
Add graph (visualize a model)
- To visualize a model, you need a model
and the inputm
.t
can be a tensor or a list of tensors depending on your model. If error happens, make sure thatt
runs without problem first.m(t)
- The graph demo
import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.utils.tensorboard import SummaryWriter
class Net1(nn.Module):
def __init__(self):
super(Net1, self).__init__()
self.conv1 = nn.Conv2d(1, 10, kernel_size=5)
self.conv2 = nn.Conv2d(10, 20, kernel_size=5)
self.conv2_drop = nn.Dropout2d()
self.fc1 = nn.Linear(320, 50)
self.fc2 = nn.Linear(50, 10)
self.bn = nn.BatchNorm2d(20)
def forward(self, x):
x = F.max_pool2d(self.conv1(x), 2)
x = F.relu(x) + F.relu(-x)
x = F.relu(F.max_pool2d(self.conv2_drop(self.conv2(x)), 2))
x = self.bn(x)
x = x.view(-1, 320)
x = F.relu(self.fc1(x))
x = F.dropout(x, training=self.training)
x = self.fc2(x)
x = F.softmax(x, dim=1)
return x
dummy_input = torch.rand(13, 1, 28, 28)
model = Net1()
# with語句,可以避免因w.close()未寫造成的問題
with SummaryWriter(comment='Net1') as w:
w.add_graph(model, (dummy_input,))
- 成功顯示網絡結構: 輕按兩下方框檢視網絡細節:
Add histogram
Saving histograms is expensive. Both in computation time and storage. If training slows down after using this package, check this first.
-
(values
,torch.Tensor
, ornumpy.array
/string
) – Values to build histogramblobname
from torch.utils.tensorboard import SummaryWriter
import numpy as np
writer = SummaryWriter()
for i in range(10):
x = np.random.random(1000)
writer.add_histogram('distribution centers', x + i, i)
writer.close()
Add image
add_image
Note that this requires the pillow
package.
-
(img_tensor
,torch.Tensor
, or string/blobname) – Image datanumpy.array
-
:Shape
:img_tensor
isDefault
. You can use(3, H, W)
(torchvision.utils.make_grid()
takes a 4D tensor and returns tiled images in 3D tensor) to convert a batch of tensor intomake_grid
format or call3xHxW
and let us do the job. Tensor withadd_images
,(1, H, W)
,(H, W)
is also suitable as long as corresponding dataformats argument is passed, e.g.(H, W, 3)
,CHW
,HWC
.HW
grid = torchvision.utils.make_grid(images)
writer.add_image('images', grid, 0)
Remember to normalize your image.
torchvision.utils.make_grid
torchvision.utils.make_grid(tensor: Union[torch.Tensor, List[torch.Tensor]],
nrow: int = 8, padding: int = 2, normalize: bool = False,
range: Optional[Tuple[int, int]] = None, scale_each: bool = False,
pad_value: int = 0) → torch.Tensor
-
(tensor
orTensor
) – 4D mini-batch Tensor of shapelist
or a(B x C x H x W)
of images all of the same size.list
-
(nrow
, optional) – Number of images displayed in each row of the grid. The final grid size isint
.(B / nrow, nrow)
:Default
.8
-
(padding
, optional) – amount of padding.int
:Default
.2
-
(normalize
, optional) – Ifbool
, shift the image to the range (0, 1), by the min and max values specified byTrue
.range
:Default
.False
-
(range
, optional) – tuple (min, max) where min and max are numbers, then these numbers are used to normalize the image. By default, min and max are computed from the tensor.tuple
-
(scale_each
, optional) – Ifbool
, scale each image in the batch of images separately rather than the (min, max) over all images.True
:Default
.False
-
(pad_value
, optional) – Value for the padded pixels.float
: .Default
add_images
Add batched image data to summary.
Note that this requires the pillow
package.
-
(dataformats
) – Image data format specification of the form NCHW, NHWC, CHW, HWC, HW, WH, etc.string
writer = SummaryWriter()
writer.add_images('my_image_batch', img_batch, 0)
writer.close()
Add figure
Render matplotlib figure into an image and add it to summary.
-
(figure
) – Figure or a list of figuresmatplotlib.pyplot.figure
-
(close
) – Flag to automatically close thebool
figure
writer = SummaryWriter()
writer.add_figure('figure', figure, iteration)
writer.close()
Add video
Note that this requires the moviepy
package.
-
(vid_tensor
) – Video datatorch.Tensor
:vid_tensor
. The values should lie in [0, 255] for type(N, T, C, H, W)
or [0, 1] for typeuint8
.float
Add audio
-
(snd_tensor
) – Sound datatorch.Tensor
:snd_tensor
. The values should lie between [-1, 1].(1, L)
is an one dimensional array, and each element in the array represents the consecutive amplitude samples. For a 2 seconds audio withsnd_tensor
44100 Hz, the inputsample_rate
should have 88200 elements. Each element should lie in [−1, 1].x
-
(sample_rate
) – sample rate in Hzint
Add text
Add embedding(高次元張量可視化/降維)
-
(mat
ortorch.Tensor
) – A matrix which each row is the feature vector of the data point. The feature representation can either be raw data (e.g. the MNIST image) or a representation learned by your network (extracted feature). This determines how the points distributes.numpy.array
:mat
, where(N, D)
is number of data andN
is feature dimensionD
(N, )
-
(metadata
) – A list of labels, each element will be convert to string 可以用來标注每個圖檔的類别list
-
(label_img
) – Images correspond to each data pointtorch.Tensor
(N,C,H,W)
Embeddings, high dimensional data, can be visualized and converted into human perceptible 3D data by tensorboard, which provides PCA and t-sne to project the data into low dimensional space.
To make the visualization more informative, you can pass optional metadata or
label_img
for each data points. In this way you can see that neighboring point have similar label and distant points have very different label (semantically or visually).
The embedding demo
import keyword
import torch
meta = []
while len(meta)<100:
meta = meta+keyword.kwlist # get some strings
meta = meta[:100]
for i, v in enumerate(meta):
meta[i] = v+str(i)
label_img = torch.rand(100, 3, 10, 32)
for i in range(100):
label_img[i]*=i/100.0
writer.add_embedding(torch.randn(100, 5), metadata=meta, label_img=label_img)
writer.add_embedding(torch.randn(100, 5), label_img=label_img)
writer.add_embedding(torch.randn(100, 5), metadata=meta)
Add P-R curve (R:召回率 P:準确率)
适用于二分類問題
PR曲線介紹:https://blog.csdn.net/b876144622/article/details/80009867
Adds precision recall curve. Plotting a precision-recall curve lets you understand your model’s performance under different threshold settings. With this function, you provide the ground truth labeling (T/F) and prediction confidence (usually the output of your model) for each target. The TensorBoard UI will let you choose the threshold interactively.
-
(labels
,torch.Tensor
, ornumpy.array
/blobname) – Ground truth data. Binary label for each element.string
-
(predictions
,torch.Tensor
, or string/blobname) – The probability that an element be classified as true. Value should in [0, 1]numpy.array
-
(num_thresholds
) – Number of thresholds used to draw the curve. 用來劃分樣本的門檻值,比如0.5即為機率大于0.5的就屬于正例int
labels = np.random.randint(2, size=100) # binary label
predictions = np.random.rand(100)
writer = SummaryWriter()
writer.add_pr_curve('pr_curve', labels, predictions, 0)
writer.close()
Add hyperparameters
Add a set of hyperparameters to be compared in TensorBoard.
-
(hparam_dict
) – Each key-value pair in the dictionary is the name of the hyper parameter and it’s corresponding value.dict
-
(metric_dict
) – Each key-value pair in the dictionary is the name of the metric and it’s corresponding value. Note that the key used here should be unique in the tensorboard record. Otherwise the value you added bydict
will be displayed in hparam plugin. In most cases, this is unwanted.add_scalar
with SummaryWriter() as w:
for i in range(5):
w.add_hparams({'lr': 0.1*i, 'bsize': i},
{'hparam/accuracy': 10*i, 'hparam/loss': 10*i})
檢視資料可視化效果
- 在浏覽器中輸入
即可http://localhost:6006/
- 如果是在遠端伺服器上訓練,則可以加上
選項,之後就可以直接在本地浏覽器檢視 tensorboard--bind_all
tensorboard --logdir="runs/exp-1/" --bind_all
官方 demo
import torch
import torchvision.utils as vutils
import numpy as np
import torchvision.models as models
from torchvision import datasets
from tensorboardX import SummaryWriter
resnet18 = models.resnet18(False)
writer = SummaryWriter()
sample_rate = 44100
freqs = [262, 294, 330, 349, 392, 440, 440, 440, 440, 440, 440]
for n_iter in range(100):
dummy_s1 = torch.rand(1)
dummy_s2 = torch.rand(1)
# data grouping by `slash`
writer.add_scalar('data/scalar1', dummy_s1[0], n_iter)
writer.add_scalar('data/scalar2', dummy_s2[0], n_iter)
writer.add_scalars('data/scalar_group', {'xsinx': n_iter * np.sin(n_iter),
'xcosx': n_iter * np.cos(n_iter),
'arctanx': np.arctan(n_iter)}, n_iter)
dummy_img = torch.rand(32, 3, 64, 64) # output from network
if n_iter % 10 == 0:
x = vutils.make_grid(dummy_img, normalize=True, scale_each=True)
writer.add_image('Image', x, n_iter)
dummy_audio = torch.zeros(sample_rate * 2)
for i in range(x.size(0)):
# amplitude of sound should in [-1, 1]
dummy_audio[i] = np.cos(freqs[n_iter // 10] * np.pi * float(i) / float(sample_rate))
writer.add_audio('myAudio', dummy_audio, n_iter, sample_rate=sample_rate)
writer.add_text('Text', 'text logged at step:' + str(n_iter), n_iter)
for name, param in resnet18.named_parameters():
writer.add_histogram(name, param.clone().cpu().data.numpy(), n_iter)
# needs tensorboard 0.4RC or later
writer.add_pr_curve('xoxo', np.random.randint(2, size=100), np.random.rand(100), n_iter)
dataset = datasets.MNIST('mnist', train=False, download=True)
images = dataset.test_data[:100].float()
label = dataset.test_labels[:100]
features = images.view(100, 784)
writer.add_embedding(features, metadata=label, label_img=images.unsqueeze(1))
# export scalar data to JSON for external processing
writer.export_scalars_to_json("./all_scalars.json")
writer.close()
示例:可視化 loss 及 graph
import torch
import torch.nn as nn
from tensorboardX import SummaryWriter
import matplotlib.pyplot as plt
import numpy as np
input_size = 1
output_size = 1
num_epoches = 60
learning_rate = 0.01
writer = SummaryWriter(comment='Linear')
x_train = np.array([[3.3], [4.4], [5.5], [6.71], [6.93], [4.168],
[9.779], [6.182], [7.59], [2.167], [7.042],
[10.791], [5.313], [7.997], [3.1]], dtype=np.float32)
y_train = np.array([[1.7], [2.76], [2.09], [3.19], [1.694], [1.573],
[3.366], [2.596], [2.53], [1.221], [2.827],
[3.465], [1.65], [2.904], [1.3]], dtype=np.float32)
model = nn.Linear(input_size, output_size)
criterion = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
for epoch in range(num_epoches):
inputs = torch.from_numpy(x_train)
targets = torch.from_numpy(y_train)
output = model(inputs)
loss = criterion(output, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 儲存loss的資料與epoch數值
writer.add_scalar('Train', loss, epoch)
if (epoch + 1) % 5 == 0:
print('Epoch {}/{},loss:{:.4f}'.format(epoch + 1, num_epoches, loss.item()))
# 将model儲存為graph
writer.add_graph(model, (inputs,))
predicted = model(torch.from_numpy(x_train)).detach().numpy()
plt.plot(x_train, y_train, 'ro', label='Original data')
plt.plot(x_train, predicted, label='Fitted line')
plt.legend()
plt.show()
writer.close()
Visdom
Github:https://github.com/facebookresearch/visdom
本節參考:https://www.cnblogs.com/fanghao/p/10256287.html
https://blog.csdn.net/wen_fei/article/details/82979497
https://blog.csdn.net/u012436149/article/details/69389610
Visdom支援
torch
和
numpy
,目的是促進遠端資料的可視化
安裝
conda install jsonpatch
conda install visdom
啟動服務
Thecommand is equivalent to running
visdom
.
python -m visdom.server
If the above does not work, try using an SSH tunnel to your server by adding the following line to your local:
~/.ssh/config
.
LocalForward 127.0.0.1:8097 127.0.0.1:8097
The following options can be provided to the server:
-
: The port to run the server on.port
-
: The hostname to run the server on.hostname
-
: The base server url (default =base_url
)./
-
: The path to the serialized session to reload.env_path
-
: Logging level (default =logging_level
). Accepts both standard text and numeric logging values.INFO
-
: Flag to start server in readonly mode.readonly
-
: Flag to setup authentication for the sever, requiring a username and password to login.enable_login
-
: Flag to reset the secure cookie used by the server, invalidating current login cookies. Requires -force_new_cookie
.enable_login
When
-enable_login
flag is provided, the server asks user to input credentials using terminal prompt. Alternatively, you can setup
VISDOM_USE_ENV_CREDENTIALS
env variable, and then provide your username and password via
VISDOM_USERNAME
and
VISDOM_PASSWORD
env variables without manually interacting with the terminal. This setup is useful in case if you would like to launch
visdom
server from bash script, or from Jupyter notebook.
VISDOM_USERNAME=username
VISDOM_PASSWORD=password
VISDOM_USE_ENV_CREDENTIALS=1 visdom -enable_login
You can also use
VISDOM_COOKIE
variable to provide cookies value if the cookie file wasn’t generated, or the flag
-force_new_cookie
was set.
可能會遇到卡死的問題,原因是下載下傳一些js、css資源檔案比較慢或者根本沒法通路,解決方案是手動下載下傳即可。在
D:\Software\Anaconda3\envs\pytorch\Lib\site-packages\visdom\server.py
中找到
download_scripts()
,手動下載下傳資源檔案即可
D:\Software\Anaconda3\envs\pytorch\Lib\site-packages\visdom\
為
install_dir
連結 | 儲存位址 |
---|---|
https://unpkg.com/[email protected]/dist/jquery.min.js | install_dir/static/js/jquery.min.js |
https://unpkg.com/[email protected]/dist/js/bootstrap.min.js | install_dir/static/js/bootstrap.min.js |
https://unpkg.com/[email protected]/umd/react.production.min.js | install_dir/static/js/react-react.min.js |
https://unpkg.com/[email protected]/umd/react-dom.production.min.js | install_dir/static/js/react-dom.min.js |
https://unpkg.com/[email protected]/dist/react-modal.min.js | install_dir/static/js/react-modal.min.js |
https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_SVG | install_dir/static/js/mathjax-MathJax.js |
https://cdn.plot.ly/plotly-latest.min.js | install_dir/static/js/plotly-plotly.min.js |
https://unpkg.com/[email protected]/sjcl.js | install_dir/static/js/sjcl.js |
https://unpkg.com/[email protected]/css/styles.css | install_dir/static/css/react-resizable-styles.css |
https://unpkg.com/[email protected]/css/styles.css | install_dir/static/css/react-grid-layout-styles.css |
https://unpkg.com/[email protected]/dist/css/bootstrap.min.css | install_dir/static/css/bootstrap.min.css |
https://unpkg.com/[email protected] | install_dir/static/fonts/classnames |
https://unpkg.com/[email protected]/dist/layout-bin-packer.js | install_dir/static/js/layout_bin_packer.js |
https://unpkg.com/[email protected]/dist/fonts/glyphicons-halflings-regular.eot | install_dir/static/fonts/glyphicons-halflings-regular.eot |
https://unpkg.com/[email protected]/dist/fonts/glyphicons-halflings-regular.woff2 | install_dir/static/fonts/glyphicons-halflings-regular.woff2 |
https://unpkg.com/[email protected]/dist/fonts/glyphicons-halflings-regular.woff | install_dir/static/fonts/glyphicons-halflings-regular.woff |
https://unpkg.com/[email protected]/dist/fonts/glyphicons-halflings-regular.ttf | install_dir/static/fonts/glyphicons-halflings-regular.ttf |
https://unpkg.com/[email protected]/dist/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular | install_dir/static/fonts/glyphicons-halflings-regular.svg#glyphicons_halflingsregular |
看檔案夾裡缺哪個就下哪個吧
後來又在網上看到有上傳好的static檔案夾,直接解壓到
install_dir/
目錄下即可:https://blog.csdn.net/qq_32523711/article/details/103345741
在啟動服務時我還碰到了一個問題:
解決方法:
參考:https://blog.csdn.net/B1151937289/article/details/106169017/
添加下面兩行代碼到
D:\Software\Anaconda3\envs\pytorch\Lib\site-packages\visdom\server.py
的相應位置即可:
import asyncio
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
修改後啟動服務成功:
啟動服務後,在浏覽器中輸入
http://localhost:8097
來通路 Visdom
基本概念
Windows / Panes(窗格)
UI
剛開始是個白闆–您可以用圖像,圖檔,文本填充它。這些填充的資料出現在
Panes
中,您可以這些
Panes
進行 拖放,删除,調整大小和銷毀操作。
Panes
是儲存在
envs
中的,
envs
的狀态存儲在會話之間。您可以下載下傳
Panes
中的内容–包括您在
svg
中的繪圖。
Tip: You can use the zoom of your browser to adjust the scale of the UI.
Callbacks
The python Visdom implementation supports callbacks on a window. The functionality of these callbacks allows the Visdom object to receive and react to events that happen in the frontend.
You can subscribe a window to events by adding a function to the event handlers dict for the window id you want to subscribe by calling
viz.register_event_handler(handler, win_id)
with your handler and the window id. Multiple handlers can be registered to the same window. You can remove all event handlers from a window using
viz.clear_event_handlers(win_id)
. When an event occurs to that window, your callbacks will be called on a dict containing:
-
: one of the below event typesevent_type
-
: all of the stored contents for that window including layout and content.pane_data
-
: the current environment ideid
-
: the window id the event is called ontarget
Right now the following callback events are supported:
-
- Triggers when a window is closed. Returns a dict with only the aforementioned fields.Close
-
- Triggers when a key is pressed. Contains additional parameters:KeyPress
- A string representation of the key pressed (applying state modifiers such askey
)SHIFT
- The javascript event keycode for the pressed key (no modifiers)key_code
-
- Triggers when a property is updated in Property panePropertyUpdate
- Position in properties listpropertyId
- New property valuevalue
-
- Triggers when Image pane is clicked on, has a parameter:Click
- dictionary with the fieldsimage_coord
andx
for the click coordinates in the coordinate frame of the possibly zoomed/panned image (not the enclosing pane).y
import visdom
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
txt = 'This is a write demo notepad. Type below. Delete clears text:<br>'
callback_text_window = vis.text(txt, win='callback')
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']
vis.text(curr_txt, win=callback_text_window)
vis.register_event_handler(type_callback, callback_text_window)
Environments(環境)
您可以使用
envs
對可視化空間進行分區。預設地,每個使用者都會有一個叫做
main
的
envs
。可以通過程式設計或UI建立新的
envs
。
envs
的狀态是長期儲存的。
可以通過 url:
http://localhost.com:8097/env/main
通路特定的
env
Comparing Environments
Selecting multiple environments in the check box will query the server for the plots with the same titles in all environments and plot them in a single plot. An additional compare legend pane is created with a number corresponding to each selected environment. Individual plots are updated with legends corresponding to “x_name” where x is a number corresponding with the compare legend pane and name is the original name in the legend.
Note: The compare envs view is not robust to high throughput data, as the server is responsible for generating the compared content. Do not compare an environment that is receiving a high quantity of updates on any plot, as every update will request regenerating the comparison. If you need to compare two plots that are receiving high quantities of data, have them share the same window on a singular env.
Managing Environments
Pressing the folder icon opens a dialog that allows you to fork or force save the current environment, or delete any of your existing environments.
Env Files: Your envs are loaded at initialization of the server, by default fromCustom paths can be passed as a cmd-line argument. Envs are removed by using the delete button or by deleting the corresponding
$HOME/.visdom/.
file from the env dir.
.json
State
Once you’ve created a few visualizations, state is maintained. The server automatically caches your visualizations – if you reload the page, your visualizations reappear.
- Save: You can manually do so with the
button. This will serialize the env’s state (to disk, in JSON), including window positions. You can save ansave
programmatically.env
- Fork: If you enter a new env name, saving will create a new env – effectively forking the previous env.
Filter
You can use the
filter
to dynamically sift through windows present in an env – just provide a regular expression with which to match titles of window you want to show.
Views
It is possible to manage the views simply by dragging the tops of windows around, however additional features exist to keep views organized and save common views.
Saving/Deleting Views
Using the folder icon, a dialog window opens where views can be forked in the same way that envs can be. Saving a view will retain the position and sizes of all of the windows in a given environment. Views are saved in
$HOME/.visdom/view/layouts.json
in the visdom filepath.
Re-Packing
Using the repack icon (9 boxes), visdom will attempt to pack your windows in a way that they best fit while retaining row/column ordering.
Reloading Views
實驗
注意:在使用時不能将源檔案命名為visdom.py,否則代碼内調包會優先調用目前檔案夾内的檔案,導緻報錯
可以參考的實驗
https://www.cnblogs.com/fanghao/p/10256287.html
官方demo
https://github.com/facebookresearch/visdom/tree/master/example
API
大多數API的輸入包含,一個tensor
X
(儲存資料)和一個可選的tensor
Y
(儲存标簽或者時間戳)。所有的繪圖函數都接收一個可選參數
win
,用來将圖畫到一個特定的window(pane)上。每個繪圖函數也會傳回目前繪圖的
win
。您也可以指定将圖添加到哪個
env
上。
畫圖的方法的接口一般是
vis.some_func(X,Y, opts={})
opts
存放目前pane的一些簡單設定,下面的是比較通用的一些配置
options.title
,
options.xlabel
,
options.ylabel
如果想在同一個圖中畫多個曲線,加上update="append"參數即可
Basics
-
: imagevis.image
-
: list of imagesvis.images
-
: arbitrary HTMLvis.text
-
: properties gridvis.properties
-
: audiovis.audio
-
: videosvis.video
-
: SVG objectvis.svg
-
: matplotlib plotvis.matplot
-
: serialize state server-sidevis.save
vis.image
It takes as input an
CxHxW
tensor
img
that contains the image.
The following
opts
are supported:
-
: JPG quality (jpgquality
0-100). If defined image will be saved as JPG to reduce file size. If not defined image will be saved as PNG.number
-
: Caption for the imagecaption
-
: Keep all images stored to the same window and attach a slider to the bottom that will let you select the image to view. You must always provide this opt when sending new images to an image with history.store_history
Note You can useon an image pane to view the x/y coordinates of the cursor. You can also
alt
to zoom,
ctrl-scroll
to pan vertically, and
alt scroll
to pan horizontally.
alt-shift scroll
inside the pane to restore the image to default.
Double click
import visdom
import torch
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
vis.image(torch.randn(3, 256, 256), win='random_image')
vis.images
It takes an input
B x C x H x W
tensor or
a list of images
all of the same size. It makes a grid of images of size (
B
/
nrow
,
nrow
).
The following arguments and opts are supported:
-
: Number of images in a rownrow
-
: Padding around the image, equal padding around all 4 sidespadding
-
: JPG quality (opts.jpgquality
0-100). If defined image will be saved as JPG to reduce file size. If not defined image will be saved as PNG.number
-
: Caption for the imageopts.caption
import visdom
import torch
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
vis.images(
torch.randn(20, 3, 64, 64),
opts=dict(title='Random images', caption='How random.'))
vis.text
It takes as input a
text
string. No specific
opts
are currently supported.
import visdom
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
# win參數表示顯示的窗格(pane)名字
vis.text('first visdom', win='text1')
# 使用 append=True 來增加text,否則會覆寫之前的text
vis.text('hello PyTorch', win='text1', append=True)
vis.video
It takes as input the
filename
of the video videofile or a
LxHxWxC
-sized
tensor
containing all the frames of the video as input. The function does not support any plot-specific
opts
.
The following
opts
are supported:
-
: FPS for the video (opts.fps
> 0; default =integer
)25
Note: Usinginput requires that
tensor
and
ffmpeg
is installed and working. Your ability to play video may depend on the browser you use: your browser has to support the Theano codec in an OGG container (Chrome supports this).
cv2
import visdom
import numpy as np
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
video = np.empty([256, 250, 250, 3], dtype=np.uint8)
for n in range(256):
video[n, :, :, :].fill(n)
vis.video(tensor=video)
這裡用tensor顯示video報錯,沒用過opencv,等以後再解決吧
D:\Software\Anaconda3\envs\pytorch\lib\site-packages\visdom\__init__.py in video(self, tensor, dim, videofile, win, env, opts)
1406 (tensor.shape[2], tensor.shape[1])
1407 )
-> 1408 assert writer.isOpened(), 'video writer could not be opened'
1409 for i in range(tensor.shape[0]):
1410 # TODO mute opencv on this function call somehow
AssertionError: video writer could not be opened
import visdom
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
vis.video(videofile='E:/Workspace/python/jupyter/pytorch/trailer.ogv',
opts={'width': 864, 'height': 480})
vis.matplot
This function draws a Matplotlib
plot
. The function supports one plot-specific option:
resizable
.
Note When set tothe plot is resized with the pane. You need
True
and
beautifulsoup4
packages installed to use this option.
lxml
Note: matplot is not rendered using the same backend as plotly plots, and is somewhat less efficient. Using too many matplot windows may degrade visdom performance.
import visdom
import matplotlib.pyplot as plt
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
plt.plot([1, 23, 2, 4])
plt.ylabel('some numbers')
vis.matplot(plt)
Plotting
-
: 2D or 3D scatter plotsvis.scatter
-
: line plotsvis.line
-
: stem plots 莖葉圖vis.stem
-
: heatmap plotsvis.heatmap
-
: bar graphs 條形圖vis.bar
-
: histograms 直方圖vis.histogram
-
: boxplots 箱型圖vis.boxplot
-
: surface plots 表面圖vis.surf
-
: contour plots 輪廓圖vis.contour
-
: quiver plots 繪出二維矢量場vis.quiver
-
: mesh plots 網格圖vis.mesh
-
: double y axis line plotsvis.dual_axis_lines
vis.scatter
This function draws a 2D or 3D scatter plot. It takes as input an
Nx2
or
Nx3
tensor
X
that specifies the locations of the
N
points in the scatter plot. An optional
N
tensor
Y
containing discrete labels that range between
1
and
K
can be specified as well – the labels will be reflected in the colors of the markers.
update
can be used to efficiently update the data of an existing plot. Use ’
append'
to append data, ’
replace'
to use new data, or ’
remove'
to remove the trace specified by
name
. Using
update='append'
will create a plot if it doesn’t exist and append to the existing plot otherwise. If updating a single trace, use
name
to specify the name of the trace to be updated. Update data that is all NaN is ignored (can be used for masking update).
The following
opts
are supported:
-
: marker symbol 标記符号 (opts.markersymbol
; default = 'string
)dot'
-
: marker size (opts.markersize
; default = 'number
)10'
-
: color per marker. (opts.markercolor
; default =torch.*Tensor
)nil
-
: marker border line width (opts.markerborderwidth
; default =float
)0.5
-
:opts.legend
containing legend namestable
-
: text label for each point (opts.textlabels
: default =list
)None
-
: dict of any additional options that the graph backend accepts for a layout. For exampleopts.layoutopts
layoutopts = {'plotly': {'legend': {'x':0, 'y':0}}}.
-
: dict mapping trace names or indices to dicts of additional options that the graph backend accepts. For exampleopts.traceopts
.traceopts = {'plotly': {'myTrace': {'mode': 'markers'}}}
-
: use WebGL for plotting (opts.webgl
; default =boolean
). It is faster if a plot contains too many points. Use sparingly as browsers won’t allow more than a couple of WebGL contexts on a single page.false
opts.markercolor
is a Tensor with Integer values. The tensor can be of size
N
or
N x 3
or
K
or
K x 3
.
- Tensor of size
: Single intensity value per data point. 表示每個點的單通道顔色強度 0 = black, 255 = redN
- Tensor of size
: Red, Green and Blue intensities per data point. 0,0,0 = black, 255,255,255 = whiteN x 3
- Tensor of size
andK
: Instead of having a unique color per data point, the same color is shared for all points of a particular label.K x 3
import visdom
import torch
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
Y = torch.rand(100)
win=vis.scatter(
X=torch.rand(100, 2),
Y=(Y[Y > 0] + 1.5).int(),
opts=dict(
legend=['Apples', 'Pears'],
xtickmin=0,
xtickmax=1,
xtickstep=0.5,
ytickmin=0,
ytickmax=1,
ytickstep=0.5,
markersymbol='cross-thin-open',
),
)
# add new trace to scatter plot
vis.scatter(
X=torch.rand(255),
Y=torch.rand(255),
win=win,
opts=dict(
markersymbol='cross-thin-open'
),
name='new_trace',
update='append'
)
vis.scatter(
X=torch.rand(100, 3),
Y=(Y + 1.5).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,
)
)
vis.line
This function draws a line plot. It takes as input an
N
or
NxM
tensor
Y
that specifies the values of the
M
lines (that connect
N
points) to plot. It also takes an optional
X
tensor that specifies the corresponding x-axis values;
X
can be an
N
tensor (in which case all lines will share the same x-axis values) or have the same size as
Y
.
update can be used to efficiently update the data of an existing plot. Use ‘append’ to append data, ‘replace’ to use new data, or ‘remove’ to remove the trace specified by name. If updating a single trace, use name to specify the name of the trace to be updated. Update data that is all NaN is ignored (can be used for masking update).
The following
opts
are supported:
-
: fill area below line (opts.fillarea
)boolean
-
: show markers (opts.markers
; default =boolean
)false
-
: marker symbol (opts.markersymbol
; default = 'string
)dot'
-
: marker size (opts.markersize
; default = 'number
)10'
-
: line colors (opts.linecolor
; default =np.array
)None
-
: line dash type for each line (opts.dash
; default = 'np.array
), one ofsolid'
,solid
,dash
, size should match number of lines being drawndashdot
-
:opts.legend
containing legend namestable
-
:opts.layoutopts
of any additional options that the graph backend accepts for a layout. For example layoutopts =dict
.{'plotly': {'legend': {'x':0, 'y':0}}}
-
:opts.traceopts
mapping trace names or indices to dicts of additional options that plot.ly accepts for a trace.dict
-
: use WebGL for plotting (opts.webgl
; default =boolean
). It is faster if a plot contains too many points. Use sparingly as browsers won’t allow more than a couple of WebGL contexts on a single page.false
import visdom
import numpy as np
# 建立visdom用戶端,環境為first
vis = visdom.Visdom(env='first')
vis.line(Y=np.random.rand(10), opts=dict(showlegend=True))
# 繪制 y=-x^2+20x+1,opts可以進行标題、坐标軸标簽等配置
x = torch.arange(21)
y = -x**2 + 20 * x + 1
vis.line(X=x, Y=y, opts={'title': 'y=-x^2+20x+1'}, win='loss')
Generic Plots
Note that the server API adheres to the
Plotly
convention of
data
and
layout
objects, such that you can produce your own arbitrary
Plotly
visualizations:
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'})
Customizing plots
繪圖函數使用可選的
options
表作為輸入。用它來修改預設的繪圖屬性。所有輸入參數在單個表中指定;輸入參數是基于輸入表中鍵的比對。
下列的選項除了對于
vis.image
,
vis.text
,
vis.video
,
vis.audio
不可用以外,其他的繪圖函數都适用。我們稱為通用選項。
-
: figure titleopts.title
-
: figure widthopts.width
-
: figure heightopts.height
-
: show legend (opts.showlegend
ortrue
)false
-
: type of x-axis (opts.xtype
or'linear'
)'log'
-
: label of x-axisopts.xlabel
-
: show ticks on x-axis (opts.xtick
)boolean
-
: first tick on x-axis (opts.xtickmin
)number
-
: last tick on x-axis (opts.xtickmax
)number
-
: distances between ticks on x-axis (opts.xtickstep
)number
-
: type of y-axis (opts.ytype
or'linear'
)'log'
-
: label of y-axisopts.ylabel
-
: show ticks on y-axis (opts.ytick
)boolean
-
: first tick on y-axis (opts.ytickmin
)number
-
: last tick on y-axis (opts.ytickmax
)number
-
: distances between ticks on y-axis (opts.ytickstep
)number
-
: left margin (in pixels)opts.marginleft
-
: right margin (in pixels)opts.marginright
-
: top margin (in pixels)opts.margintop
-
opts.marginbottom
: bottom margin (in pixels)
其它的一些選項就是函數特定的選項,在上面API介紹的時候已經提到過。
Others
-
: close a window by idvis.close
-
: delete an environment by env_idvis.delete_env
-
: check if a window already exists by idvis.win_exists
-
: get a list of all of the environments on your servervis.get_env_list
-
: get md5 hash of window’s contentsvis.win_hash
-
: get current data for a windowvis.get_window_data
-
: check if the server is connectedvis.check_connection
-
: replay the actions from the provided log filevis.replay_log
vis.stem
這個函數用來畫莖葉圖。它需要一個形狀為
N
或者
N*M
的 tensor
X
來指定
M
時間序列中
N
個點的值。一個可選擇的
Y
,形狀為
N
或者
N×M
,用
Y
來指定時間戳,如果
Y
的形狀是
N
,那麼預設
M
時間序列共享同一個時間戳。
支援以下特定選項:
-
: 色圖 (options.colormap
; default =string
)'Viridis'
-
: 儲存圖例名字的options.legend
table
vis.heatmap
這個函數用來畫熱力圖。它輸入一個 形狀為
N×M
的 tensor
X
。
X
指定了熱力圖中位置的值。
支援下列特定選項:
-
: 色圖 (options.colormap
; default =string
)'Viridis'
-
: 小于這個值的會被剪切成這個值(options.xmin
; default =number
)X:min()
-
: 大于這個值的會被剪切成這個值 (options.xmax
; default =number
)X:max()
-
: 包含x軸标簽的options.columnnames
table
-
: 包含y軸标簽的options.rownames
table
vis.bar
這個函數可以畫正常的,堆起來的,或分組的的條形圖。
輸入參數:
- X(tensor):形狀
或N
,指定每個條的高度。如果N×M
有X
列,那麼每行的值可以看作一組或者把他們值堆起來(取決與M
是否為options.stacked
)。True
- Y(tensor, optional):形狀
,指定對應的x軸的值。N
支援以下特定選項:
-
:options.columnnames
containing x-axis labelstable
-
: stack multiple columns inoptions.stacked
X
-
:options.legend
containing legend labelstable
vis.histogram
這個函數用來畫指定資料的直方圖。他需要輸入長度為
N
的 tensor
X
。
X
儲存了建構直方圖的值。
支援下面特定選項:
-
:options.numbins
的個數 (bins
; default =number
)30
vis.boxplot
這個函數用來畫箱型圖:
輸入:
- X(tensor): 形狀
或N
,指定做第N×M
個箱型圖的m
個值。N
支援以下特定選項:
-
: labels for each of the columns inoptions.legend
X
vis.surf
這個函數用來畫表面圖:
輸入:
- X(tensor):形狀
,指定表面圖上位置的值.N×M
支援以下特定選項:
-
: colormap (options.colormap
; default =string
)'Viridis'
-
: clip minimum value (options.xmin
; default =number
)X:min()
-
: clip maximum value (options.xmax
; default =number
)X:max()
vis.contour
這個函數用來畫輪廓圖。
輸入:
- X(tensor):形狀
,指定了輪廓圖中的值N×M
支援以下特定選項:
-
: colormap (options.colormap
; default =string
)'Viridis'
-
: clip minimum value (options.xmin
; default =number
)X:min()
-
: clip maximum value (options.xmax
; default =number
)X:max()
vis.quiver
這個函數用來畫二維矢量場圖。
輸入:
- X(tensor): 形狀
N*M
- Y(tensor):形狀
N*M
- gridX(tensor, optional):形狀
N*M
- gradY(tensor, optional): 形狀
N*M
與X
決定了 箭頭的長度和方向。可選的Y
和gridX
指定了偏移。gridY
支援下列特定選項:
-
: 最長肩頭的長度 (options.normalize
)number
-
: 是否現實箭頭 (options.arrowheads
; default =boolean
)true
vis.svg
此函數繪制一個
SVG
對象。輸入是一個
SVG
字元串或 一個
SVG
檔案的名稱。該功能不支援任何特定的功能options。
vis.mesh
此函數畫出一個網格圖。
輸入:
- X(tensor): shape(
或N*2
) 定義N個頂點N*3
- Y(tensor, optional):shape(
或M*2
) 定義多邊形M×3
支援下列特定選項:
-
: color (options.color
)string
-
: 多邊形的不透明性 (options.opacity
between 0 and 1)number