"); //-->
作者 | 锦恢@知乎
来源 | https://zhuanlan.zhihu.com/p/220403674
编辑 | 极市平台
导读
本文大致想说一下pytorch下的网络结构可视化和训练过程可视化。
一、网络结构的可视化我们训练神经网络时,除了随着step或者epoch观察损失函数的****,从而建立对目前网络优化的基本认知外,也可以通过一些额外的可视化库来可视化我们的神经网络结构图。这将更加地高效地向读者展现目前的网络结构。
为了可视化神经网络,我们先建立一个简单的卷积层神经网络:
import torch
import torch.nn as nn
class ConvNet(nn.Module):
def __init__(self):
super(ConvNet, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(1, 16, 3, 1, 1),
nn.ReLU(),
nn.AvgPool2d(2, 2)
)
self.conv2 = nn.Sequential(
nn.Conv2d(16, 32, 3, 1, 1),
nn.ReLU(),
nn.MaxPool2d(2, 2)
)
self.fc = nn.Sequential(
nn.Linear(32 * 7 * 7, 128),
nn.ReLU(),
nn.Linear(128, 64),
nn.ReLU()
)
self.out = nn.Linear(64, 10)
def forward(self, x):
x = self.conv1(x)
x = self.conv2(x)
x = x.view(x.size(0), -1)
x = self.fc(x)
output = self.out(x)
return output
输出网络结构:
MyConvNet = ConvNet()
print(MyConvNet)
输出结果:
ConvNet(
(conv1): Sequential(
(0): Conv2d(1, 16, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): AvgPool2d(kernel_size=2, stride=2, padding=0)
)
(conv2): Sequential(
(0): Conv2d(16, 32, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU()
(2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(fc): Sequential(
(0): Linear(in_features=1568, out_features=128, bias=True)
(1): ReLU()
(2): Linear(in_features=128, out_features=64, bias=True)
(3): ReLU()
)
(out): Linear(in_features=64, out_features=10, bias=True)
)
有了基本的神经网络后,我们分别通过HiddenLayer和PyTorchViz库来可视化上述的卷积层神经网络。
1.1 通过HiddenLayer可视化网络需要说明的是,这两个库都是基于Graphviz开发的,因此倘若你的电脑上没有安装并且没有添加环境变量,请自行安装Graphviz工具,安装教程
首先当然是安装库啦,打开cmd,输入:
pip install hiddenlayer
绘制的基本程序如下:
import hiddenlayer as h
vis_graph = h.build_graph(MyConvNet, torch.zeros([1 ,1, 28, 28])) # 获取绘制图像的对象
vis_graph.theme = h.graph.THEMES["blue"].copy() # 指定主题颜色
vis_graph.save("./demo1.png") # 保存图像的路径
效果如下:
1.2 通过PyTorchViz可视化网络先安装库:
pip install torchviz
这里我们只使用可视化函数make_dot()来获取绘图对象,基本使用和HiddenLayer差不多,不同的地方在于PyTorch绘图之前可以指定一个网络的输入值和预测值。
from torchviz import make_dot
x = torch.randn(1, 1, 28, 28).requires_grad_(True) # 定义一个网络的输入值
y = MyConvNet(x) # 获取网络的预测值
MyConvNetVis = make_dot(y, params=dict(list(MyConvNet.named_parameters()) + [('x', x)]))
MyConvNetVis.format = "png"
# 指定文件生成的文件夹
MyConvNetVis.directory = "data"
# 生成文件
MyConvNetVis.view()
打开与上述代码相同根目录下的data文件夹,里面会有一个.gv文件和一个.png文件,其中的.gv文件是Graphviz工具生成图片的脚本代码,.png是.gv文件编译生成的图片,直接打开.png文件就行。
默认情况下,上述程序运行后会自动打开.png文件
生成图片:
二、训练过程可视化观察我们的网络的每一步的损失函数或准确率的变化可以有效地帮助我们判断当前训练过程的优劣。如果能将这些过程可视化,那么我们判断的准确性和舒适性都会有所增加。
此处主要讲通过可视化神器tensorboardX和刚刚用到的HiddenLayer来实现训练过程的可视化。
为了训练网络,我们先导入训练网络需要的数据,此处就导入MNIST数据集,并做训练前的一些基本的数据处理。
import torchvision
import torch.utils.data as Data
# 准备训练用的MNIST数据集
train_data = torchvision.datasets.MNIST(
root = "./data/MNIST", # 提取数据的路径
train=True, # 使用MNIST内的训练数据
transform=torchvision.transforms.ToTensor(), # 转换成torch.tensor
download=False # 如果是第一次运行的话,置为True,表示下载数据集到root目录
)
# 定义loader
train_loader = Data.DataLoader(
dataset=train_data,
batch_size=128,
shuffle=True,
num_workers=0
)
test_data = torchvision.datasets.MNIST(
root="./data/MNIST",
train=False, # 使用测试数据
download=False
)
# 将测试数据压缩到0-1
test_data_x = test_data.data.type(torch.FloatTensor) / 255.0
test_data_x = torch.unsqueeze(test_data_x, dim=1)
test_data_y = test_data.targets
# 打印一下测试数据和训练数据的shape
print("test_data_x.shape:", test_data_x.shape)
print("test_data_y.shape:", test_data_y.shape)
for x, y in train_loader:
print(x.shape)
print(y.shape)
break
结果:
test_data_x.shape: torch.Size([10000, 1, 28, 28])2.1 通过tensorboardX可视化训练过程
test_data_y.shape: torch.Size([10000])
torch.Size([128, 1, 28, 28])
torch.Size([128])
tensorboard是谷歌开发的深度学习框架tensorflow的一套深度学习可视化神器,在pytorch团队的努力下,他们开发出了tensorboardX来让pytorch的玩家也能享受tensorboard的福利。
先安装相关的库:
pip install tensorboardX
pip install tensorboard
并将tensorboard.exe所在的文件夹路径加入环境变量path中(比如我的tensorboard.exe的路径为D:\Python376\Scripts\tensorboard.exe,那么就在path中加入D:\Python376\Scripts)
下面是tensorboardX的使用过程。基本使用为,先通过tensorboardX下的SummaryWriter类获取一个日志编写器对象。然后通过这个对象的一组方法往日志中添加事件,即生成相应的图片,最后启动前端服务器,在localhost中就可以看到最终的结果了。
训练网络,并可视化网络训练过程的代码如下:
from tensorboardX import SummaryWriter
logger = SummaryWriter(log_dir="data/log")
# 获取优化器和损失函数
optimizer = torch.optim.Adam(MyConvNet.parameters(), lr=3e-4)
loss_func = nn.CrossEntropyLoss()
log_step_interval = 100 # 记录的步数间隔
for epoch in range(5):
print("epoch:", epoch)
# 每一轮都遍历一遍数据加载器
for step, (x, y) in enumerate(train_loader):
# 前向计算->计算损失函数->(从损失函数)反向传播->更新网络
predict = MyConvNet(x)
loss = loss_func(predict, y)
optimizer.zero_grad() # 清空梯度(可以不写)
loss.backward() # 反向传播计算梯度
optimizer.step() # 更新网络
global_iter_num = epoch * len(train_loader) + step + 1 # 计算当前是从训练开始时的第几步(全局迭代次数)
if global_iter_num % log_step_interval == 0:
# 控制台输出一下
print("global_step:{}, loss:{:.2}".format(global_iter_num, loss.item()))
# 添加的第一条日志:损失函数-全局迭代次数
logger.add_scalar("train loss", loss.item() ,global_step=global_iter_num)
# 在测试集上预测并计算正确率
test_predict = MyConvNet(test_data_x)
_, predict_idx = torch.max(test_predict, 1) # 计算softmax后的最大值的索引,即预测结果
acc = accuracy_score(test_data_y, predict_idx)
# 添加第二条日志:正确率-全局迭代次数
logger.add_scalar("test accuary", acc.item(), global_step=global_iter_num)
# 添加第三条日志:这个batch下的128张图像
img = vutils.make_grid(x, nrow=12)
logger.add_image("train image sample", img, global_step=global_iter_num)
# 添加第三条日志:网络中的参数分布直方图
for name, param in MyConvNet.named_parameters():
logger.add_histogram(name, param.data.numpy(), global_step=global_iter_num)
运行完后,我们通过cmd来到与代码同一级的目录(如果你使用的是pycharm,可以通过pycharm中的终端)输入指令tensorboard --logdir="./data/log",启动服务器。
logdir后面的参数是日志文件的文件夹的路径
然后在谷歌浏览器中访问红框框中的url,便可得到可视化界面,点击上面的页面控件,可以查看我们通过add_scalar、add_image和add_histogram得到的图像,而且各方面做得都很丝滑。
以下是笔者安装使用tensorboard时遇到的一些错误。
好,作为一名没有装过TensorFlow的windows玩家,笔者下面开始踩坑。踩完后,直接把几个可能的错误呈上。
第一个错误,运行tensorboard --logdir="./data/log",遇到报错,内容为有重复的tensorboard的包。
解决方法:找到site-packages(如果你是像我一样全局安装的,那么找到解释器那一级目录的site-packages,如果是在项目虚拟环境中安装的,那么找到项目中的site-packages),删去下图中红框框标出来的文件夹。
第二个错误,在解决第一个错误后,再次运行命令,还是报错,内容为编码出错。由于笔者做过一点前端,在学习webpack项目时,曾经被告知项目路径不能含有中文,否则会有编码错误,而刚才的报错中涉及到了前端服务器的启动,因此,笔者想到从文件名入手。
解决方法:确保命令涉及的文件路径、所有程序涉及到文件不含中文。笔者是计算机名字含有中文,然后tensorboard的日志文件是以本地计算机名为后缀的,所以笔者将计算机名修改成了英文,重启后再输入指令就ok了。
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。