nn.Linear 的输出对于相同的输入是不同的

Output of nn.Linear is different for the same input

torch==1.7.1+cu101中,我有两个张量

import torch
a = torch.rand(1,5,10)
b = torch.rand(100,1,10)

和一个前馈网络

import torch.nn as nn
l = nn.Linear(10,10)

我强制其中一行相等:

a[0,0] = b[80][0].clone()

然后我将两个张量都提供给 l:

r1 = l(a)
r2 = l(b)

显然,由于a[0,0]等于b[80,0]r1[0,0]必然等于r2[80,0]。 但结果是这样的:

(r1[0,0] == r2[80,0]).all()
>>> False

我通过以下方式修复了随机性:

seed = 42

random.seed(seed)
os.environ['PYTHONHASHSEED'] = str(seed)
np.random.seed(seed)
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = True

有谁知道为什么 (r1[0,0] == r2[80,0]).all() 是假的?

如果您打印 r1[0, 0]r2[80, 0],您会发现它们非常相似。即使打印位数相同。

但是,如果您打印 r1[0, 0] - r2[80, 0],您会发现结果条目并不完美 0.0(尽管它们接近它),这意味着 r1[0, 0]r2[80, 0] 接近但不完全相同。

现在,如果我们要先取出那些单独的向量,然后像这样将它们传递给线性层:

r1_small = l(a[0, 0])
r2_small = l(b[80, 0])
print((r1_small == r2_small).all())  # tensor(True)

我们知道它们完全相同,即使是浮点数。

因此,这意味着相同的向量在通过线性层.

时是较大张量的较小 部分,因此会引入一些差异。

同样值得注意的是,当前 n-1 个维度都是 2 的幂时,不会出现相同的差异:

a2 = torch.randn(8, 8, 10)
b2 = torch.randn(4, 16, 10)
a2[0, 0] = b2[1, 0].clone()
r1_2 = l(a2)
r2_2 = l(b2)
print((r1_2[0, 0] == r2_2[1, 0]).all())  # tensor(True)

所以,虽然我不知道细节,但我怀疑它与 byte alignment 有关。

一般来说,测试在数学上应该相等的浮点值之间的完全相等并不总能给出预期的结果。那么我们如何处理这些差异呢?您可以使用 torch.isclose or torch.allclose 检查不完全相等。