TensorboardX使用方法
资源来源:Pytorch模型训练实用教程
调用方法
- 首先要import tensorboardX
from tensorboardX import SummaryWriter - 直接往接口写入pytorch形式的tensor
writer.add_histogram(‘zz/x’, x, epoch) - 保存记录信息到.json文件里
writer.export_scalars_to_json("./test.json") - 及时关闭writer
writer.close()
查看结果
- 运行代码后,在linux服务器端生成的结果目录下,打开terminal
- 执行:tensorboard --logdir=‘路径’ --port=‘选择的端口’
- 在windows中转打开浏览器,打开页面:(ip地址):(端口号)
- 查看显示的界面
tensorboardX的函数
add_scalar()
功能:
在一个图表中记录一个标量的变化,常用于 Loss 和 Accuracy 曲线的记录。
参数:
add_scalar(tag, scalar_value, global_step=None, walltime=None)
- tag(string)- 该图的标签,即每张图的名字
- scalar_value(float or string)- 曲线图的 y 坐标
- global_step(int)- 曲线图的 x 坐标
- walltime(float)- 为 event 文件的文件名设置时间,默认为 time.time()
writer = SummaryWriter('../../Result/runs')
for n_iter in range(100):
y = torch.rand(1)
writer.add_scalar('data/scalar_systemtime', y[0], n_iter)
add_scalars()
功能:
在一个图表中记录多个标量的变化,常用于对比,如 Train Loss 和 Valid Loss 的比较等。
参数:
add_scalars(main_tag, tag_scalar_dict, global_step=None, walltime=None)
- main_tag(string)- 该图的标签
- tag_scalar_dict(dict)- key 是变量的 tag,value是变量的值
- global_step(int)- 曲线图的 x 坐标
- walltime(float)- 为 event 文件的文件名设置时间,默认为 time.time()
for n_iter in range(100):
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)
add_histogram()
功能:
绘制直方图和多分位数折线图,常用于监测权值及梯度的分布变化情况,便于诊断网络更新方向是否正确。
参数:
add_histogram(tag, values, global_step=None, bins=‘tensorflow’, walltime=None)
- tag(string)- 该图的标签
- values(torch.Tensor, numpy.array or string)- 用于绘制直方图的值
- global_step(int)- 曲线图的 y 坐标
- bins(string)- 决定如何取 bins,默认为‘tensorflow’,可选:’auto’, ‘fd’等
- walltime(float)- 为 event 文件的文件名设置时间,默认为 time.time()
resnet18 = models.resnet18(False)
for name, param in resnet18.named_parameters():
writer.add_histogram(name, param.clone().cpu().data.numpy(), n_iter)
可以在 HISTOGRAMS 和 DISTRIBUTIONS 里面分别得到两种图:
x 轴即变量大小,y 轴为 gloabl_step。377 表示卷积层 conv1 的权值中有 377 个weight 的大小是在 0.036 这个区间。
x 轴为 gloabl_step,由于这里没有训练,所以随着 x 轴的增加,曲线是平直的。看 y 轴,从上到下,共计 9 条曲线(若有训练,会是曲线,现在是直线),分别对应[maximum, 93%, 84%, 69%, 50%, 31%, 16%, 7%, minimum]分位数。
add_image()
功能:
绘制图片,可用于检查模型的输入,监测 feature map 的变化,或是观察 weight。
参数:
add_image(tag, img_tensor, global_step=None, walltime=None)
- tag(string)- 该图的标签
- img_tensor(torch.Tensor,numpy.array, or string/blobname)- 需要可视化的图片数据, shape = [C,H,W]
- global_step(int)- x 坐标
- walltime(float)- 为 event 文件的文件名设置时间,默认为 time.time()
通常会借助 torchvision.utils.make_grid() 将一组图片绘制到一个窗口
torchvision.utils.make_grid()
功能:
将一组图片拼接成一张图片,便于可视化。
参数:
torchvision.utils.make_grid(tensor, nrow=8, padding=2, normalize=False, range=None, scale_each=False, pad_value=0)
- tensor(Tensor or list)- 需可视化的数据,shape:(B x C x H x W) ,B 表示 batch 数,即几张图片
- nrow(int)- 一行显示几张图,默认值为 8
- padding(int)- 每张图片之间的间隔,默认值为 2
- normalize(bool)- 是否进行归一化至(0,1)
- range(tuple)- 设置归一化的 min 和 max,若不设置,默认从 tensor 中找 min 和 max
- scale_each(bool)- 每张图片是否单独进行归一化,还是 min 和 max 的一个选择
- pad_value(float)- 填充部分的像素值,默认为 0,即黑色
import torchvision.utils as vutils
img = torch.rand(32, 3, 64, 64) # (B x C x H x W)
if n_iter % 10 == 0:
x = vutils.make_grid(img, normalize=True, scale_each=True)
writer.add_image('Image', x, n_iter) # x.size= (3, 266, 530) (C*H*W)
add_graph()
功能:
绘制网络结构拓扑图
参数:
add_graph(model, input_to_model=None, verbose=False, **kwargs)
- model(torch.nn.Module)- 模型实例
- input_to_model(torch.autograd.Variable)- 模型的输入数据,可以生成一个随机数,只
要 shape 符合要求即可
import torchvision.models as models
resnet18 = models.resnet18(False)
input = torch.rand(6, 3, 224, 224)
writer.add_graph(resnet18, input)
add_embedding()
功能:
在三维空间或二维空间展示数据分布,可选 T-SNE、PCA 和 CUSTOM 方法。
参数:
add_embedding(mat, metadata=None, label_img=None, global_step=None, tag=‘default’, metadata_header=None)
- mat(torch.Tensor or numpy.array)- 需要绘制的数据,一个样本必须是一个向量形式
- shape = (N,D),N 是样本数,D 是特征维数
- metadata(list)- 数据的标签,是一个 list,长度为 N
- label_img(torch.Tensor)- 空间中展示的图片,shape = (N,C,H,W)
- global_step(int)- Global step value to record
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))
add_text()
add_text(tag, text_string, global_step=None, walltime=None)
功能: 记录文字
add_video()
add_video(tag, vid_tensor, global_step=None, fps=4, walltime=None)
功能: 记录视频
add_figure()
add_figure(tag, figure, global_step=None, close=True, walltime=None)
功能: 添加 matplotlib 图片到图像中
add_image_with_boxes()
add_image_with_boxes(tag, img_tensor, box_tensor, global_step=None, walltime=None, * *kwargs)
功能: 图像中绘制 Box,目标检测中会用到
add_pr_curve()
add_pr_curve(tag, labels, predictions, global_step=None, num_thresholds=127, weights=None, walltime=None)
功能: 绘制 PR 曲线
add_pr_curve_raw()
add_pr_curve_raw(tag, true_positive_counts, false_positive_counts, true_negative_counts, false_negative_counts, precision, recall, global_step=None, num_thresholds=127, weights=None, walltime=None)
功能: 从原始数据上绘制 PR 曲线
export_scalars_to_json()
export_scalars_to_json(path)
功能: 将 scalars 信息保存到 json 文件,便于后期使用
实际应用
卷积核可视化
net = Net() # 创建一个网络
writer = SummaryWriter(log_dir='../../Result/visual_weights')
params = net.state_dict()
for k, v in params.items():
if 'conv' in k and 'weight' in k:
c_int = v.size()[1] # 输入层通道数
c_out = v.size()[0] # 输出层通道数
for j in range(c_out):
kernel_j = v[j, :, :, :].unsqueeze(1) # 压缩维度,为make_grid制作输入
kernel_grid = vutils.make_grid(kernel_j, normalize=True, scale_each=True, nrow=c_int) # 1*输入通道数, w, h
writer.add_image(k+'_split_in_featuremap', kernel_grid, global_step=j) # j 表示feature map数
# 将一个卷积层的卷积核绘制在一起,每一行是一个feature map的卷积核
k_w, k_h = v.size()[-1], v.size()[-2]
kernel_all = v.view(-1, 1, k_w, k_h)
kernel_grid = vutils.make_grid(kernel_all, normalize=True, scale_each=True, nrow=c_int) # 1*输入通道数, w, h
writer.add_image(k + '_all', kernel_grid, global_step=666)
writer.close()
特征图可视化
net = Net()
normMean = [0.49139968, 0.48215827, 0.44653124]
normStd = [0.24703233, 0.24348505, 0.26158768]
normTransform = transforms.Normalize(normMean, normStd)
testTransform = transforms.Compose([
transforms.Resize((32, 32)),
transforms.ToTensor(),
normTransform
])
test_data = MyDataset(txt_path=txt_path, transform=testTransform)
test_loader = DataLoader(dataset=test_data, batch_size=1)
img, label = iter(test_loader).next()
x = img
writer = SummaryWriter(log_dir=log_dir)
for name, layer in net._modules.items():
x = x.view(x.size(0), -1) if 'fc' in name else x
x = layer(x) # 对x执行单层运算
x = F.relu(x) if 'conv' in name else x
if name == 'conv1':
x1 = x.transpose(0, 1) # C, B, H, W ---> B, C, H, W
img_grid = vutils.make_grid(x1, normalize=True, scale_each=True, nrow=2) # B, C, H, W
writer.add_image(vis_layer + '_feature_maps', img_grid, global_step=666)
# 绘制原始图像
img_raw = normalize_invert(img, normMean, normStd) # 图像去标准化
img_raw = np.array(img_raw * 255).clip(0, 255).squeeze().astype('uint8')
writer.add_image('raw img', img_raw, global_step=666) # j 表示feature map数
writer.close()