浮点数精度格式比较 | AI生成和翻译
float32、float16 与 bfloat16 的区别
这些都是计算中使用的浮点数据类型,特别是在机器学习框架中(如您分享的 PyTorch 代码片段)。它们的位宽不同,这会影响精度(表示数字的准确程度)、动态范围(可处理数值的跨度)、内存使用和计算速度。具体如下:
- float32(单精度):
- 总共 32 位:1 个符号位、8 个指数位、23 个尾数位。
- 高精度和宽动态范围(指数允许数值范围约为 1e-38 至 1e+38)。
- 优点:对大多数计算准确,在许多场景下避免溢出/下溢。
- 缺点:内存使用较高(每个数字 4 字节),在 GPU 上计算速度较慢,因为需要更多带宽和处理能力。
- 常用于传统基于 CPU 的计算或需要完全准确性的场景。
- float16(半精度):
- 总共 16 位:1 个符号位、5 个指数位、10 个尾数位。
- 较低精度和较窄动态范围(指数限制数值范围约为 1e-7 至 65504)。
- 优点:内存使用减半(每个数字 2 字节),在支持它的硬件(如现代 GPU)上加速计算,对于像 LLM 这样内存是瓶颈的大型模型非常有用。
- 缺点:容易溢出(大数值)或下溢(小数值/梯度),可能导致训练中出现 NaN(非数字)等问题。在表示中也会丢失更多细节。
- bfloat16(Brain 浮点格式):
- 总共 16 位:1 个符号位、8 个指数位、7 个尾数位。
- 匹配 float32 的动态范围(相同的指数位,因此数值跨度相似),但精度降低(尾数位更少)。
- 优点:与 float16 相同的内存节省(2 字节),但由于更宽的范围,在深度学习中稳定性更好——不太可能溢出/下溢。专为神经网络设计,在训练中表现良好,无需太多缩放或归一化。
- 缺点:精度甚至低于 float16,可能导致略微更多的近似误差,但在实践中,对于 LLM 来说通常可以忽略。
在您展示的代码中(dtype = 'bfloat16' if torch.cuda.is_available() and torch.cuda.is_bf16_supported() else 'float16'),它选择 bfloat16(如果 GPU 支持,常见于较新的 NVIDIA/AMD 硬件),否则回退到 float16。这用于混合精度设置,其中计算使用较低精度以提高速度,同时保持某些部分(如累加器)在较高精度以维持准确性。bfloat16 在许多现代设置中(如 Google 的 TPU)更受青睐,因为它在范围上更像 float32,减少了训练不稳定性。
量化方法及其关联
量化是一种减少模型权重、激活值(有时是梯度)位宽的技术,进一步压缩模型,而不仅仅是使用 float16/bfloat16。它与代码中切换数据类型(更多是关于运行时的浮点精度)不同,但相关,因为两者都旨在优化 LLM 的效率。
- 什么是量化?
- 它将高精度值(如 float32)映射到低位表示(如 int8、int4 或甚至自定义浮点)。这减少了内存占用和推理时间,对于在边缘设备上或大规模部署 LLM 至关重要。
- 示例:一个 float32 权重(32 位)可能被量化为 int8(8 位),大小减少 4 倍。
- 常见量化方法:
- 训练后量化(PTQ):在训练后应用。简单但如果未校准(如使用小数据集调整尺度)可能会降低准确性。方法包括最小-最大缩放或基于直方图的方法(如 TensorRT 或 ONNX 中)。
- 量化感知训练(QAT):在训练期间模拟量化(如 PyTorch 中的伪量化操作),因此模型学会处理降低的精度。更准确但需要重新训练。
- 高级变体:
- 仅权重量化:仅量化权重(如到 int4),保持激活值在 float16/bfloat16。
- 分组量化:按组量化(如 GPTQ 方法分组权重以提高准确性)。
- AWQ(激活感知权重量化):考虑激活分布以更好地进行裁剪。
- INT4/INT8 反量化:在推理期间,反量化回 float16 进行计算。
- 与 float16/bfloat16/float32 的关系:
- 您的 dtype 选择是混合精度的一种形式(如 PyTorch 中的 AMP),它使用 float16/bfloat16 进行大多数操作,但缩放到 float32 以防止下溢。量化通过使用整数或甚至更低位的浮点进一步推进。
- 它们在优化流程中相关:从 float32 训练开始,切换到 bfloat16 以加速训练,然后量化为 int8 以进行部署。例如,像 Hugging Face Transformers 这样的库在加载时使用
torch_dtype=bfloat16,然后应用量化(如通过 BitsAndBytes)减少到 4 位。 - 权衡:较低精度/量化加速但风险准确性损失(如 LLM 中困惑度增加)。bfloat16 通常在完全量化之前是一个折中点。
与 Flash Attention 的关系
Flash Attention 是 transformer 中计算注意力(LLM 如 GPT 的关键部分)的优化算法。它通过即时重新计算中间值而不是存储它们来减少内存使用和加速,尤其适用于长序列。
- 精度如何关联:
- Flash Attention(如通过
torch.nn.functional.scaled_dot_product_attention或 flash-attn 库)原生支持较低精度如 float16/bfloat16。事实上,在这些 dtype 中通常更快,因为 GPU(如 NVIDIA Ampere+)有硬件加速(如 Tensor Cores)。 - 您的代码的 dtype 选择直接影响它:使用 bfloat16 或 float16 启用 Flash Attention 的高性能模式,因为它可以融合操作并避免内存瓶颈。在 float32 中,它可能回退到较慢的实现。
- 量化也与之相关——量化模型可以在计算期间反量化为 float16 时使用 Flash Attention。像 vLLM 或 ExLlama 这样的库将 Flash Attention 与量化集成以实现超快推理。
- Flash Attention(如通过
在 PyTorch 中,如果您设置 torch.backends.cuda.enable_flash_sdp(True),当 dtype 是 float16/bfloat16 且硬件支持时,它优先使用 Flash Attention。
浮点精度在 LLM 模型中的一般使用
在大型语言模型(LLM)如 GPT、Llama 或 Grok 中:
- 训练:通常从 float32 开始以保持稳定性,但转向 bfloat16(如 Google 的模型中)或混合精度(float16 带 float32 缩放)以更快处理大规模数据集。bfloat16 越来越受欢迎(如 PyTorch 2.0+ 中),因为它比 float16 需要更少的超参数调整。
- 推理/部署:float16 或 bfloat16 在 GPU 上常见以加速。为了更高效率(如在消费级硬件上),模型被量化为 8 位或 4 位(如 llama.cpp 中的 GGUF 格式)。这允许在 <24GB VRAM 上运行 70B 参数模型。
- 权衡:
- 较高精度(float32):更好的准确性,但更慢且更耗内存。
- 较低精度:更快、更轻,但可能输出质量下降(如在极端量化中幻觉略微增加)。
- 趋势:随着像 NVIDIA H100(强 bfloat16 支持)这样的硬件,bfloat16 正在成为标准。像 PEFT(参数高效微调)这样的工具将其与量化结合以进行微调。在开源中,像 Transformers 或 Optimum 这样的库处理自动 dtype 转换和量化。
如果您在代码中实现这一点,请在您的硬件上测试——bfloat16 在较新的 GPU 上表现出色,而 float16 更通用但在梯度处理上更棘手。
参考文献:
理解深度学习中的浮点精度
LLM 量化技术
Flash Attention 解释
PyTorch 中的混合精度训练