pytorch 的机器精度是多少,什么时候应该使用双打?

Cha*_*ker 5 floating-point precision pytorch

我正在对合成数据进行实验(例如拟合正弦曲线),我在 pytorch 中遇到了非常小的错误。一如约2.00e-7。我正在阅读有关机器精度的信息,它似乎非常接近机器精度。我怎么知道这是否会导致问题(或者它是否已经存在,例如我无法区分不同的错误,因为它们是“机器零”)。

错误:

p = np.array([2.3078539778125768e-07,
               1.9997889411762922e-07,
               2.729681222011256e-07,
               3.2532371115080884e-07])

m = np.array([3.309504692539563e-07,
                 4.1058904888091606e-06,
                 6.8326703386053605e-06,
                 7.4616147721799645e-06])
Run Code Online (Sandbox Code Playgroud)

让我感到困惑的是,我尝试将我认为的数字添加到较小的数字中,以便它没有返回任何差异,但它确实返回了一个差异(即我尝试a+eps = a使用eps = smaller than machine precision):

import torch

x1 = torch.tensor(1e-6)
x2 = torch.tensor(1e-7)
x3 = torch.tensor(1e-8)
x4 = torch.tensor(1e-9)

eps = torch.tensor(1e-11)

print(x1.dtype)
print(x1)
print(x1+eps)

print(x2)
print(x2+eps)

print(x3)
print(x3+eps)

print(x4)
print(x4+eps)
Run Code Online (Sandbox Code Playgroud)

输出:

torch.float32
tensor(1.0000e-06)
tensor(1.0000e-06)
tensor(1.0000e-07)
tensor(1.0001e-07)
tensor(1.0000e-08)
tensor(1.0010e-08)
tensor(1.0000e-09)
tensor(1.0100e-09)
Run Code Online (Sandbox Code Playgroud)

我希望一切都为零,但事实并非如此。有人可以向我解释发生了什么吗?如果我的损失接近,1e-7我应该使用double而不是float? 谷歌搜索似乎 single 是 float afaik 的精度。

如果我想使用双打,什么是缺点/优点 + 更改代码最不容易出错的方法是什么?对双类型的单一更改是否足够,或者是否有全局标志?


有用的提醒:

召回机器精度:

机器精度最小是多少?这样 1 和 1 + 之间的差异?非零,即计算机识别的这两个数字之间的最小差值。对于 IEEE-754 单精度,这是 2 -23(大约 10 -7)而对于 IEEE-754 双精度,它是 2 -52(大约 10 -16)。


潜在的解决方案:

好的,让我们看看这是否是我认为正确的一个很好的总结(取模忽略了我现在不完全理解浮点数的一些细节,比如偏差)。

但我得出的结论是,对我来说最好的事情是确保我的错误/数字有两个属性:

它们彼此相差 7 个小数(由于尾数是 24 大,就像你指出的 log_10(2^24) = 7.225)它们离边缘足够远。为此,我将尾数设为距下边缘 23 位(点位置约 -128+23),最大边缘相同但 127-23。只要我们或多或少地满足,我们就可以避免将两个太小而机器无法区分的数字相加(条件 1)并避免上溢/下溢(条件 2)。

也许我可能会因偏差或其他一些浮点细节(例如表示无穷大,NaN)而遗漏了一个小细节。但我相信这是正确的。

如果有人能更正细节,那就太棒了。


有用的链接:

hkc*_*rex 7

我认为您误解了浮点的工作原理。关于浮点是什么,有很多很好的资源(例如),所以我在这里不详细介绍。

关键是浮点数是动态的。它们可以表示达到一定精度的非常大的值的相加,或者达到一定精度的非常小的值的相加,但不能表示非常大的值与非常小的值的相加。他们在旅途中调整自己的范围

所以这就是为什么你的测试结果与“机器精度”中的解释不同——你添加了两个非常小的值,但该段落明确表示“1+eps”。1 是比 1e-6 大得多的值。因此,以下内容将按预期工作:

import torch

x1 = torch.tensor(1).float()
eps = torch.tensor(1e-11)

print(x1.dtype)
print(x1)
print(x1+eps)
Run Code Online (Sandbox Code Playgroud)

输出:

torch.float32
tensor(1.)
tensor(1.)
Run Code Online (Sandbox Code Playgroud)

第二个问题——什么时候应该使用 double?

优点 - 更高的准确性。

缺点 - 速度慢得多(大部分时间硬件配置为浮动),内存使用量加倍。

这实际上取决于您的应用程序。大多数时候我只会说不。正如我所说,当网络中存在非常大的值和非常小的值时,您需要加倍。通过适当的数据标准化,这种情况无论如何都不会发生。

(另一个原因是指数溢出,比如当你需要表示非常非常大/小值,超出 1e-38 和 1e38 时)