在使用深度学习模型时,浮点格式并不是最有魅力的,或者(坦率地说)不是最重要的考虑因素:如果您的模型不能很好地工作,那么您的浮点格式肯定不会拯救您!但是,过去一定的模型复杂性/模型大小/培训时间,您选择的离散点格式可能会对您的模型培训时间甚至性能产生重大影响。
众所周知,深度神经网络可以容忍较低的数值精度。事实证明,高精度的计算在训练或推断神经网络方面没有那么有用:额外的精度没有任何好处,但速度更慢,内存效率更低。
令人惊讶的是,一些模型甚至可以在较低精度的情况下达到较高的精度,最近的研究将其归因于精度较低的正则化效应。
最后(这是我的猜测-我还没有看到任何实验或论文来证实这一点),除非你使用适当的精确格式,否则某些复杂的模型可能无法收敛。在解析梯度更新和实际反向传播之间存在漂移:精度越低,漂移越大。我预计深度学习特别容易受到这里的一个问题的影响,因为这里有很多乘法、除法和减法运算。
让我们快速了解一下深度学习的三种浮点格式。有更多的浮点格式,但只有几个获得了吸引力:浮点格式需要适当的硬件和固件支持,这限制了新格式的引入和采用。
为了快速概述,Grigory Sapunov为深入学习编写了各种浮点格式的简要介绍。
当有人说“浮点”时,这些浮点格式可能是大多数人想到的。IEEE标准754规定了几种格式,但出于深度学习的目的,我们只对三种格式感兴趣:FP16、FP32和FP64(也称为半精度、单精度和双精度浮点格式)1。
让我们以FP32为例。每个FP32数字都是一个32位的序列。总之,这个序列表示实数
通过确定表示值的大小或刻度(请注意,这些位中的任何一位的改变都会极大地改变其表示值的大小)。这些位称为指数位或刻度位。
最后,通过确定代表值的精确值。这些位称为尾数位或精度位。
显然,你拥有的比特越多,你能做的就越多。以下是这三种格式的细分方式:
这里我略去了一些细节(例如,如何表示nan、正无穷大和负无穷大),但这主要是浮点数的工作方式。更多细节可以在维基百科页面上找到,当然还有IEEE标准754本身的最新修订版。
FP32和FP64受到软件(C/C++、PyTorch、Tensor Flow)和硬件(x86 CPU和大多数NVIDIA/AMD GPU)的广泛支持。
另一方面,FP16在软件中没有得到广泛的支持(在C/C++中需要使用专用库)。然而,由于深度学习倾向于偏爱FP16而不是FP32,它在主要的深度学习框架(如tf.float16和torch.float16)中得到了支持。在硬件方面,x86CPU不支持FP16作为一种独特的类型,但在现代GPU上得到了很好的支持。
BFloat16(也称为。Brain浮点格式(以Google Brain命名)基本上与fp16相同,但3个尾数位变成指数位(即bfloat16用3位精度换取小数)。
说到深度学习,价值一般有三种“味道”:权重、活跃度和梯度。Google建议将权重和渐变存储在fp32中,将激活存储在bflat16中。然而,在特别宽松的情况下,权重可以存储在bflat16中,而不会显著降低性能。
在软件支持方面,C/C++不支持bfloat16,但TensorFlow(tf.bfloat16)和PyTorch(torch.bfloat16)支持bfloat16。
在硬件支持方面,它得到了一些现代CPU的支持,但真正的支持来自GPU和ASIC。在撰写本文时,bfloat16得到了NVIDIA A100(第一个支持它的GPU!)的支持,并将在未来的AMDGPU中得到支持,当然,它也得到了Google TPU v2/v3的支持。
严格地说,这并不是它自己的浮点格式,只是对NVIDIA开发的在他们的张量核心硬件2上以混合精度训练的技术的过分狂热的烙印。
NVIDIA TensorFloat(也称为NVIDIA TensorFloat)。TF32)只是一个32位浮点,为了在张量内核上执行,它降低了13个精度位。因此,它的精度为FP16(10位),范围为FP32(8位)。但是,如果您没有使用张量核,那么它只是一个32位浮点数;如果您只考虑存储,那么它只是一个32位浮点数。
TF32的一个明显优势是它们有点像FP32。引用NVIDIA开发人员博客中的一句话:
使用NVIDIA库的应用程序使用户能够在无需更改代码的情况下利用TF32的优势。TF32张量核心对FP32输入进行操作,并在FP32中产生结果。非矩阵运算继续使用FP32。
您可以在NVIDIA博客上阅读更多关于TF32的内容,也可以在NVIDIA开发人员博客上阅读有关其在安培架构中的硬件支持的更多信息。
在硬件方面,NVIDIA A100是第一个支持TF32的GPU(在撰写本文时,也是唯一的设备)。
首先要说的是,对于您的深度学习模型,浮点格式绝不是最重要的考虑因素-甚至不是最重要的考虑因素。浮点格式很可能只会对非常大或复杂的模型产生影响,因为在GPU内存上匹配模型是一个挑战,或者对这些模型来说,培训时间非常长。
要说的第二件事是,任何实用的建议都必须在很大程度上依赖于您可以使用的软件。
大多数深度学习堆栈支持混合精度训练,这是一个相当好的默认选项,可以获得低精度训练的一些好处,同时仍然可以合理地避免下溢和溢出问题。
TensorFlow本身支持混合精度训练,而NVIDIA Apexlibrary使PyTorch提供自动混合精度训练。首先,看看NVIDIA的AMP开发人员指南,以及关于混合精度培训的文档。
混合精确训练的要点值得一读。基本上有两个主要技巧:
损失比例:将损失乘以某个较大的数字,然后将梯度更新除以相同的较大数字。这避免了FP16中的损耗下溢(即由于精度有限而钳位到零),同时仍然保持了可靠的反向传播。
权重的FP32主副本:将权重本身存储在FP32中,但在进行前向和后向传播之前将它们强制转换为FP16(以获得性能优势)。在权重更新期间,FP16渐变将强制转换为FP32以更新主副本。
您可以在NVIDIA和BaiduResearch的这篇文章中或在NVIDIA附带的博客文章中阅读有关这些技术的更多信息。
如果您已经训练过混合精度的模型,那么可能不值得花费时间或精力来移植代码以利用替代的浮点格式和尖端硬件。
然而,如果您选择走这条路,请确保您的用例确实需要它,也许您不使用bfloat16就无法扩展您的模型,或者您真的需要减少培训时间。
不幸的是,对于bflat16如何与tf32相比较,我没有很好的见解,所以“做好功课”是我唯一能给出的建议。然而,由于NVIDIA A100才刚刚进入市场(在撰写本文时),看看机器学习社区对各种低精度选项的看法将是一件很有趣的事情。
从技术上讲,有四倍和八倍精度的浮点格式,但这些格式很少使用,在深度学习中肯定是闻所未闻的。-↩。
张量核心实质上是一种混合精度的fp16/fp32核心,英伟达针对深度学习应用对其进行了优化。--↩