为什么 pytorch matmul 在 cpu 和 gpu 上执行时得到不同的结果?

2024-04-23

我试图找出 numpy/pytorch、gpu/cpu、float16/float32 数字之间的舍入差异,而我发现的内容让我感到困惑。

基本版本是:

a = torch.rand(3, 4, dtype=torch.float32)
b = torch.rand(4, 5, dtype=torch.float32)
print(a.numpy()@b.numpy() - a@b)

然而,结果如预期全为零

print((a.cuda()@b.cuda()).cpu() - a@b)

得到非零结果。为什么 Pytorch float32 matmul 在 gpu 和 cpu 上执行不同?

一个更令人困惑的实验涉及 float16,如下所示:


a = torch.rand(3, 4, dtype=torch.float16)
b = torch.rand(4, 5, dtype=torch.float16)
print(a.numpy()@b.numpy() - a@b)
print((a.cuda()@b.cuda()).cpu() - a@b)

这两个结果均非零。为什么 numpy 和 torch 处理 float16 数字的方式不同?我知道cpu只能进行float32运算,并且numpy在计算之前将float16转换为float32,但是torch计算也在cpu上执行。

你猜怎么着,print((a.cuda()@b.cuda()).cpu() - a.numpy()@b.numpy()) 得到全零结果!这对我来说纯粹是幻想……

环境如下:

  • 蟒蛇:3.8.5
  • 火炬:1.7.0
  • numpy:1.21.2
  • CUDA:11.1
  • 显卡:GeForce RTX 3090

根据一些评论者的建议,我添加了以下平等测试

(a.numpy()@b.numpy() - (a@b).numpy()).any()
((a.cuda()@b.cuda()).cpu() - a@b).numpy().any()
(a.numpy()@b.numpy() - (a@b).numpy()).any()
((a.cuda()@b.cuda()).cpu() - a@b).numpy().any()
((a.cuda()@b.cuda()).cpu().numpy() - a.numpy()@b.numpy()).any()

分别直接执行上述五个打印函数,结果为:

False
True
True
True
False

对于最后一个,我已经尝试过好几次了,我想我可以排除运气的可能性。


正如 @talonmies 所提到的,差异主要是数字上的。 CPU/GPU 及其各自的 BLAS 库的实现方式不同,并且使用不同的操作/操作顺序,因此存在数值差异。

