浅尝Pytorch自动混合精度AMP

本文介绍了Pytorch中的自动混合精度(AMP)功能,包括浮点数的概念、半精度和单精度的区别以及在深度学习中的应用。通过例子展示了半精度可能导致的上溢和下溢问题,阐述了AMP如何解决这些问题,提升计算效率并减少显存占用。文章还讨论了梯度缩放和相关装饰器的使用,以及在多GPU和多模型、Losses、优化器情况下的处理方式。
摘要由CSDN通过智能技术生成

浅尝Pytorch自动混合精度

本文是《AUTOMATIC MIXED PRECISION PACKAGE - TORCH.CUDA.AMP》一文的简单学习,所以有些语句有些翻译腔还请各位谅解。本文主要内容为Pytorch的混合精度功能。

先说个题外话,以前我训练模型的时候,尝鲜AMP都是用的Nvidia开源的 APEX 包,这个包里面有个混合精度(AMP)功能,当时堪称训练神器~

关于这个包的故事就不多说了,后来Facebook官方将这个好用的AMP功能加到Pytorch里面去了,成为了原生功能。今天我正好学习一下这个神奇的功能是怎么使用的。

从浮点数说起

说起浮点数,大家肯定很熟悉,我们编程过程中最常用的数据类型之一就是浮点数了,英文名 Float。一般而言我们用浮点数来表示一个小数,比如 0.4。

在Python里面我们直接赋值

In[1] n = 0.4
In[2] print(type(n))
<class 'float'>

实际上,0.4 在二进制上是一个无限循环的数字:0.0110 0110 0110 0110 …
换句话说,0.4 的二进制表示为 0.4 = 0 × 2 − 1 + 1 × 2 − 2 + 1 × 2 − 3 + 0 × 2 − 4 ⋯ 0.4=0\times2^{-1}+1\times2^{-2}+1\times2^{-3}+0\times2^{-4}\cdots 0.4=0×21+1×22+1×23+0×24这是一个无穷级数,越往后我们对0.4的表示就越精确。

后来,IEEE制定了 IEEE 754 标准,规定了浮点数的表示方法。这里我们不深究这个标准的制定规则。就简单拿0.4举个例子,如果我们规定它是一个32位浮点数,那么一般来说它会占用4个字节。根据 IEEE 754 标准,这32位如下图:
32位浮点数
它由三部分组成:
在这里插入图片描述

符号位:(第31位)值为0,说明是正数。
指数位:(第 30-23位)01111101
这里指数是-2+127,其中127是偏移量,至于为啥可以看这里
尾数:(第22-0位)10011001100110011001101

0.4 的二进制是
0.0110 0110 0110 0110 0110 0110 0110 0110 …
根据IEEE 754,首先移动小数点(向左或向右),保证整数部分只有一位非零的1(浮点的来历,对0.4就是小数点向右移动两位):

1.100110011001100110011001100110 …

  • 因为移动了两位,所以指数就是-2
  • 尾数就是取小数点后面23位。

这里我们称这个32位的浮点数为单精度浮点数。同理还有一种double数据类型,就是截取了更长的小数到64位,也就是传说中的双精度浮点数~

以此类推,如果是半精度浮点数,就是16位,也是本文后面的主角之一。

深度学习中的浮点数

现在我们会简单比较一下 FP32FP16
单精度浮点数
半精度浮点数
很明显 float32 的能表示的数字范围远大于 float16 ,但是 float16 也有其优点。在NVIDIA官方基于 V100 的测试里,在 Tensor Core 运算中:

  • float16 计算吞吐量是 float32 的8倍
  • float16 内存吞吐量是 float32 的2倍
  • float16 只占用一半显存

这就是我们为啥想使用FP16,主要是因为穷。当然我们也不能无脑使用半精度,我们以下面两个例子来说明。

例1-上溢

我们现在进一步比较一下两者区别:

a = torch.cuda.HalfTensor(4096)
a.fill_(16.0)
print(a.sum())

b = torch.cuda.FloatTensor(4096)
b.fill_(16.0)
print(b.sum())

这段代码的作用是创造两个长度为4096的张量,唯一的区别就是前者是半精度张量而后者是单精度张量。

结果,半精度张量的a,其 sum 结果为 inf,而单精度张量的b,其 sum 结果为tensor(65536, device='cuda') 。这个例子说明了其最大动态范围的区别。

例2-下溢

param = torch.cuda.HalfTensor([1.0])
update = torch.cuda.HalfTensor([.0001])
print(param + update)

param 
  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值