thorough-pytorch-main-task2

7 篇文章 0 订阅

task2 PyTorch进阶

(Datawhale35期组队学习)

1基础点

  • 自定义损失函数
    • 函数定义
    • 类定义
  • 动态调整学习率
    • 官方scheduler
    • 自定义scheduler
  • 模型微调
    • 流程
    • 使用已有模型
    • 训练特定层
  • 半精度训练
    • 半精度训练设置

2具体内容

2.1 自定义损失函数

PyTorch在torch.nn模块提供了常用的损失函数。

2.1.1 函数定义
def my_loss(output, target):
  loss = torch.mean((output - target)**2)
  return loss
2.1.2 类定义

Loss 函数部分继承自 _loss , 部分继承自 _WeightedLoss ,
而 _WeightedLoss 继承自 _loss , _loss 继承自 nn.Module。

  • Dice Loss
    在这里插入图片描述
  • BCE-Dice Loss,Jaccard/Intersection over Union (IoU) Loss,Focal Loss…
  • 涉及数学运算,PyTorch提供张量计算接口

2.2 动态调整学习率

  • 学习率
    • 过小降低收敛速度,增加训练时间
    • 过大参数在最优解两侧来回振荡
  • 适当的学习率衰减策略
2.2.1官方scheduler
  • torch.optim.lr_scheduler
    • lr_scheduler.LambdaLR
    • lr_scheduler.MultiplicativeLR
    • lr_scheduler.StepLR
    • lr_scheduler.MultiStepLR
    • lr_scheduler.ExponentialLR
    • lr_scheduler.CosineAnnealingLR
    • lr_scheduler.ReduceLROnPlateau
    • lr_scheduler.CyclicLR
    • lr_scheduler.OneCycleLR
    • lr_scheduler.CosineAnneaLingWarmRestarts
      使用:
# 选择一种优化器
optimizer = torch.optim.Adam(...)
# 选择上面提到的一种或多种动态调整学习率的方法
scheduler1 = torch.optim.lr_scheduler....
scheduler2 = torch.optim.lr_scheduler....
...
schedulern = torch.optim.lr_scheduler....
# 进行训练
for epoch in range(100):
  train(...)
  validate(...)
  optimizer.step()
  # 需要在优化器参数更新之后再动态调整学习率
scheduler1.step()
...
schedulern.step()

用torch.optim.lr_scheduler 时,需要将 scheduler.step() 放在
optimizer.step() 后面进行使用

2.2.2 自定义scheduler
  • 自定义函数 adjust_learning_rate 来改变 param_group 中 lr 的值
