pytorch 中的机器精度是多少?何时应该使用双倍?

问题描述 投票:0回答:1

我正在对合成数据进行实验(例如拟合正弦曲线),并且我在 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])

令我困惑的是,我尝试将我认为是小的数字添加到一个很小的数字中,这样它就没有返回任何差异,但它确实返回了一个差异(即我尝试使用

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)

输出:

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)

我原以为一切都会为零,但事实并非如此。有人可以向我解释一下发生了什么事吗?如果我的损失接近

1e-7
,我是否应该使用
double
而不是
float
?谷歌搜索似乎 single 是 float afaik 的精度。

如果我想使用双打,什么是缺点/优点+更改代码最不容易出错的方法是什么?对 double 类型进行一次更改就足够了还是有全局标志?


有用的提醒:

回忆机器精度:

机器精度是使 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)。但我相信这是正确的。

如果有人可以纠正细节,那就太好了。


有用的链接:

floating-point pytorch precision
1个回答
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)

输出:

torch.float32
tensor(1.)
tensor(1.)

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

优点 - 更高的准确性。

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.