zoukankan      html  css  js  c++  java
  • Pytorch trick集锦

    1.查看模型每层输出详情

    1 from torchsummary import summary
    2 summary(your_model, input_size=(channels, H, W))

    input_size是根据你自己的网络模型的输入尺寸进行设置。

    2.梯度裁剪

    1 import torch.nn as nn
    2 
    3 outputs = model(data)
    4 loss= loss_fn(outputs, target)
    5 optimizer.zero_grad()
    6 loss.backward()
    7 nn.utils.clip_grad_norm_(model.parameters(), max_norm=20, norm_type=2)
    8 optimizer.step()

    nn.utils.clip_grad_norm_的参数:

    • parameters – 一个基于变量的迭代器,会进行梯度归一化
    • max_norm – 梯度的最大范数
    • norm_type – 规定范数的类型,默认为L2

    3.扩展单张图片维度

    因为在训练时的数据维度一般都是 (batch_size, c, h, w),而在测试时只输入一张图片,所以需要扩展维度,扩展维度有多个方法:

     1 import cv2
     2 import torch
     3 
     4 image = cv2.imread('1.png')
     5 image = torch.tensor(image)
     6 print(image.size())                     #torch.Size([296, 790, 3])
     7 
     8 img1 = image.view(1, *image.size())
     9 print(img1.size())                      #torch.Size([1, 296, 790, 3])
    10 
    11 #或者
    12 img2 = image.unsqueeze(dim=0)  
    13 print(img2.size())                      #torch.Size([1, 296, 790, 3])

    4.独热编码

    在PyTorch中使用交叉熵损失函数的时候会自动把label转化成onehot,所以不用手动转化,而使用MSE需要手动转化成onehot编码。

     1 import torch
     2 import torch.nn.functional as F
     3 
     4 class_num = 8
     5 batch_size = 4
     6 
     7 def one_hot(label):
     8     """
     9     将一维列表转换为独热编码
    10     """
    11     label = label.resize_(batch_size, 1)
    12     m_zeros = torch.zeros(batch_size, class_num)
    13     # 从 value 中取值,然后根据 dim 和 index 给相应位置赋值
    14     onehot = m_zeros.scatter_(1, label, 1)       # (dim,index,value)
    15 
    16     return onehot.numpy()  # Tensor -> Numpy
    17 
    18 label = torch.LongTensor(batch_size) % class_num  # 对随机数取余
    19 print(label)
    20 print(one_hot(label))
    21 
    22 #或者
    23 encode = F.one_hot(label, num_classes = class_num)
    24 print(encode)

    运行结果:

     1 tensor([5, 3, 3, 2])
     2 [[0. 0. 0. 0. 0. 1. 0. 0.]
     3  [0. 0. 0. 1. 0. 0. 0. 0.]
     4  [0. 0. 0. 1. 0. 0. 0. 0.]
     5  [0. 0. 1. 0. 0. 0. 0. 0.]]
     6 tensor([[[0, 0, 0, 0, 0, 1, 0, 0]],
     7 
     8         [[0, 0, 0, 1, 0, 0, 0, 0]],
     9 
    10         [[0, 0, 0, 1, 0, 0, 0, 0]],
    11 
    12         [[0, 0, 1, 0, 0, 0, 0, 0]]])

    Tip:torch.nn.functional.one_hot函数返回的是Tensor类型

    5.防止验证模型时爆显存

    验证模型时不需要求导,即不需要梯度计算,关闭autograd,可以提高速度,节约内存。

    1 with torch.no_grad():
    2     # 使用model进行预测的代码
    3     pass

    6.学习率衰减

     1 import torch.optim as optim
     2 from torch.optim import lr_scheduler
     3 
     4 # 训练前的初始化
     5 optimizer = optim.Adam(net.parameters(), lr=0.001)
     6 scheduler = lr_scheduler.StepLR(optimizer, 10, 0.1)       # 每过10个epoch,学习率乘以0.1
     7 
     8 # 训练过程中
     9 for n in n_epoch:
    10     scheduler.step()
    11     ...

    可以随时查看学习率的值:optimizer.param_groups[0]['lr']

    还有其他:torch.optim.lr_scheduler 中提供了基于多种epoch数目调整学习率的方法。详见之前的博客:https://www.cnblogs.com/cxq1126/p/13289364.html#_label3

    7.冻结某些层的参数,使其参数在训练过程中不发生变化

    首先知道每一层的名字,这几层的grad都是True。

    1 net = Network()                    # 获取自定义网络结构
    2 for name, value in net.named_parameters():
    3     print('name: {0},	 grad: {1}'.format(name, value.requires_grad))

    定义一个要冻结的层列表:

    1 no_grad = [
    2     'cnn.VGG_16.convolution1_1.weight',
    3     'cnn.VGG_16.convolution1_1.bias',
    4     'cnn.VGG_16.convolution1_2.weight',
    5     'cnn.VGG_16.convolution1_2.bias'
    6 ]

    冻结方法如下:

    1 for name, value in net.named_parameters():
    2     if name in no_grad:
    3         value.requires_grad = False
    4     else:
    5         value.requires_grad = True

    前两层的weight和bias的requires_grad都为False,表示它们不可训练。最后在定义优化器时,只对requires_grad为True的层的参数进行更新。

    1 optimizer = optim.Adam(filter(lambda p: p.requires_grad, net.parameters()), lr=0.01)

    8.对不同层使用不同学习率

     1 net = Network()  # 获取自定义网络结构
     2 for name, value in net.named_parameters():
     3     print('name: {}'.format(name))
     4 
     5 #对 convolution1 和 convolution2 设置不同的学习率,首先将它们分开,即放到不同的列表里
     6 conv1_params = []
     7 conv2_params = []
     8 
     9 for name, parms in net.named_parameters():
    10     if "convolution1" in name:
    11         conv1_params += [parms]
    12     else:
    13         conv2_params += [parms]
    14 
    15 # 然后在优化器中进行如下操作:
    16 optimizer = optim.Adam(
    17     [
    18         {"params": conv1_params, 'lr': 0.01},
    19         {"params": conv2_params, 'lr': 0.001},
    20     ],
    21     weight_decay=1e-3,
    22 )

    9.网络参数初始化

    9.1pytorch内置的torch.nn.init方法。常用的初始化操作,例如正态分布、均匀分布、xavier初始化、kaiming初始化等都已经实现,可以直接使用。

    1 init.xavier_uniform(net1[0].weight)

    9.2自定义方法

    1 for layer in net1.modules():
    2     if isinstance(layer, nn.Linear): # 判断是否是线性层
    3         param_shape = layer.weight.shape
    4         layer.weight.data = torch.from_numpy(np.random.normal(0, 0.5, size=param_shape)) 
    5         # 定义为均值为 0,方差为 0.5 的正态分布

    10.加载内置预训练模型

    torchvision.models模块的子模块中包含以下模型:

    • AlexNet
    • VGG
    • ResNet
    • SqueezeNet
    • DenseNet

    导入模型方法:

    1 import torchvision.models as models
    2 resnet18 = models.resnet18(pretrained=True)
    3 alexnet = models.alexnet(pretrained=True)
    4 vgg16 = models.vgg16(pretrained=True)

    Tip:参数为pretrained,默认为False,表示只导入模型的结构,其中的权重是随机初始化的。如果pretrained 为 True,表示导入的是在ImageNet数据集上预训练的模型。

    其他Pytorch模型:https://zhuanlan.zhihu.com/p/73893187

    https://pytorch-cn.readthedocs.io/zh/latest/torchvision/torchvision-models/

  • 相关阅读:
    php中curl类常用方法封装和详解
    一个简单的PHP的CURL类
    PHP的curl常用的5个例子
    PHP封装CURL扩展
    马老师的WoTou生产消费线程讲解例子
    URL路径设置----第二章:创建和管理内容
    浅谈js设计模式之迭代器模式
    浅谈js设计模式之代理模式
    浅谈js设计模式之策略模式
    浅谈js设计模式之单例模式
  • 原文地址:https://www.cnblogs.com/cxq1126/p/13696082.html
Copyright © 2011-2022 走看看