分布式训练之AMP混合精度训练面试题
《分布式训练之AMP混合精度训练面试题》共 15 页、0.4 万字,通篇围绕 CUDA、上下文、GPU、显存 展开,归在「训练、微调与数据」这一层。
适合要自己训模型、或者判断这一版该不该训的人
目录骨架(2 节)
- 设置随机数种子,保证实验可重现
- 'weight_decay':0.0 }
原 PDF 已逐页还原成图,共 15 页,这里先放前 3 页。右侧文字由 OCR 按版面重排,可能有个别错字,以图为准;点图可全屏放大。

为什么需要 AMP 混合精度训练? …
为什么需要 AMP 混合精度训练? PyTorch 1.6 版本今天发布了,带来的最大更新就是自动混合精度。release 说明的标题是: Stable release of automatic mixed precision (AMP). New Beta features include a TensorPipe backend for RPC, memory profiler, and several improvements to distributed training for both RPC and DDP.
- 可见自动混合精度正是 PyTorch 1.6 的最大更新。这就带来了几个问题:
- 什么是自动混合精度训练?
- 为什么需要自动混合精度?
- 如何在 PyTorch 中使用自动混合精度? 一、什么是自动混合精度训练(AMP) 我们知道神经网络框架的计算核心是 Tensor,也就是那个从 scaler -> array-> matrix -> tensor 维度一路丰富过来 的 tensor。在 PyTorch 中,我们可以这样创建一个 Tensor:
>> import torch
>> gemfield = torch. zeros (70, 30) >>> gemfield. type ( 'torch. FloatTensor'
>> syszux = torch. Tensor ([ 1, 2 ]) >>> syszux.type () 'torch. FloatTensor’ 可以看到默认创建的 tensor 都是 FloatTensor 类型。而在 PyTorch 中,一共有 10 种类型的 tensor:
- torch.Floatlensor (32-bit floating point)
- torch. DoubleTensor (64-bit floating point)
- torch.HalfTensor (16-bit floating point 1)
- torch.BFloat16Tensor (16-bit floating point 2)
- torch.Byte Tensor (8-bit integer (unsigned))
- torch.Charlensor (8-bit integer (signed))
- torch.ShortTensor (16-bit integer (signed))
- torch.IntTensor (32-bit integer (signed))
- torch.Long Tensor (64-bit integer (signed))
- torch.BoolTensor (Boolean)
由此可见,默认的 Tensor 是 32-bit floating point,这就是 32 位浮点型精度的 Tensor。 自动混合精度的关键词有两个:自动、混合精度。这是由 PyTorch 1.6 的 torch.cuda.amp 模块带来的:
from torch.cuda.amp import autocast as autocast
混合精度预示着有不止一种精度的 Tensor,那在 PyTorch 的 AMP 模块里是几种呢?2 种:torch.FloatTensor 和
torch.HalfTensor;

自动预示着 Tensor 的 dty…
自动预示着 Tensor 的 dtype 类型会自动变化,也就是框架按需自动调整 tensor 的 dtype (其实不是完全自动,有些 地方还是需要手工干预); torch.cuda.amp 的名字意味着这个功能只能在 cuda 上使用,事实上,这个功能正是 NVIDIA 的开发人员贡献到 PyTorch 项目中的。而只有支持 Tensor core 的 CUDA 硬件才能享受到 AMP 的好处(比如 2080t 显卡)。Tensor Core 是一种矩阵乘累加的计算单元,每个 Tensor Core 每个时钟执行 64 个浮点混合精度操作(FP16 矩阵相乘和 FP32 累加),英伟达宣称使用 Tensor Core 进行矩阵运算可以轻易的提速,同时降低一半的显存访问和存储。 因此,在 PyTorch 中,当我们提到自动混合精度训练,我们说的就是在 NVIDIA 的支持 Tensor core 的 CUDA 设备上 使用 torch.cuda.amp.autocast (以及 torch.cuda.amp.GradScaler)来进行训练。咦?为什么还要有 torch.cuda.amp.GradScaler?
二,为什么需要自动混合精度? 这个问题其实暗含着这样的意思:为什么需要自动混合精度,也就是 torch.FloatTensor 和 torch.HalfTensor 的混 合,而不全是 torch.FloatTensor?或者全是 torch.HalfTensor? 如果非要以这种方式问,那么答案只能是,在某些上下文中 torch.FloatTensor 有优势,在某些上下文中 torch.HalfTensor 有优势呗。答案进一步可以转化为,相比于之前的默认的 torch.FloatTensor, torch.HalfTensor 有时具有优势,有时劣势不可忽视。 torch. HalfTensor 的优势就是存储小、计算快、更好的利用 CUDA 设备的 Tensor Core。因此训练的时候可以減少 显存的占用(可以增加 batchsize 了),同时训练速度更快; torch.HalfTensor 的劣势就是:数值范围小(更容易 Overflow / Underflow)、舍入误差(Rounding Error,导致 一些微小的梯度信息达不到 16bit 精度的最低分辦率,从而丢失)。 可见,当有优势的时候就用 torch.HalfTensor,而为了消除 torch.HalfTensor 的劣势,我们带来了两种解决方案: 1. 梯度 scale,这正是上一小节中提到的 torch.cuda.amp.GradScaler,通过放大 loss 的值来防止梯度的 underflow (这只是 BP 的时候传递梯度信息使用,真正更新权重的时候还是要把放大的梯度再 unscale 回
- 回落到 torch.FloatTensor,这就是混合一词的由来。那怎么知道什么时候用 torch.FloatTensor,什么时候用半 精度浮点型呢?这是 PyTorch 框架决定的,在 PyTorch 1.6 的 AMP 上下文中,如下操作中 tensor 会被自动转化 为半精度浮点型的 torch.HalfTensor: matmul addbmm addmm addmv addr baddbmm bmm chain matmul convld conv2d conv3d
conv_transposeld conv_transpose2d
conv_transpose3d linear matmul
prelu

三,混合精度训练的优点是什么?
parameter cast (1loat16) forward compute activation
backward propagation (1loat16)
cast (float16 to float32)
activation_grad/weight_grad (float32) parameter parameter parameter update (float32)
- 三,混合精度训练的优点是什么?
- 减少显存
- 占用加快训练速度:通信量
- 減半;计算性能翻倍。 四、混合精度训练的缺点是什么?
- 数据溢出
- 五、混合精度训练的关键技术是什么?
- float32 主权重备份
- 动态损失缩放 六.介绍一下混合精度训练动态损失缩放?
- 介绍:即损失标度。这会将梯度也放大 1024 倍,大大降只需要将损失乘以某个大数字(如 1024),低了梯度发 生下溢的几率。计算出梯度后,只需将其除以 1024 就可以得到准确值。
- 动态选择损失标度介绍:发生溢出,跳过优化器更新,损失标度减半;连续 N 个 steps 没有发生溢出,损失标 度翻倍
loss_scale
七、如何在 PyTorch 中使用自动混合精度? 答案就是 autocast + GradScaler。 1. autocast 正如前文所说,需要使用 torch.cuda.amp 模块中的 autocast 类。使用也是非常简单的: torch.cuda.amp import autocast autocast
#创建 model,默认是 torch. FloatTensor model = Net ().cuda () optimizer = optim. SGD (model.parameters (),..)
activation
parameter/activation (foat16)
(float16)
