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)而遗漏了一个小细节。但我相信这是正确的。
如果有人能更正细节,那就太棒了。
有用的链接:
我认为您误解了浮点的工作原理。关于浮点是什么,有很多很好的资源(例如),所以我在这里不详细介绍。
关键是浮点数是动态的。它们可以表示达到一定精度的非常大的值的相加,或者达到一定精度的非常小的值的相加,但不能表示非常大的值与非常小的值的相加。他们在旅途中调整自己的范围。
所以这就是为什么你的测试结果与“机器精度”中的解释不同——你添加了两个非常小的值,但该段落明确表示“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 时)