• 文档 >
  • 数值精度
快捷键

数值精度 ¶

在现代计算机中,浮点数使用 IEEE 754 标准表示。有关浮点算术和 IEEE 754 标准的更多详细信息,请参阅浮点算术。特别是要注意,浮点数提供有限的精度(单精度浮点数约为 7 位十进制数字,双精度浮点数约为 16 位十进制数字),并且浮点数的加法和乘法不具有结合律,因此操作顺序会影响结果。因此,PyTorch 不能保证对数学上相同的浮点计算产生位相同的输出。同样,位相同的输出在 PyTorch 版本之间、单个提交或不同平台之间也不保证相同。特别是,即使在控制随机数来源的情况下,CPU 和 GPU 的结果也可能不同,即使对于位相同的输入也是如此。

批处理计算或切片计算 ¶

PyTorch 中的许多操作支持批量计算,即对输入批次的元素执行相同的操作。例如, torch.mm()torch.bmm() 。可以将批量计算实现为遍历批次元素的循环,并对单个批次元素应用必要的数学运算,但由于效率原因,我们通常不对整个批次进行计算。我们调用的数学库和 PyTorch 对操作的内部实现在这种情况下可能会产生与非批量计算略有不同的结果。特别是,如果 AB 是适合批量矩阵乘法的 3D 张量,那么 (A@B)[0] (批量结果的第一个元素)不一定与 A[0]@B[0] (输入批次第一个元素的矩阵乘积)在位运算上完全相同,尽管从数学上讲它们是相同的计算。

同样,对一个张量切片进行的操作不保证产生与对整个张量进行相同操作的结果切片相同的结果。例如,设 A 是一个二维张量。 A.sum(-1)[0] 不保证与 A[:,0].sum() 按位相等。

极端值 ¶

当输入包含可能导致中间结果超出所用数据类型范围的较大值时,最终结果也可能溢出,即使它在原始数据类型中是可表示的。例如:

import torch
a=torch.tensor([1e20, 1e20]) # fp32 type by default
a.norm() # produces tensor(inf)
a.double().norm() # produces tensor(1.4142e+20, dtype=torch.float64), representable in fp32

线性代数 ( torch.linalg ) ¶

无穷值

torch.linalg 所使用的外部库(后端)在输入具有无穷值(如 infNaN )时,不提供其行为保证。因此,PyTorch 也不提供保证。操作可能会返回包含无穷值的张量,或者引发异常,甚至导致段错误。

在调用这些函数之前考虑使用 torch.isfinite() 来检测这种情况。

线性代数中的极值

torch.linalg 中的函数比其他 PyTorch 函数具有更多的极值。

解算器和逆算器假设输入矩阵 A 是可逆的。如果它接近不可逆(例如,如果它具有非常小的奇异值),则这些算法可能会静默地返回错误的结果。这些矩阵被称为病态矩阵。如果提供病态矩阵作为输入,这些函数的结果可能会因在不同设备上使用相同的输入或在通过关键字 driver 使用不同的后端时而变化。

当输入的奇异值彼此接近时,像 svdeigeigh 这样的谱操作也可能返回错误的结果(并且它们的梯度可能是无穷大)。这是因为用于计算这些分解的算法在这些输入上难以收敛。

float64 中运行计算(如 NumPy 默认所做的那样)通常有帮助,但这并不解决所有情况下的这些问题。通过 torch.linalg.svdvals() 分析输入的谱或通过 torch.linalg.cond() 分析它们的条件数可能有助于检测这些问题。

TensorFloat-32(TF32) 在 Nvidia Ampere(及以后)设备上

在 Ampere(及以后)的 Nvidia GPU 上,PyTorch 可以使用 TensorFloat32(TF32)来加速数学密集型操作,特别是矩阵乘法和卷积。当使用 TF32 索引核心执行操作时,仅读取输入尾数的第一个 10 位。这可能会降低精度并产生令人惊讶的结果(例如,将矩阵乘以单位矩阵可能会产生与输入不同的结果)。默认情况下,TF32 索引核心在矩阵乘法中是禁用的,在卷积中是启用的,尽管大多数神经网络负载在使用 TF32 时与使用 fp32 时的收敛行为相同。如果您网络不需要完整的 float32 精度,我们建议使用 torch.backends.cuda.matmul.allow_tf32 = True 启用 TF32 索引核心进行矩阵乘法。如果您的网络需要矩阵乘法和卷积的完整 float32 精度,则也可以使用 torch.backends.cudnn.allow_tf32 = False 禁用卷积的 TF32 索引核心。

