Pytorch框架学习---(5)调整学习率、可视化操作

本节简单总结Pytorch中用于学习率调整的函数,如何使用tensorboard可视化曲线、梯度、权重、特征图、卷积核,以及如何使用torchvision.utils.make_grid()制作网格图。【文中思维导图采用MindMaster软件

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可视化特征图

(每次都要调出对应层,一个个输入,一个个输出,有点麻烦,即便调用for循环,代码也有点冗余性,下一节介绍的hook函数就可以在网络运行过程中,直接保存特征图)

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()
原文地址:https://www.cnblogs.com/zpc1001/p/13322902.html