【问题标题】:Breaking down a batch in pytorch leads to different results, why?在pytorch中分解一批会导致不同的结果,为什么?
【发布时间】:2020-04-19 02:12:54
【问题描述】:

我正在尝试在 pytorch 中进行批处理。在我下面的代码中,您可能会将x 视为批量大小为 2 的批次(每个样本是一个 10d 向量)。我使用x_sep 表示x 中的第一个样本。

import torch
import torch.nn as nn

class net(nn.Module):
    def __init__(self):
        super(net, self).__init__()
        self.fc1 = nn.Linear(10,10)

    def forward(self, x):
        x = self.fc1(x)
        return x

f = net()

x = torch.randn(2,10)
print(f(x[0])==f(x)[0])

理想情况下,f(x[0])==f(x)[0] 应该给出一个包含所有真实条目的张量。但是我电脑上的输出是

tensor([False, False,  True,  True, False, False, False, False,  True, False])

为什么会这样?是计算错误吗?还是与pytorch中如何实现批处理有关?


更新:我稍微简化了代码。问题还是一样。

我的推理: 我相信f(x)[0]==f(x[0]) 应该有它的所有条目True,因为矩阵乘法是这样说的。让我们将x 视为一个2x10 矩阵,并将线性变换f() 视为由矩阵B 表示(暂时忽略偏差)。然后用我们的符号f(x)=xB。矩阵乘法告诉我们xB等于先将两行分别乘以右边的B,然后再将两行放回一起。翻译回代码,是f(x[0])==f(x)[0]f(x[1])==f(x)[1]

即使我们考虑偏差,每一行都应该有相同的偏差,并且相等性应该仍然成立。

另请注意,此处未进行任何培训。因此,如何初始化权重并不重要。

【问题讨论】:

  • 你的最后一层返回接收 10 个特征向量并返回一个 10 个特征向量。那么问题是什么以及您在哪里使用批处理?
  • @Green 假设我将样本定义为 10 个分量的向量。那么你可以把这里的x看作是一批2个样本,x_sepx中的第一个样本。将线性变换应用于x,你得到y,一批大小为2。y[0]不应该等于f(x_sep)==y_sep吗?但我的结果告诉我没有,为什么?
  • @Green 或者松散地说,为什么f(x[0])==f(x)[0] 不成立?
  • 我详细回答了你。希望你现在清楚了。

标签: python numpy pytorch batch-processing


【解决方案1】:

TL;DR

在底层它使用了一个名为 addmm 的函数,该函数进行了一些优化,并且可能以稍微不同的方式将向量相乘


我刚刚明白什么是真正的问题,我编辑了答案。

尝试在我的机器上重现和调试它之后。 我发现:

f(x)[0].detach().numpy()
>>>array([-0.5386441 ,  0.4983463 ,  0.07970242,  0.53507525,  0.71045876,
        0.7791027 ,  0.29027492, -0.07919329, -0.12045971, -0.9111403 ],
      dtype=float32)
f(x[0]).detach().numpy()
>>>array([-0.5386441 ,  0.49834624,  0.07970244,  0.53507525,  0.71045876,
        0.7791027 ,  0.29027495, -0.07919335, -0.12045971, -0.9111402 ],
      dtype=float32)
f(x[0]).detach().numpy() == f(x)[0].detach().numpy()
>>>array([ True, False, False,  True,  True,  True, False, False,  True,
   False])

如果你仔细观察,你会发现所有为False的索引,在第5个浮点数上有轻微的数字变化。

经过更多调试,我看到它使用的线性函数addmm

def linear(input, weight, bias=None):
    if input.dim() == 2 and bias is not None:
        # fused op is marginally faster
        ret = torch.addmm(bias, input, weight.t())
    else:
        output = input.matmul(weight.t())
    if bias is not None:
        output += bias
    ret = output
return ret

当 addmm addmm 时,实现 beta*mat + alpha*(mat1 @ mat2) 并且应该更快(例如参见 here)。

Credit to Szymon Maszke

【讨论】:

  • 这似乎是一件精密的事情。感觉很奇怪的是:为什么添加第二行会影响第一行的结果? pytorch(可能也是numpy)在计算第一行的输出时是否使用第二行的信息?为什么会这样……
  • 有趣的发现。但似乎这种现象并不特定于 dim 2 的张量。用x=torch.randn(2,10,10) 尝试然后输出f(x[0][0])==f(x)[0][0] 仍然部分给出True,部分给出False。虽然,f(x[0][0])-f(x)[0][0] 的差异很小,对于不同意的组件大约是 1e-7
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-05
  • 2021-06-14
  • 1970-01-01
相关资源
最近更新 更多