一种可能的原因是顺序操作与减少操作(https://discuss.pytorch.org/t/why- Different-results-when-multiplying-in-cpu-than-in-gpu/1356/3 https://discuss.pytorch.org/t/why-different-results-when-multiplying-in-cpu-than-in-gpu/1356/3),例如(((a+b)+c)+d) 与 ((a+b)+(c+d)) 相比将具有不同的数值属性。

这个问题 https://stackoverflow.com/questions/21020356/matrix-multiplication-on-cpu-numpy-and-gpu-gnumpy-give-different-results还谈到融合操作(乘加)可能会导致数值差异。

我做了一些测试,发现如果我们在计算前将数据类型提升为float32,然后将其降级,GPU在float16模式下的输出是可以匹配的。这可能是由于内部中间铸造或融合操作更好的数值稳定性造成的(torch.backends.cudnn.enabled不要紧)。但这并不能解决 float32 中的情况。

import torch

def test(L, M, N):
    # test (L*M) @ (M*N)
    for _ in range(5000):
        a = torch.rand(L, M, dtype=torch.float16)
        b = torch.rand(M, N, dtype=torch.float16)

        cpu_result = a@b
        gpu_result = (a.cuda()@b.cuda()).cpu()
        if (cpu_result-gpu_result).any():
            print(f'({L}x{M}) @ ({M}x{N}) failed')
            return
    else:
        print(f'({L}x{M}) @ ({M}x{N}) passed')


test(1, 1, 1)
test(1, 2, 1)
test(4, 1, 4)
test(4, 4, 4)

def test2():
    for _ in range(5000):
        a = torch.rand(1, 2, dtype=torch.float16)
        b = torch.rand(2, 1, dtype=torch.float16)

        cpu_result = a@b
        gpu_result = (a.cuda()@b.cuda()).cpu()

        half_result = a[0,0]*b[0,0] + a[0,1]*b[1,0]
        convert_result = (a[0,0].float()*b[0,0].float() + a[0,1].float()*b[1,0].float()).half()

        if ((cpu_result-half_result).any()):
            print('CPU != half')
            return
        if (gpu_result-convert_result).any():
            print('GPU != convert')
            return
    else:
        print('All passed')

test2()

Output:

(1x1) @ (1x1) passed
(1x2) @ (2x1) failed
(4x1) @ (1x4) passed
(4x4) @ (4x4) failed
All passed

你可以看出,当内部尺寸为1,它通过了检查(不需要乘法加法/归约)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么 pytorch matmul 在 cpu 和 gpu 上执行时得到不同的结果? 的相关文章

  • 以不同顺序对多列上的结构化 Numpy 数组进行排序

    我有一个结构化的 numpy 数组 dtype price float counter int values 35 1 36 2 36 3 a np array values dtype dtype 我想按价格排序 如果价格相等则按计数器排
  • 测试由于浮点限制而导致的舍入误差

    我最近了解到浮点的主要限制之一 事实上 某些数字无法以二进制正确表示 因此可能给出的答案对于您的目的来说不够准确 知道round 2 675 2 and round 2 665 2 两者相等2 67我尝试编写一些代码来给出具有此属性的数字列
  • 使用 NaN 计算 numpy 数组中的移动平均值

    我正在尝试计算包含 NaN 的大型 numpy 数组中的移动平均值 目前我正在使用 import numpy as np def moving average a n 5 ret np cumsum a dtype float ret n
  • 四舍五入到 25、50、75、100

    我不是一个数学爱好者 所以我很难想出一个将小数四舍五入到 25 50 75 和 100 的计算方法 这不会是典型的四舍五入 因为小数不会减少但只增加了 Example 如果 11 12 则舍入为 11 25 如果为 11 34 则舍入为 1
  • numpy 中的分层抽样

    在 numpy 中我有一个这样的数据集 前两列是索引 我可以通过索引将数据集分成多个块 即第一个块是 0 0 第二个块是 0 1 第三个块 0 2 然后是 1 0 1 1 1 2 等等 每个块至少有两个元素 索引列中的数字可能会有所不同 我
  • 使用文件处理程序时 numpy savetxt 失败

    在Windows 7上 使用最新的numpy 1 13 3和PYTHON 3 5 如果我有一个名为points的数组 其形状为m x 6 dtype为float32 我可以将数组保存到 foo txt 文件中 如下所示 np savetxt
  • 带有指针数组的 cython

    我在 python 中有一个 numpy ndarrays 列表 具有不同的长度 并且需要非常快速地访问 python 中的列表 我认为指针数组就可以解决问题 我试过 float type t list of arrays no of ar
  • 如何使用 pandas 选择所有非 NaN 列和非 NaN 最后一列?

    如果标题有点令人困惑 请原谅我 假设我有test h5 下面是使用读取该文件的结果df read hdf test h5 testdata 0 1 2 3 4 5 6 0 123 444 111 321 NaN NaN NaN 1 12 2
  • 如何“缩放”numpy 数组?

    我想将形状 h w 的数组缩放 n 倍 从而得到形状 h n w n 的数组 其中 假设我有一个 2x2 数组 array 1 1 0 1 我想将数组缩放为 4x4 array 1 1 1 1 1 1 1 1 0 0 1 1 0 0 1 1
  • 让 distutils 在正确的位置查找 numpy 头文件

    在我的安装中 numpy 的arrayobject h位于 site packages numpy core include numpy arrayobject h 我编写了一个使用 numpy 的简单 Cython 脚本 cimport
  • 将具有不同大小的行的数据加载到 Numpy 数组中

    假设我有一个包含如下数据的文本文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 如何将它加载到 numpy 数组中 使其看起来像这样 1 2 3 4 5 0 6 7 8 0 0 0 9 1
  • 将索引数组转换为 NumPy 中的 one-hot 编码数组

    给定一个一维索引数组 a array 1 0 3 我想将其一次性编码为二维数组 b array 0 1 0 0 1 0 0 0 0 0 0 1 创建归零数组b有足够的列 即a max 1 然后 对于每一行i 设置a i 第 列 至1 gt
  • 将非方邻接矩阵导入 Networkx python

    我在下面有一些 pandas 数据框形式的数据 其中列代表离散技能 行代表离散工作 仅当工作需要该技能时才存在 1 否则为 0 skill 1 skill 2 job 1 1 0 job 2 0 0 job 3 1 1 我想使用 netwo
  • 当 pandas 是导入时,Cx_freeze TypeError 只能使用 numpy 依赖项将列表(不是“NoneType”)连接到列表

    我正在尝试使用 cxfreeze 将以下脚本转换为可执行文件 import datetime from calendar import monthrange from tia bbg import LocalTerminal as Lt i
  • 使用 scipy、python、numpy 进行非线性 e^(-x) 回归

    下面的代码为我提供了一条最佳拟合线的平坦线 而不是沿着 e x 模型的一条适合数据的漂亮曲线 谁能告诉我如何修复下面的代码以使其适合我的数据 import numpy as np import matplotlib pyplot as pl
  • 求解超定系统最小二乘的最快方法

    我有一个大小为 m n 的矩阵 A m 阶约为 100K n 阶约为 500 和向量 b 另外 我的矩阵是病态的并且等级不足 现在我想找出 Ax b 的最小二乘解 为此我比较了一些方法 scipy linalg lstsq 时间 剩余 14
  • 如何计算总和的平方和?

    我有一笔款项需要加快处理速度 在一种情况下是 S x y k l Fu ku Fv lv Fx kx Fy ly 另一种情况是 S x y S k l Fu ku Fv lv Fx kx Fy ly 2 注意 S indices 是这些索引
  • 使用 Scipy/Numpy 在浊点的二维插值中仅获取“有效”点

    我有一个通过人的背部摄影测量获得的浊点 我正在尝试对其进行插值以获得规则网格 为此我正在使用scipy interpolate到目前为止取得了良好的成果 问题是 我正在使用的函数 scipy interpolate griddata 使用平
  • Python Numpy Reshape错误[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 我在尝试重塑 3D numpy 数组时遇到一个奇怪的错误 数组 x 的形状为 6 10 300 我想将其重塑为 6 3000 我正
  • 如何调试 numpy 掩码

    这个问题与this one https stackoverflow com q 73672739 11004423 我有一个正在尝试矢量化的函数 这是原来的函数 def aspect good angle float planet1 goo

随机推荐