前言
之前实现了一些常见的网络架构,但是有些网络架构并没有细说,并且网络传输过程中shape的变化也很少谈及过。
除此之外,前面的实现很少涉及到可视化的内容,比如损失值的可视化、网络结构的可视化。
所以本期博客就是补充一下这几点。
目录结构
安装tensorboardX
安装可视化库:
pip install tensorboardX
当然建议指定镜像源:
pip install tensorboardX -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
安装torchkeras
如果你想要使用tensorflow库的summary,可以安装这个库:
pip install torchkeras -i https://pypi.tuna.tsinghua.edu.cn/simple some-package
还记得LeNet5这个网络架构吗,我下面演示的代码都是基于这个代码来的,不清楚的可以看这篇文章。
首先导入库:
from torchkeras import summary
当然,其它的代码,比如创建模型、定义优化器等我们不说。只说如何使用这个方法。
summary使用很简单,直接按照下面的格式使用即可:
# 打印summary值
print(summary(model,input_shape=(1,28,28)))
注意:
input_shape
为输入的shape大小,比如这里用的MNIST数据集,所以shape=[1,28,28] 打印的结果值:
--------------------------------------------------------------------------
Layer (type) Output Shape Param #
==========================================================================
Conv2d-1 [-1, 6, 28, 28] 156
Sigmoid-2 [-1, 6, 28, 28] 0
MaxPool2d-3 [-1, 6, 14, 14] 0
Conv2d-4 [-1, 16, 10, 10] 2,416
Sigmoid-5 [-1, 16, 10, 10] 0
MaxPool2d-6 [-1, 16, 5, 5] 0
Linear-7 [-1, 120] 48,120
Sigmoid-8 [-1, 120] 0
Linear-9 [-1, 84] 10,164
Sigmoid-10 [-1, 84] 0
Linear-11 [-1, 10] 850
==========================================================================
Total params: 61,706
Trainable params: 61,706
Non-trainable params: 0
--------------------------------------------------------------------------
Input size (MB): 0.002991
Forward/backward pass size (MB): 0.111404
Params size (MB): 0.235390
Estimated Total Size (MB): 0.349785
--------------------------------------------------------------------------
--------------------------------------------------------------------------
Layer (type) Output Shape Param #
==========================================================================
Conv2d-1 [-1, 6, 28, 28] 156
Sigmoid-2 [-1, 6, 28, 28] 0
MaxPool2d-3 [-1, 6, 14, 14] 0
Conv2d-4 [-1, 16, 10, 10] 2,416
Sigmoid-5 [-1, 16, 10, 10] 0
MaxPool2d-6 [-1, 16, 5, 5] 0
Linear-7 [-1, 120] 48,120
Sigmoid-8 [-1, 120] 0
Linear-9 [-1, 84] 10,164
Sigmoid-10 [-1, 84] 0
Linear-11 [-1, 10] 850
==========================================================================
Total params: 61,706
Trainable params: 61,706
Non-trainable params: 0
--------------------------------------------------------------------------
Input size (MB): 0.002991
Forward/backward pass size (MB): 0.111404
Params size (MB): 0.235390
Estimated Total Size (MB): 0.349785
--------------------------------------------------------------------------
相比于summary,我个人觉得tensorboardX更好用,因为它可以将结果可视化,并且操作也十分简单。
代码中使用流程与举例
首先,标准的使用流程为:
# 1. 导入库
from tensorboardX import SummaryWriter
# 2. 创建对象,
writer = SummaryWriter()
# 路径一般默认,不过也可以指定
# 指定路径: writer = SummaryWriter('.\temp')
# 3. 可视化1: 可视化某个变量的值,一般为损失值
writer.add_scalar('变量名字',存储的值,序号)
# 其中序号指的是损失值的序号,比如1、2、3这样的,目的是区分不同值
# 日志记录: 序号 --- 变量名字 --- 存储值
# 4. 可视化2:可视化模型结构
writer.add_graph(model,input_to_model=batch_data)
# 第一个参数为模型
# 第二个参数为输入的shape,一般直接用batch_data即可
# 注意两者必须在同一设备中,和summary类似
# 5. 关闭可视化
writer.close()
那么,以LeNet5举个例子:
# 导入可视化
from tensorboardX import SummaryWriter
# 创建模型
class LeNet(nn.Module):
...
# 下载数据集或者加载数据集
...
# 加载数据: 分批次,每批256个数据
...
# 创建模型
model = LeNet()
# 模型放入GPU中
...
# 定义损失函数、优化器
...
# *****初始化可视化对象*****
writer = SummaryWriter() # 路径一般默认,不过也可以指定
# 开始训练
x = 0 # 用于指定序号
for i in range(10):
...
for j,(batch_data,batch_label) in enumerate(train_loader):
...
if (j + 1) % 200 == 0:
...
# 可视化1:一般添加loss值
writer.add_scalar('200_step_loss',loss_temp / 200,x)
x += 1
...
# 可视化2:模型结构
writer.add_graph(model,input_to_model=batch_data)
# 关闭可视化
writer.close()
对于上面需要说明的一点:(图画的有点抽象,见谅)
可视化
当上述代码云心完毕后,如果你没有更改默认路径,那么在所属文件夹会出现一个名为runs
的文件夹:
那么,你打开Windows的cmd,进入当前目录,运行下面的代码:
tensorboard --logdir=runs
然后,将给出的网址复制到浏览器打开(此时不要关闭cmd窗口):
网络结构的可视化操作还是比较简单的,而且效果也非常不错。如果你要做ppt或者其它的,建议可以试一试。
LeNet5案例完整代码(需要根据需求修改注释)
# author: baiCai
# 导包
import time
import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
from torchvision.datasets import MNIST
import torchvision.transforms as transforms
# 导入可视化
from tensorboardX import SummaryWriter
from torchkeras import summary
# 创建模型
class LeNet(nn.Module):
def __init__(self):
super(LeNet,self).__init__()
# 定义模型
self.features = nn.Sequential(
nn.Conv2d(in_channels=1,out_channels=6,kernel_size=(5,5),stride=1,padding=2),
nn.Sigmoid(),
nn.MaxPool2d(kernel_size=2,stride=2),
nn.Conv2d(in_channels=6,out_channels=16,kernel_size=(5,5),stride=1),
nn.Sigmoid(),
nn.MaxPool2d(kernel_size=2,stride=2),
)
self.classifier = nn.Sequential(
nn.Linear(in_features=400, out_features=120),
nn.Sigmoid(),
nn.Linear(in_features=120, out_features=84),
nn.Sigmoid(),
nn.Linear(in_features=84, out_features=10)
)
def forward(self,x):
# 定义前向算法
x = self.features(x)
# print(x.shape)
x = torch.flatten(x,1)
# print(x.shape)
result = self.classifier(x)
return result
# 下载数据集或者加载数据集
train_dataset = MNIST(root='../data',train=True,transform=transforms.ToTensor(),download=True)
test_dataset = MNIST(root='../data',train=False,transform=transforms.ToTensor())
# 加载数据: 分批次,每批256个数据
batch_size = 32
train_loader = DataLoader(dataset=train_dataset,batch_size=batch_size,shuffle=True)
test_loader = DataLoader(dataset=test_dataset,batch_size=batch_size,shuffle=False)
# start time
start_time = time.time()
# 创建模型
model = LeNet()
# 模型放入GPU中
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = model.to(device)
# 定义损失函数
loss_func = nn.CrossEntropyLoss()
loss_list = [] # 用来存储损失值
# 定义优化器
SGD = optim.Adam(params=model.parameters(),lr=0.001)
# 初始化可视化对象
writer = SummaryWriter() # 路径一般默认,不过也可以指定
# 打印summary值
# print(summary(model,input_shape=(1,28,28)))
# 训练指定次数
x = 0
for i in range(10):
loss_temp = 0 # 定义一个损失值,用来打印查看
# 其中j是迭代次数,data和label都是批量的,每批32个
for j,(batch_data,batch_label) in enumerate(train_loader):
# 启用GPU
batch_data,batch_label = batch_data.cuda(),batch_label.cuda()
# 清空梯度
SGD.zero_grad()
# 模型训练
prediction = model(batch_data)
# 计算损失
loss = loss_func(prediction,batch_label)
loss_temp += loss
# BP算法
loss.backward()
# 更新梯度
SGD.step()
if (j + 1) % 200 == 0:
print('第%d次训练,第%d批次,损失值: %.3f' % (i + 1, j + 1, loss_temp / 200))
# 可视化1:一般添加loss值
writer.add_scalar('200_step_loss',loss_temp / 200,x)
x += 1
loss_temp = 0
# end_time
end_time = time.time()
print('训练花了: %d s' % int((end_time-start_time)))
# 可视化2:模型结构
writer.add_graph(model,input_to_model=batch_data)
# 关闭可视化
writer.close()
# 使用GPU: 训练花了: 124 s
# 不适用GPU:训练花了: 160 s
# 测试
# correct = 0
# for batch_data,batch_label in test_loader:
# batch_data, batch_label = batch_data.cuda(), batch_label.cuda()
# prediction = model(batch_data)
# predicted = torch.max(prediction.data, 1)[1]
# correct += (predicted == batch_label).sum()
# print('准确率: %.2f %%' % (100 * correct / 10000)) # 因为总共10000个测试数据
# 准确率: 11.35 %