def adjust_learning_rate(optimizer, epoch):
  lr = args.lr * (0.1 ** (epoch // 30))
  for param_group in optimizer.param_groups:
    param_group['lr'] = lr

有了 adjust_learning_rate 函数的定义,在训练的过程就可以调用我们的函数来实现学习率的动态变化

def adjust_learning_rate(optimizer,...):
 ...
optimizer = torch.optim.SGD(model.parameters(),lr = args.lr,momentum = 0.9)
for epoch in range(10):
  train(...)
  validate(...)
  adjust_learning_rate(optimizer,epoch)

2.3 模型微调

  • 越大的模型对数据量需求越大,过拟合无法避免
    • 收集更多的数据
    • 应用迁移学习transfer learning,将从源数据集学到的知识迁移到目标数据集
    • 模型微调finetune
2.3.1流程
  • 源数据集上预训练一个NN,源模型
  • 创建一个新NN,目标模型
  • 为目标模型添加一个输出大小为目标数据集类别个数的输出层,随机初始化该层模型参数
  • 在目标数据集上训练目标模型。我们将从头训练输出层,而其余层的参数都是基于源模型的参数微
    调得到的
    在这里插入图片描述
2.3.2使用已有模型
  • 实例化网络
import torchvision.models as models
resnet18 = models.resnet18()
# resnet18 = models.resnet18(pretrained=False) 等价于与上面的表达式
alexnet = models.alexnet()
vgg16 = models.vgg16()
squeezenet = models.squeezenet1_0()
densenet = models.densenet161()
inception = models.inception_v3()
googlenet = models.googlenet()
shufflenet = models.shufflenet_v2_x1_0()
mobilenet_v2 = models.mobilenet_v2()
mobilenet_v3_large = models.mobilenet_v3_large()
mobilenet_v3_small = models.mobilenet_v3_small()
resnext50_32x4d = models.resnext50_32x4d()
wide_resnet50_2 = models.wide_resnet50_2()
mnasnet = models.mnasnet1_0()
  • 传递 pretrained 参数

通过 True 或者 False 来决定是否使用预训练好的权重,在默认状态下 pretrained = False ,意味着
我们不使用预训练得到的权重,当 pretrained = True ,意味着我们将使用在一些数据集上预训练得
到的权重

import torchvision.models as models
resnet18 = models.resnet18(pretrained=True)
alexnet = models.alexnet(pretrained=True)
squeezenet = models.squeezenet1_0(pretrained=True)
vgg16 = models.vgg16(pretrained=True)
densenet = models.densenet161(pretrained=True)
inception = models.inception_v3(pretrained=True)
googlenet = models.googlenet(pretrained=True)
shufflenet = models.shufflenet_v2_x1_0(pretrained=True)
mobilenet_v2 = models.mobilenet_v2(pretrained=True)
mobilenet_v3_large = models.mobilenet_v3_large(pretrained=True)
mobilenet_v3_small = models.mobilenet_v3_small(pretrained=True)
resnext50_32x4d = models.resnext50_32x4d(pretrained=True)
wide_resnet50_2 = models.wide_resnet50_2(pretrained=True)
mnasnet = models.mnasnet1_0(pretrained=True)

注意:

  1. 通常PyTorch模型的扩展为 .pt 或 .pth ,程序运行时会首先检查默认路径中是否有已经下载的模型权重,一旦权重被下载,下次加载就不需要下载
  2. 一般情况下预训练模型的下载会比较慢,我们可以直接通过迅雷或者其他方式去 这里 查看自己的模型里面 model_urls ,然后手动下载,预训练模型的权重在 Linux 和 Mac 的默认下载路径是用户根目录下的 .cache 文件夹。在 Windows 下就是 C:\Users
    .cache\torch\hub\checkpoint 。我们可以通过使用torch.utils.model_zoo.load_url() 设置权重的下载地址
  3. 将自己的权重下载下来放到同文件夹下,然后再将参数加载网络
self.model = models.resnet50(pretrained=False)
self.model.load_state_dict(torch.load('./model/resnet50-19c8e357.pth'))
  1. 中途强行停止下载的话,一定要去对应路径下将权重文件删除干净,要不然可能会报错
2.3.3训练特定层
  • 默认参数的属性 .requires_grad = True
  • 正在提取特征并且只想为新初始化的层计算梯度,其他参数不进行改变。需要通过设置 requires_grad = False 来冻结部分层
def set_parameter_requires_grad(model, feature_extracting):
  if feature_extracting:
    for param in model.parameters():
      param.requires_grad = False
  • 仅改变最后一层的模型参数,不改变特征提取的模型参数
  • 先冻结模型参数的梯度,再对模型输出部分的全连接层进行修改,这样修改后的全连接层的参数就是可计算梯度
import torchvision.models as models
# 冻结参数的梯度
feature_extract = True
model = models.resnet18(pretrained=True)
set_parameter_requires_grad(model, feature_extract)
# 修改模型
num_ftrs = model.fc.in_features
model.fc = nn.Linear(in_features=512, out_features=4, bias=True)
  • 在训练过程中,model仍会进行梯度回传,但是参数更新则只会发生在fc层。
  • 设定参数的requires_grad属性,完成了指定训练模型的特定层的目标,这对实现模型微调非常重要

2.4 半精度训练

GPU:算力(显卡计算的速度)+显存(显卡可以同时放入多少数据用于计算)

  • 采用torch.float32,可以只保留一般信息,“半精度”,减少显存
    在这里插入图片描述
2.4.1半精度训练设置
  • import autocast
from torch.cuda.amp import autocast
  • 模型设置:使用python的装饰器方法,用autocast装饰模型中的forward函数
@autocast() 
def forward(self, x):
 ...
  return x
  • 训练过程:在将数据输入模型及其之后的部分放入“with autocast():
for x in train_loader:
x = x.cuda()
with autocast():
    output = model(x)
   ...

注意:

  • 半精度训练主要适用于数据本身的size比较大(比如说3D图像、视频等)
  • 当数据本身的size并不大时(比如手写数字MNIST数据集的图片尺寸只有28*28),使用半精度训练则可能不会带来显著的提升

3参考

  • https://github.com/datawhalechina/thorough-pytorch
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值