翻译至原文链接:https://devblogs.nvidia.com/mixed-precision-training-deep-neural-networks/

                             Mixed-Precision Training of Deep Neural Networks

mxnet 官方文档实现:https://beta.mxnet.io/guide/performance/compression/float16.html 

                                    https://mxnet.apache.org/api/faq/float16

深度神经网络的混合精度训练:

 

深度神经网络(DNN)在许多领域都取得了突破,包括图像处理和理解,语言建模,语言翻译,语音处理,游戏策略以及许多其他领域。 为了获得这些卓越结果,DNN的复杂性一直在增加,这反过来又增加了训练这些网络所需的计算资源。 混合精度训练通过使用低精度算术降低了所需的资源,具有以下好处。

 

减少所需的内存量。 半精度浮点格式(FP16)使用16位,而单精度(FP32)使用32位。 降低所需的内存可以训练更大的模型或训练时使用更大的batch size。

缩短训练或推理时间。计算的次数或者数据存储的存储十分影响算法的执行时间。半精度使用单精度的一半内存访问,从而降低了在存储层方面所花费的时间。 与单精度相比,NVIDIA GPU的半精度算术吞吐量最多提高了8倍,从而加快了数学受限层的速度。

fp16训练(混合精度训练)

由于DNN训练传统上是依靠(根据)IEEE单精度格式,因此本文的重点是半精度训练,同时保持以单精度实现的网络精度(acc)(如图1所示)。 这种技术称为混合精度训练,因为它同时使用了单精度和半精度表示形式。

 

混合精度训练成功的技巧(方法)

半精度浮点格式由1个符号位,5个指数位和10个小数位组成。 支持的指数值在[-24,15]范围内,这意味着格式支持[2^-24,65,504]范围内的非零值范围。 由于此范围比单精度格式支持的[2^-149,〜3.4×10^38]范围窄,因此训练某些网络需要额外考虑。

 本节描述了三种成功地以半精度成功训练DNN的技术:

  1. 将FP16产品累积到FP32中;将FP16产品累积到FP32中。
  2. 损失缩放
  3. FP32重量主副本(就是copy权重)。

借助这些技术,NVIDIA和百度研究院能够为所有经过训练的网络(混合精度训练)达到单精度结果准确性。请注意,并非所有网络都需要使用所有这些技术进行训练。

有关如何在各种框架(包括可用的代码示例)中应用这些技术的详细说明,请参阅Training with Mixed Precision User Guide.

 

    1.累加到FP32

NVIDIA Volta GPU架构引入了Tensor Core指令,该指令将半精度矩阵相乘,将结果累加为单精度或半精度输出。 我们发现累积成单精度对于获得良好的训练结果至关重要。 写入存储器之前,累计值将转换为半精度。 cuDNN和CUBLAS库提供了各种依赖Tensor Core进行算术运算的函数。

(大概意思就是:矩阵相乘用半精度相乘,结果求和(累计)的时候用单精度,减少在累计的时候造成误差的叠加,最后累计的结果再转成半精度写入内存。)

 

    2.损失缩放(Loss Scaling)

训练DNN时会遇到四种类型的张量:**,**梯度,权重和权重梯度。根据我们的经验,**,权重和权重梯度落在以半精度表示的值幅度范围内。但是,对于某些网络,小幅度的**梯度低于半精度范围。例如,考虑图2中训练Multibox SSD检测网络时遇到的**梯度直方图,该图显示了log2标度上的值百分比。小于2^-24的值以半精度格式变为零。

 

请注意,**梯度不使用大部分的半精度范围,**梯度往往是较小的值,其幅度低于1。因此,我们可以通过将它们乘以比例因子S来将其“移动”到FP16可表示的范围内。对于SSD网络,将梯度乘以8就足够了。这表明幅度小于2^-27的**梯度值与该网络的训练无关,而将(2^-27,2^-24)范围内的值保留则很重要。

fp16训练(混合精度训练)

 

