这是一个关于深度学习和高性能计算中非常常见且重要的问题。BF16和FP16都是用于表示浮点数的16位格式,旨在加速计算并减少内存使用,但它们的设计目标和权衡有所不同。

下面我将详细解释它们。

核心概念:什么是浮点数?

简单来说,浮点数用类似科学计数法的方式来表示一个很大或很小的数字。它主要由三个部分组成:

  • 符号位:表示正负。
  • 指数位:表示数值的规模(例如,10的几次方)。
  • 尾数位:表示数值的精度(例如,1.234…)。

FP16和BF16的区别就在于如何分配这16个比特(位)给这三个部分。


1. FP16 - 半精度浮点数

FP16是标准的16位浮点数格式。

  • 位分配

    • 1位 符号位
    • 5位 指数位
    • 10位 尾数位
  • 动态范围: 约 ±65,504

  • 精度: 具有10位尾数,因此精度相对较高。

  • 优点

    • 在16位格式中提供了较好的精度。
    • 得到许多GPU(如NVIDIA从Pascal架构开始)的硬件原生支持,计算速度快。
  • 缺点

    • 动态范围有限:这是FP16在深度学习训练中的主要问题。由于指数位只有5位,它能表示的数值范围不够大。在训练过程中,梯度(用于更新模型参数的值)可能会变得非常小,以至于在FP16下会下溢成为0,这被称为梯度消失问题,会导致模型无法学习。

为了解决FP16的动态范围问题,研究者们发明了“混合精度训练”技术,即:

  • 使用FP16进行前向传播和反向传播,以加速计算。
  • 但在内部保留一个FP32的权重副本,用于权重更新和累加,以避免精度损失。
  • 这是目前使用FP16进行训练的标准做法。

2. BF16 - 脑浮点数

BF16是由Google Brain为机器学习应用专门设计的16位格式。它的名字“Brain Float”也来源于此。

  • 位分配

    • 1位 符号位
    • 8位 指数位
    • 7位 尾数位
  • 动态范围: 与FP32完全相同(约 ±3.4 × 10³⁸)

  • 精度: 只有7位尾数,因此精度比FP16低。

  • 设计哲学

    • 牺牲精度,保留范围。神经网络对数值的范围(指数) 比对其精确值(尾数) 更敏感。只要数值不至于溢出(变成无穷大)或下溢(变成零),即使有些精度损失,模型通常也能很好地工作和收敛。
  • 优点

    • 巨大的动态范围:其范围与FP32一致,彻底解决了FP16在训练中容易出现的梯度下溢/上溢问题。这使得训练更加稳定,通常无需像FP16那样复杂的混合精度技巧。
    • 与FP32轻松转换:从BF16转换到FP32非常简单,只需在尾数后面补零即可。这简化了硬件和软件设计。
  • 缺点

    • 精度较低:由于尾数位少,它能表示的精度比FP16还要低。但对于大多数深度学习应用来说,这是可以接受的权衡。

对比总结

特性 FP16(半精度) BF16(脑浮点数) FP32(单精度)
总位数 16位 16位 32位
符号位 1位 1位 1位
指数位 5位 8位 8位
尾数位 10位 7位 23位
动态范围 较小(±65k) 大(与FP32相同) 大(±3.4e³⁸)
精度 较高 较低
主要应用 推理,混合精度训练 深度学习训练和推理 通用计算,科学计算
设计目标 通用的16位浮点标准 为机器学习优化 高精度通用标准

实际应用中的选择

  • 训练

    • BF16 正变得越来越流行,因为它能提供稳定的训练,且通常比混合精度FP16训练更简单、更快速。支持BF16的硬件(如Google TPU, NVIDIA Ampere架构及以后的GPU, Intel Sapphire Rapids CPU等)正在成为主流。
    • FP16 通过混合精度训练仍然被广泛使用,尤其是在稍旧的硬件上。
  • 推理

    • 两者都常被用于推理,以加速计算和减少模型内存占用。选择哪一个通常取决于目标硬件对哪种格式的支持更好、更高效。

简单比喻:

  • FP32 像一把高精度的游标卡尺,又准又能量很大很小的东西。
  • FP16 像一把短程的游标卡尺,很准但量程有限,量不了太大规模的东西。
  • BF16 像一把长程的卷尺,量程非常大,但刻度比较粗糙,读数没那么精确,但对于估算房间大小来说已经足够了。

总而言之,BF16和FP16都是为了在深度学习中实现速度与精度的平衡,但BF16通过牺牲精度来换取更大的数值表示范围,这一设计更贴合深度学习训练的需求,因此正逐渐成为训练领域的主流格式。

更多推荐