数值精度¶
在现代计算机中,浮点数使用 IEEE 754 标准表示。 有关浮点运算和 IEEE 754 标准的更多详细信息,请参阅浮点运算 特别要注意的是,浮点提供的精度有限(大约 7 位十进制数字 对于单精度浮点数,对于双精度,大约为 16 个十进制数字 浮点数),并且浮点加法和乘法不是 associative,因此操作的顺序会影响结果。 因此,不保证 pytorch 为浮点计算生成按位相同的结果,这些浮点计算是 数学上相同。同样,不能保证 PyTorch 版本、单个提交或不同平台。特别是 CPU 和 GPU 即使对于按位相同的输入,甚至在控制了 随机性的来源。
批处理计算或切片计算¶
pytorch 中的许多操作都支持批处理计算,其中执行相同的操作
对于输入批次的元素。这方面的一个例子是 and
。可以将批处理计算实现为批处理元素的循环,
并将必要的数学运算应用于各个 batch 元素,以提高效率
我们不会这样做,通常会对整个批次执行计算。数学
我们正在调用的库,以及 PyTorch 内部的操作实现可以生成
与非批处理计算相比,在这种情况下的结果略有不同。特别
let 和 是 3D 张量,其维度适合批量矩阵乘法。
then (批处理结果的第一个元素) 不能保证按位
identical to (输入批次的第一个元素的矩阵乘积)
尽管在数学上它是相同的计算。
A
B
(A@B)[0]
A[0]@B[0]
同样,应用于张量切片的操作不能保证产生以下结果
与应用于完整张量的相同操作的结果的切片相同。例如,设 为 2 维张量。 不保证按位等于 。A
A.sum(-1)[0]
A[:,0].sum()
极值¶
当输入包含较大的值,以至于中间结果可能会溢出 used 数据类型,则最终结果也可能溢出,即使它可以在原始 数据类型。例如:
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
Nvidia Ampere 设备上的 TensorFloat-32(TF32)¶
在 Ampere Nvidia GPU 上,pytorch 默认使用 TensorFloat32 (TF32) 进行数学加速
密集运算,特别是矩阵乘法和卷积。执行操作时
使用 TF32 Tensor Core 时,仅读取输入尾数的前 10 位。这会导致准确性降低
结果,以及令人惊讶的结果,例如将矩阵乘以单位矩阵会产生
结果与输入不同。
大多数神经网络工作负载在使用 tf32 时具有与它们相同的收敛行为
但是,对于 FP32,如果需要更高的精度,可以使用 TF32 关闭torch.backends.cuda.matmul.allow_tf32 = False
有关更多信息,请参阅 TensorFloat32
FP16 GEMM 的精度降低¶
半精度 GEMM 操作通常以单精度进行中间累积(减少)来完成,以提高数值精度和提高对溢出的弹性。为了提高性能,某些 GPU 架构,尤其是较新的 GPU 架构,允许对中间累积结果进行一些截断,以降低精度(例如,半精度)。从模型收敛的角度来看,这种变化通常是良性的,尽管它可能会导致意外的结果(例如,最终结果应该以半精度表示的值)。
如果降低精度的缩减有问题,可以使用inf
torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = False