1.前言
tensorflow框架可以使用tensorboard这一高级的可视化的工具,而Pytorch可以使用tensorboardX可视化
2.环境依赖
python3.6+
pytorch0.4.0+
tensorboardX : pip install tensorboardX
注意:Pytorch下使用tensorboardX不需要安装tensorflow
3.教程
本文主要介绍scalar 、 graph和feature maps
3.1 scale教程
import numpy as np
from tensorboardX import SummaryWriter
writer = SummaryWriter()
for epoch in range(100):
# 参数依次为生成的文件所放的目录、要保存的值、步数;第二个参数是可以理解为Y轴数据,第三个参数可以理解为X轴数据;当Y轴数据不止一个时,可以使用writer.add_scalars()
writer.add_scalar('scalar/test', np.random.rand(), epoch)
# writer.add_scalars添加许多的scalars,参数为生成文件所放的目录、要保存的键值对
writer.add_scalars('scalar/scalars_test', {'xsinx': epoch * np.sin(epoch), 'xcosx': epoch * np.cos(epoch)}, epoch)
writer.close()
运行上述代码,会生成runs文件夹,里面就保存了我们要可视化的东西
可视化
打开cmd或者终端,输入tensorboard --logdir=filename
这里的filename必须是你的文件的上一级目录,不然会报错No dashboards are active for the current data set
以下图为例
我这里的runs文件夹下的Nov7_16-08-14文件夹下有我需要可视化的内容,那么在命令行中输入的内容是
这时会在终端里面显示网址,复制到浏览器里面就可以看到结果
3.2 graph教程
主要是可视化网络结构
import torch
import torch.nn as nn
from tensorboardX import SummaryWriter
class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Sequential( #input_size=(1*28*28)
nn.Conv2d(1, 6, 5, 1, 2),
nn.ReLU(), #(6*28*28)
nn.MaxPool2d(kernel_size=2, stride=2), #output_size=(6*14*14)
)
self.conv2 = nn.Sequential(
nn.Conv2d(6, 16, 5),
nn.ReLU(), #(16*10*10)
nn.MaxPool2d(2, 2) #output_size=(16*5*5)
)
self.fc1 = nn.Sequential(
nn.Linear(16 * 5 * 5, 120),
nn.ReLU()
)
self.fc2 = nn.Sequential(
nn.Linear(120, 84),
nn.ReLU()
)
self.fc3 = nn.Linear(84, 10)
# 定义前向传播过程,输入为x
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
# nn.Linear()的输入输出都是维度为一的值,所以要把多维度的tensor展平成一维
x = x.view(x.size()[0], -1)
x = self.fc1(x)
x = self.fc2(x)
x = self.fc3(x)
return x
dummy_input = torch.rand(13, 1, 28, 28) #假设输入13张1*28*28的图片
model = LeNet()
with SummaryWriter(comment='LeNet') as w:
# 第一个参数为需要保存的模型,第二个参数为输入值,元组类型
w.add_graph(model, (dummy_input, ))
运行代码,生成一个文件夹,如下图,里面又保存了我们需要可视化的东西
打开终端,输入tensorboard --logdir=Nov07_16-35-05_gaoyao-N8xEJEKLeNet
,复制网址,得到下图
接着点击上面的GRAPHS,就出现了网络结构。双击LeNet就出现了详细的网络结构。
3.3 feature maps教程
import torch
import torch.nn as nn
from torchvision import models, transforms, datasets
from torchvision.utils import make_grid
from tensorboardX import SummaryWriter
from PIL import Image
'''动起手来就已经成功一半了'''
net = models.vgg16(pretrained= True).eval() # 用预训练好的vgg16可视化lenna图片各层features map
'''我要利用net这个模型实例重建一个模型,大改net的话问题太多了'''
class Map(nn.Module):
def __init__(self):
super(Map, self).__init__()
self.model = nn.Sequential()
self.names = []
i = j_1 = j_2 = j_3 = j_4 = 1
# 卷积-BN-激活-池化(遇到池化就划分一截)为一个部分,用i表示;j_1,2,3,4表示每个部分内的卷积,BN,激活,池化
'''实验过后发现,a=b=1,对a变化不影响b,尽管id一样;a,b=1,1时也不会相互影响'''
for layer in net.features.children(): # 我们不需要classifier中的全连接等层(这个for循环主要就是为了给每层重新起个名字)
if isinstance(layer, nn.Conv2d):
name = 'conv%d_%d'%(i, j_1)
j_1 += 1
elif isinstance(layer, nn.BatchNorm2d):
name = 'bn%d_%d'%(i, j_2)
j_2 += 1
elif isinstance(layer, nn.ReLU):
name = 'relu%d_%d'%(i, j_3)
j_3 += 1
elif isinstance(layer, nn.MaxPool2d):
name = 'maxpool%d_%d'%(i, j_4)
i += 1
j_1 = j_2 = j_3 = 1
#else:
#raise RuntimeError('Unrecognized layer: %s'%(layer.__class__.__name__)
self.model.add_module(name, layer) # 把layer添加到model并取名为name
self.names.append(name)
#print(self.model) # 也可以打印出来模型看看哦
def forward(self, input_img):
writer = SummaryWriter(log_dir='feature_map') # 定义tensorboard文件夹名称
for i, layer in enumerate(self.model.children()):
print(self.names[i]) # 输出这层名字
print(input_img.size())
input_img = layer(input_img) # feature maps
input_img = input_img.permute(1, 0, 2 ,3) # 第0和第1维转置,交换位置,是为了适应make_grid函数
print(input_img.size()) # 打印维度看看,变化成功了
# make_grid的作用是将若干幅图像拼成一幅图像;
# torchvision.utils.make_grid(tensor, nrow, padding, normalize, range, scale_each, padding_value)
# 参数依次为:相同大小的图片列表(形状为N*C*H*W)、网格每一行显示的图片数(默认为8)、填充数量即子图像与子图像的间距(默认为2)、normal为True,减去最小像素值,除以最大像素值,将结果限制到(0,1)
# range(min, max)--上一步提到的最小、最大像素值、padding_value:填充像素值
result = make_grid(input_img, normalize=True) # 一个channel代表一张图片,把每层的多个图片拼接成一张大图
writer.add_image(self.names[i], result, i) # 每次写入时step为i,不写这个step不报错,但你会发现新图可能会覆盖旧图(没试过)
input_img = input_img.transpose(1, 0) # Tensor维度还要变回去,否则下次循环,维度不是BCHW的话layer(input_img)会出错的
writer.close()
# permute(1,0,2,3)需要把所有维度都写出来;transpose(1,0)可以只把需要转置的几个维度写出来;功能是差不多的
model = Map() # 新模型实例
image_path = '1.jpg'
image = Image.open(image_path)
transform = transforms.Compose([
transforms.ToTensor(), #转为Tensor格式,并将值取在[0,1]中
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) #标准化,得到在[-1,1]的值
])
image = transform(image).unsqueeze(0) # 图片有三个通道,而VGG等网络的输入都需要BCHW,增加一个虚拟维度
model(image) # 让新模型跑起来(坐等结果吧)
执行完之后,也会生成文件夹feature_map,在终端输入tensorboard --logdir=feature_map
打开浏览器即可看到效果
可能会遇到的错误
TypeError: clamp_(): argument ‘min’ must be Number, not Tensor
解决方法:在所安装的torchvision的utils.py的60行,改为下面的代码,可能是版本问题。
norm_ip(t, float(t.min()), float(t.max()))
2019.11.21
训练loss可视化
import torch
import torch.nn as nn
from tensorboardX import SummaryWriter
from matplotlib import 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()
writer.add_scalar('Train', loss, epoch)
if (epoch + 1) % 5 == 0:
print('Epoch {}/{}, loss:{:.4f}'.format(epoch + 1, num_epoches, loss.item()))
运行生成runs文件夹,进入runs文件夹
终端输入tensorboard --logdir=Nov21_09-30-47_gaoyao-N8xEJEKLinear ,在浏览器输入网址即可
参考
https://zhuanlan.zhihu.com/p/54947519utm_source=wechat_session&utm_medium=social&utm_oi=697408796275777536