更多信息请参阅 TensorFloat32。

FP16 和 BF16 GEMMs 的精度降低

半精度 GEMM 操作通常使用单精度中间累积(减少)来保证数值精度和增强对溢出的抵抗力。为了性能,某些 GPU 架构,尤其是较新的架构,允许对中间累积结果进行一些截断以降低精度(例如,半精度)。从模型收敛的角度来看,这种变化通常是良性的,尽管它可能导致意外的结果(例如,当最终结果应该可以用半精度表示时出现 inf 值)。如果降低精度的减少有问题,可以使用 torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = False 将其关闭

对于 BF16 GEMM 操作也存在类似的标志,默认情况下是开启的。如果 BF16 降低精度的减少有问题,可以使用 torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = False 将其关闭

更多信息请参阅 allow_fp16_reduced_precision_reduction 和 allow_bf16_reduced_precision_reduction

比例点积注意(SDPA)中的 FP16 和 BF16 的降低精度减少

一个简单的 SDPA 数学后端,当使用 FP16/BF16 输入时,由于使用低精度中间缓冲区,可能会累积显著的数值误差。为了缓解这个问题,现在的默认行为是将 FP16/BF16 输入上转换为 FP32。计算在 FP32/TF32 中进行,然后将最终的 FP32 结果下转换回 FP16/BF16。这将提高具有 FP16/BF16 输入的数学后端的数值精度,但会增加内存使用,并且可能导致计算从 FP16/BF16 BMM 转移到 FP32/TF32 BMM/Matmul 时性能下降。

对于需要降低精度以加快速度的场景,可以通过以下设置启用: torch.backends.cuda.allow_fp16_bf16_reduction_math_sdp(True)

在 AMD Instinct MI200 设备上实现 FP16 和 BF16 的降低精度 GEMMs 和卷积

在 AMD Instinct MI200 GPU 上,FP16 和 BF16 的 V_DOT2 和 MFMA 矩阵指令会将输入和输出的非规格值清零。FP32 和 FP64 的 MFMA 矩阵指令不会将输入和输出的非规格值清零。受影响的指令仅由 rocBLAS(GEMM)和 MIOpen(卷积)内核使用;所有其他 PyTorch 操作都不会遇到这种行为。所有其他支持的 AMD GPU 都不会遇到这种行为。

rocBLAS 和 MIOpen 为受影响的 FP16 操作提供了替代实现。BF16 操作的替代实现尚未提供;BF16 数的动态范围比 FP16 数大,不太可能遇到非规格值。对于 FP16 的替代实现,FP16 输入值被转换为中间的 BF16 值,然后在累加 FP32 操作后转换回 FP16 输出。这样,输入和输出类型保持不变。

当使用 FP16 精度进行训练时,一些模型可能会因为 FP16 未规范化值被清零而无法收敛。未规范化值在训练反向传播的梯度计算过程中更频繁地出现。PyTorch 默认在反向传播过程中会使用 rocBLAS 和 MIOpen 的交替实现。可以通过环境变量 ROCBLAS_INTERNAL_FP16_ALT_IMPL 和 MIOPEN_DEBUG_CONVOLUTION_ATTRIB_FP16_ALT_IMPL 来覆盖默认行为。这些环境变量的行为如下:

前向

反向

环境变量未设置

原始

交替

环境设置为 1

交替

替代

环境设置为 0

原始

原始

以下为 rocBLAS 可能用到的操作列表:

  • torch.addbmm

  • torch.addmm

  • torch.baddbmm

  • torch.bmm

  • torch.mm

  • torch.nn.GRUCell

  • torch.nn.LSTMCell

  • torch.nn.Linear

  • torch.sparse.addmm

  • 以下 torch._C._ConvBackend 实现:

    • slowNd

    • slowNd_转置

    • slowNd_膨胀

    • slowNd_膨胀转置

以下为 MIOpen 可能用到的操作列表:

  • torch.nn.Conv[Transpose]Nd

  • 以下 torch._C._ConvBackend 实现:

    • ConvBackend::Miopen

    • ConvBackend::MiopenDepthwise

    • ConvBackend::MiopenTranspose


© 版权所有 PyTorch 贡献者。

使用 Sphinx 构建,并使用 Read the Docs 提供的主题。

文档

PyTorch 的全面开发者文档

查看文档

教程

深入了解初学者和高级开发者的教程

查看教程

资源

查找开发资源并获得您的疑问解答

查看资源