当前位置: 首页 > news >正文

Pytorch混合精度(FP16FP32)(AMP自动混合精度)/半精度 训练(一) —— 原理(torch.half)

我们定义一个tensor默认都是FP32的,即单精度,single

fp16是半精度,half;fp64是双精度, double

AMP自动混合精度

      一般用自动混合精度(AMP, Automatic mixed precision),用半精度可能对acc的影响较大

       混合精度的performance也要看网络,有些网络的提升不大,有些网络会影响acc

      AMP自动混合精度,可以在神经网络推理过程中,针对不同的层,采用不同的数据精度进行计算,从而实现节省显存和加快速度的目的。在Pytorch 1.5版本及以前,通过NVIDIA提供的apex库可以实现amp功能。但是在使用过程中会伴随着一些版本兼容和奇怪的报错问题。从1.6版本开始,Pytorch原生支持自动混合精度训练(torch.cuda.amp),并已进入稳定阶段,AMP 训练能在 Tensor Core GPU 上实现更高的性能并节省多达 50% 的内存。

原理

       当前Pytorch的默认存储数据类型是整数INT64(8字节),浮点数FP32(4字节),PyTorch Tensor的默认类型为单精度浮点数FP32。随着模型越来越大,加速训练模型的需求就产生了。在深度学习模型中使用FP32主要存在几个问题,第一模型尺寸大,训练的时候对显卡的显存要求高;第二模型训练速度慢;第三模型推理速度慢。其解决方案就是使用低精度计算对模型进行优化。

      精度减半(FP32→ FP16) ,训练时间减半。与单精度浮点数float32(32bit,4个字节)相比,半精度浮点数float16仅有16bit,2个字节组成。可以很明显的看到,使用FP16可以解决或者缓解上面FP32的两个问题:显存占用更少:通用的模型FP16占用的内存只需原来的一半,训练的时候可以使用更大的batchsize。计算速度更快:有论文指出半精度的计算吞吐量可以是单精度的 2-8 倍。

      自动混合精度训练的精髓在于“在内存中用FP16进行tensor储存和做乘法从而加速计算,用FP32做累加避免舍入误差”。混合精度训练的策略有效地缓解了舍入误差的问题。从而加快速度,减少内存占用。缺陷是只能在支持FP16操作的一些特定类型的显卡上面使用; 而且依然会存在溢出误差和舍入误差。

        FP16就是torch.half

     NVIDIA GPU 使用 float16 执行运算的速度比使用 float32 快当前很多NVIDIA GPU搭载了专门为快速FP16矩阵运算设计的特殊用途Tensor Core,比如Tesla P100,Tesla V100、Tesla A100、GTX 20XX 和RTX 30XX等。Tensor Core是一种矩阵乘累加的计算单元,每个Tensor Core每个时钟执行64个浮点混合精度操作(FP16矩阵相乘和FP32累加),英伟达宣称使用Tensor Core进行矩阵运算可以轻易的提速,同时降低一半的显存访问和存储。随着Tensor Core的普及FP16计算也一步步走向成熟,低精度计算也是未来深度学习的一个重要趋势。

      动态损失放大,是为了解决使用了混合精度训练,还是会存在无法收敛的情况。因为激活梯度的值太小,造成了下溢出(Underflow)。损失放大的思路是:

具体做法

上面说过,自动混合精度训练的精髓在于“在内存中用FP16进行tensor储存和做乘法从而加速计算,用FP32做累加避免舍入误差”。

那么,从FP32转FP16容易,但是从FP16可就没法转回FP32了,就有精度损失了,所以需要进行FP32的权重备份,即weights, activations, gradients 等数据在训练中都利用FP16来存储,同时拷贝一份FP32的weights,用于更新。

 

因为

这样不会使得显存占用增大,因为大头activations是用FP16存的

用FP32做累加的意思是,2个FP16的值累加,产生的结果用FP32存,然后再转为FP16

并不需要两个FP16先转为FP32

实验 

      硬件使用NVIDIA Geforce RTX 3070作为测试卡,这块卡有184个Tensor Core,能比较好的支持amp模式。模型使用ERFNet分割模型作为基准,cityscapes作为测试数据,10个epoch下的测试效果如下所示:

      在模型的训练性能方面,amp模式下的平均训练时间并没有明显节省,甚至还略低于正常模式。显存的占用大约节省了25%,对于需要大量显存的模型来说这个提升还是相当可观的。理论上训练速度应该也是有提升的,到Pytorch的GitHub issue里翻了一下,好像30系显卡会存在速度提不上来的问题,不太清楚是驱动支持不到位还是软件适配不到位。

 在模型的精度方面,在不进行数据shuffle的情况下统计了10个epoch下两种模式的train_lossval_acc,可以看出不管是训练还是推理,amp模式并没有带来明显的精度损失。


 

相关文章:

  • CUDA编程(一) —— 相关概念基础知识
  • CUDA编程(二) —— CUDA编程模型
  • Python Fastai框架
  • ubuntu安装docker
  • Linux(ubuntu)(十三) —— (系统)服务管理 (systemctlservicechkconfig)服务的运行级别(Runlevel)
  • linux 文件/目录名 颜色
  • nvcc(CUDA编译器)
  • docker使用GPU(nvidia-docker)
  • Pytorch分布式训练/多卡训练(二) —— Data Parallel并行(DDP)(2.3)(torch.multiprocessing(spawn) Apex)
  • OpenStack
  • Python logging日志模块
  • CUDA编程(三) —— 编程实践
  • Python函数传参(*星号)
  • Python调用函数带括号和不带括号的区别
  • Microsoft CMT 系统
  • [译]前端离线指南(上)
  • 「前端」从UglifyJSPlugin强制开启css压缩探究webpack插件运行机制
  • Docker 笔记(1):介绍、镜像、容器及其基本操作
  • extjs4学习之配置
  • HTTP传输编码增加了传输量,只为解决这一个问题 | 实用 HTTP
  • js正则,这点儿就够用了
  • mysql常用命令汇总
  • Shell编程
  • v-if和v-for连用出现的问题
  • Vue官网教程学习过程中值得记录的一些事情
  • Zepto.js源码学习之二
  • 闭包,sync使用细节
  • 从零开始的webpack生活-0x009:FilesLoader装载文件
  • 技术:超级实用的电脑小技巧
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 微服务核心架构梳理
  • 原生 js 实现移动端 Touch 滑动反弹
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • Prometheus VS InfluxDB
  • ​ubuntu下安装kvm虚拟机
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • # 计算机视觉入门
  • #我与Java虚拟机的故事#连载01:人在JVM,身不由己
  • (4)logging(日志模块)
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (接口封装)
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (四) 虚拟摄像头vivi体验
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .NET Framework 的 bug?try-catch-when 中如果 when 语句抛出异常,程序将彻底崩溃
  • .net refrector
  • .NET/C# 推荐一个我设计的缓存类型(适合缓存反射等耗性能的操作,附用法)
  • .NET开源项目介绍及资源推荐:数据持久层
  • .Net中wcf服务生成及调用
  • [.net] 如何在mail的加入正文显示图片
  • [1127]图形打印 sdutOJ
  • [BZOJ]4817: [Sdoi2017]树点涂色
  • [C#] 如何调用Python脚本程序