• [Pytorch]基于混和精度的模型加速


    这篇博客是在pytorch中基于apex使用混合精度加速的一个偏工程的描述,原理层面的解释并不是这篇博客的目的,不过在参考部分提供了非常有价值的资料,可以进一步研究。

    一个关键原则:“仅仅在权重更新的时候使用fp32,耗时的前向和后向运算都使用fp16”。其中的一个技巧是:在反向计算开始前,将dloss乘上一个scale,人为变大;权重更新前,除去scale,恢复正常值。目的是为了减小激活gradient下溢出的风险。

    apex是nvidia的一个pytorch扩展,用于支持混合精度训练和分布式训练。在之前的博客中,神经网络的Low-Memory技术梳理了一些low-memory技术,其中提到半精度,比如fp16。apex中混合精度训练可以通过简单的方式开启自动化实现,组里同学交流的结果是:一般情况下,自动混合精度训练的效果不如手动修改。分布式训练中,有社区同学心心念念的syncbn的支持。关于syncbn,在去年做CV的时候,我们就有一些来自民间的尝试,不过具体提升还是要考虑具体任务场景。

    那么问题来了,如何在pytorch中使用fp16混合精度训练呢?

    第零:混合精度训练相关的参数

    parser.add_argument('--fp16',
                            action='store_true',
                            help="Whether to use 16-bit float precision instead of 32-bit")
    parser.add_argument('--loss_scale',
                            type=float, default=0,
                            help="Loss scaling to improve fp16 numeric stability. Only used when fp16 set to True.
    "
                                 "0 (default value): dynamic loss scaling.
    "
                                 "Positive power of 2: static loss scaling value.
    ")
    

    第一:模型参数转换为fp16

    nn.Module中的half()方法将模型中的float32转化为float16,实现的原理是遍历所有tensor,而float32和float16都是tensor的属性。也就是说,一行代码解决,如下:

    model.half()
    

    第二:修改优化器

    在pytorch下,当使用fp16时,需要修改optimizer。类似代码如下(代码参考这里):

    # Prepare optimizer
        if args.do_train:
            param_optimizer = list(model.named_parameters())
            no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']
            optimizer_grouped_parameters = [
                {'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.01},
                {'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
                ]
            if args.fp16:
                try:
                    from apex.optimizers import FP16_Optimizer
                    from apex.optimizers import FusedAdam
                except ImportError:
                    raise ImportError("Please install apex from https://www.github.com/nvidia/apex to use distributed and fp16 training.")
    
                optimizer = FusedAdam(optimizer_grouped_parameters,
                                      lr=args.learning_rate,
                                      bias_correction=False,
                                      max_grad_norm=1.0)
                if args.loss_scale == 0:
                    optimizer = FP16_Optimizer(optimizer, dynamic_loss_scale=True)
                else:
                    optimizer = FP16_Optimizer(optimizer, static_loss_scale=args.loss_scale)
                warmup_linear = WarmupLinearSchedule(warmup=args.warmup_proportion,
                                                     t_total=num_train_optimization_steps)
    
            else:
                optimizer = BertAdam(optimizer_grouped_parameters,
                                     lr=args.learning_rate,
                                     warmup=args.warmup_proportion,
                                     t_total=num_train_optimization_steps)		
    

    第三:backward时做对应修改

     if args.fp16:
     	optimizer.backward(loss)
     else:
          loss.backward()
    

    第四:学习率修改

    if args.fp16:
          # modify learning rate with special warm up BERT uses
          # if args.fp16 is False, BertAdam is used that handles this automatically
         lr_this_step = args.learning_rate * warmup_linear.get_lr(global_step, args.warmup_proportion)
         for param_group in optimizer.param_groups:
                param_group['lr'] = lr_this_step
         optimizer.step()
         optimizer.zero_grad()
    

    根据参考3,值得重述一些重要结论:

    (1)深度学习训练使用16bit表示/运算正逐渐成为主流。

    (2)低精度带来了性能、功耗优势,但需要解决量化误差(溢出、舍入)。

    (3)常见的避免量化误差的方法:为权重保持高精度(fp32)备份;损失放大,避免梯度的下溢出;一些特殊层(如BatchNorm)仍使用fp32运算。

    参考资料:

    1.nv官方repo给了一些基于pytorch的apex加速的实现

    实现是基于fairseq实现的,可以直接对比代码1-apex版代码2-非apex版(fairseq官方版),了解是如何基于apex实现加速的。

    2.nv官方关于混合精度优化的原理介绍

    按图索骥,可以get到很多更加具体地内容。

    3.低精度表示用于深度学习 训练与推断

    感谢团队同学推荐。

  • 相关阅读:
    关于Jonathan S. Weissman与RIT(罗切斯特理工学院,位于纽约)
    jQuery获取元素值以及设置元素值总结
    页面跳转
    Node JS复制文件
    js获取当前日期并格式yyy-MM-dd
    Json文件删除元素
    HTML页面间传值
    计算机实用但冷门快捷键
    NodejS---require的机制
    Node某个JS导出方法变量以及在其他地方引用的例子
  • 原文地址:https://www.cnblogs.com/jfdwd/p/11238834.html
Copyright © 2020-2023  润新知