确保梯度落入半精度表示的范围内的一种非常有效的方法是将训练损失乘以比例因子。 这仅增加了一个乘法,并通过链式规则确保了所有梯度均按比例放大(或上移),而无需花费额外费用。 损失缩放尺度(Loss scaling)可确保恢复丢失为零的相关梯度值。 在权重更新之前,权重梯度需要缩小相同的因子S。 缩小操作可以与权重更新本身融合在一起(不会导致额外的内存访问),也可以单独执行。 有关更多详细信息,请参阅 Training with Mixed Precision User Guide 和 Mixed-Precision Training论文。

 

    3. FP32 Master Copy of Weights(将fp32的主要权重复制)

DNN训练的每次迭代都通过添加相应的权重梯度来更新网络权重。权重梯度的大小通常远小于相应的权重,尤其是在乘以学习率(或针对诸如Adam或Adagrad的优化程序的自适应计算因子)之后。如果加数之一太小而无法在半精度表示中产生差异,则此大小差异可能导致不进行更新(例如,由于指数差异较大,较小的加数在移位以对齐二进制点后变为零)。

 

对于以这种方式丢失更新的网络,一种简单的补救方法是以单精度维护和更新权重的主副本。在每次迭代中,将制作一个半精度的主权重副本,并将其用于正向和反向传播,从而获得性能优势。在权重更新期间,将计算出的权重梯度转换为单精度并用于更新主副本,然后在下一次迭代中重复该过程。因此,我们仅在需要时才将半精度存储与单精度存储混合在一起。

 

混合精度训练迭代

 

上面介绍的三种技术可以结合到每个训练迭代的以下步骤序列中。 传统迭代过程的补充内容以粗体显示。

  1. 制作砝码的FP16副本
  2. 使用FP16权重和**进行正向传播
  3. 将产生的损耗乘以比例因子S
  4. 使用FP16权重,**及其梯度向后传播
  5. 重量梯度乘以1 / S
  6. (可选)处理权重梯度(梯度削波,权重衰减等)
  7. 在FP32中更新权重的主副本

有关如何在各种DNN训练框架的脚本中添加混合精度训练步骤的示例,请参见 Training with Mixed Precision User Guide

 

 

实验结果:

 

我们在各种卷积,递归和生成DNN上使用了上述三种混合精度训练技术。应用包括包括图像分类,对象检测,图像生成,语言建模,语音处理和语言翻译。有关完整的实验详细信息,请参阅《混合精度训练》( Mixed-Precision Training )论文。表1显示了使用各种DNN模型进行图像分类的结果。表1中的任何网络都不需要进行损耗定标以匹配单精度结果精度。表2显示了对象检测网络的平均平均精度。 Multibox SSD训练需要损耗缩放,并且缩放因子8足以匹配单精度训练。没有这个比例因子,太多的**梯度值将丢失为零,并且网络无法训练。递归网络往往要求损耗缩放(Loss scaling),并且在许多情况下需要权重的单精度主副本。例如,bigLSTM英语语言建模网络需要一个128的比例因子,如果没有这个比例因子,最终的训练结果如图1所示。请参阅混合精度训练文章以获取更多的网络和训练详细信息。

fp16训练(混合精度训练)

fp16训练(混合精度训练)

结论

这篇文章简要介绍了三种混合精度训练技术,这些技术在训练半精度DNN时非常有用。 这些技术的经验结果表明,尽管半精度范围比单精度范围要窄,但对于结果先进的DNN进行各种应用程序任务的训练就足够了,因为结果与纯单精度训练的结果相匹配。 请查看“混合精度训练”(  Mixed-Precision Training )论文,以更详细地描述混合精度训练和各种网络的结果。 有关可在自己的训练脚本中用于各种DNN训练框架的代码示例,请参阅《混合精度训练用户指南》 Training with Mixed Precision User Guide 

 

 

References

P. Micikevicius, S. Narang, J. Alben, G. Diamos, E. Eelsen, B. Ginsburg, M. Houston, O. Kuchaiev, G. Venkatesh, H. Wu.  Mixed Precision Training, 2017. https://arxiv.org/abs/1710.03740

 

Training with Mixed-Precision User Guide, 2017. http://docs.nvidia.com/deeplearning/sdk/mixed-precision-training/index.html.

 

B. Ginsburg, S. Nikolaev, P. Micikevicius. Training with Mixed Precision, GPU Technology Conference, 2017. http://on-demand.gputechconf.com/gtc/2017/presentation/s7218-training-with-mixed-precision-boris-ginsburg.pdf

 

 

 

 

相关文章: