Pytorch框架学习—(5)调整学习率、可视化操作
本节简单总结Pytorch中用于学习率调整的函数,如何使用tensorboard可视化曲线、梯度、权重、特征图、卷积核,以及如何使用torchvision.utils.make_grid()制作网格图。【文中思维导图采用MindMaster软件】
目录
1.学习率的调整
2.tensorboard可视化工具
(1)流程
(2)如何记录可视化的数据?
①scalar绘制曲线(单条、多条)
②histogram直方图,查看权重、梯度,判断是否梯度消失或发散
③记录图像(利用torchvision.utils中make_grid制作网格)
④利用make_grid可视化特征图
⑤graph可视化模型计算图
1.学习率的调整
Pytorch中封装了调整LR的函数,如下:
它们都继承父类class _LRScheduler,需要复写函数def get_lr(self),该函数用于计算学习率并返回:
class _LRScheduler(object):
def __init__(self, optimizer, last_epoch=-1):
······
def get_lr(self):
raise NotImplementedError
参数:
optimizer:优化器类实例
last_epoch:记录epoch数
base_lrs:记录初始学习率,该参数用于后续的学习率计算
方法:
step():更新下一个epoch的学习率
get_lr():虚函数,计算下一个epoch学习率
节省精力, 由于网上已经有人对这六个函数总结的很好,故在此引用,不再复写。
2.tensorboard可视化工具
(1)流程
(2)如何记录可视化的数据?
调用SummaryWriter类,代码如下:
'''SummaryWriter类'''
class SummaryWriter(object):
def __init__(self, log_dir=None, comment='', purge_step=None, max_queue=10,
flush_secs=120, filename_suffix=''):
# 参数如下:
# log_dir:eventfile输出文件夹地址
# comment:当不指定log_dir时,该参数为文件夹的后缀
# filename_suffix:eventfile文件名的后缀
'''实际运用时'''
from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter(log_dir='./a',comment="handw_exp",filename_suffix="test1")
若不指定log_dir,则直接该项目下创建runs文件夹,可对照下图进行理解:
各种记录数据的方法如下:
①scalar绘制曲线(单条、多条)
'''一张图中,只能单条曲线'''
def add_scalar(self, tag, scalar_value, global_step=None, walltime=None):
# 参数:
# tag:图像的标签名
# scalar_value:要记录的标量,例如loss
# global_step:x轴
'''一张图中,可以多条曲线'''
def add_scalars(self, main_tag, tag_scalar_dict, global_step=None, walltime=None):
# 参数:
# main_tag:总的标签名,用于曲线索引放置
# tag_scalar_dict:要记录的标量,例如loss
# global_step:x轴
实战中,以 def add_scalars 为例:
iter_count = 0
for epoch in range(Max_Epoch):
······
for i, (inputs, labels) in enumerate(train_loader):
iter_count += 1
······
writer.add_scalars(main_tag="Loss", tag_scalar_dict={"Train": loss.item()}, global_step=iter_count)
writer.add_scalars("Accuracy", {"Train": correct/total}, global_step=iter_count)
if (epoch+1) % print_info_valid == 0:
······
with torch.no_grad():
for j,(inputs_valid,labels_valid) in enumerate(test_loader):
······
writer.add_scalars("Loss", {"Valid": loss_info_valid/len(test_loader)}, iter_count)
writer.add_scalars("Accuracy", {"Valid": correct_valid / total_valid}, iter_count)
writer.flush() # 及时刷新,否则无法同时观看到训练和验证
writer.close()
此时通过pycharm终端,输入 tensorboard –logdir=./a(event的地址),就会得到tensorboard的可视化网址,打开可以得到如下图:
②histogram直方图,查看权重、梯度,判断是否梯度消失或发散
def add_histogram(self, tag, values, global_step=None, bins='tensorflow', walltime=None, max_bins=None):
# 参数:
# tag:图像的标签名
# values:要统计的参数
# global_step:y轴!!!!!!!!!!!!!(结合下图理解)
实战中,代码参考如下:
# 每一个epoch,记录各层权重、梯度
for name, param in net.named_parameters(): # 返回网络的
writer.add_histogram(name + '_grad', param.grad, epoch)
writer.add_histogram(name + '_data', param, epoch)
貌似横轴是大小,高度代表该数值下的个数???:
③记录图像(利用torchvision.utils中make_grid制作网格)
torchvision.utils.make_grid()函数定义:
def make_grid(tensor, nrow=8, padding=2,
normalize=False, range=None, scale_each=False, pad_value=0):
# 参数:
# tensor:必须是B*C*H*W形式
# nrow:指定行数
# padding:图像与图像之间的间隔多少个像素单位pad_value
# normalize:是否将像素值标准化到(0~255)
# range:指定标准化范围,先将像素值规范到该range,然后再进行(0~255)转换
# scale_each:是否对单张图像进行range
# pad_value:指定padding的大小(黑色0、白色255等等)
实战中,代码参考如下:
'''调用torchvision中make_grid 网格可视化图像'''
import torchvision.utils as vutils
img_batch,label_batch = next(iter(train_loader)) # 调用一个批次的图片
img_grid = vutils.make_grid(img_batch, nrow=10,normalize=True) # 变为 C*H*W
writer.add_image("make_grid",img_grid, global_step=0)
writer.flush()
'''当然也可以直接调用add_image或add_images'''
def add_image(self, tag, img_tensor, global_step=None, walltime=None, dataformats='CHW'):
# 参数:
# 非常不方便,只能查看一个图像!!!!
# 当像素值为【0,1】,则乘以255,缩放回【0,255】;若像素值不在【0,1】之间,默认是0~255范围内。
# tag:图像的标签名
# img_tensor:注意shape,可以是3HW、HW3、HW、1HW,但不能是四维的,即有batch!!!!!!!(可以通过add_images解决或torchvision.utils.make_grid())
# global_step:x轴
def add_images(self, tag, img_tensor, global_step=None, walltime=None, dataformats='NCHW'):
# 参数:
# 无法指定行数!!!!!
# tag:图像的标签名
# img_tensor:注意shape,可以是NCHW or NHWC,但是,这里Channel在后续处理的时候只能为1或者3!!!!!
# global_step:x轴
④利用make_grid可视化特征图
vlaid_img,_ = next(iter(test_loader))
conv1 = net.cpu().feature[0]
fmap1 = conv1(vlaid_img) # 100*16*72*72
fmap1_first = fmap1[0,:,:,:]
fmap1_first.unsqueeze_(0).transpose_(0,1) # 16*1*72*72
fmap1_grid = vutils.make_grid(fmap1_first,4,normalize=True)
writer.add_image("fmap", fmap1,global_step=0)
从下面的特征图可以看出: 经过卷积核操作后,得到的各种特征图(提取边缘后、锐化后等等)。
⑤graph可视化模型计算图
def add_graph(self, model, input_to_model=None, verbose=False):
# 参数:
# model:模型,必须是继承torch.nn.Module
# input_to_model:模型的输入
# verbose:是否打印计算图结构信息
'''可视化模型计算图'''
input_v = torch.rand((1,3,75,75))
writer.add_graph(net, input_v)
writer.flush()