CPU和GPU生成的结果不匹配

重大的

我准备将Numba与我的AMD GPU一起使用。我从他们网站上可用的最基本的示例开始,使用蒙特卡洛模拟来计算Pi的值。

我对代码进行了一些更改,以使其可以先在GPU上运行,然后在CPU上运行。这样,我只想比较执行代码和验证结果所花费的时间。下面是代码:

from numba import jit
import random
from timeit import default_timer as timer

@jit(nopython=True)
def monte_carlo_pi(nsamples):
    acc = 0
    for i in range(nsamples):
        x = random.random()
        y = random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

def monte_carlo_pi_cpu(nsamples):
    acc = 0
    for i in range(nsamples):
        x = random.random()
        y = random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples

num = int(input())

start = timer()
random.seed(0)
print(monte_carlo_pi(num))
print("with gpu", timer()-start)

start = timer()
random.seed(0)
print(monte_carlo_pi_cpu(num))
print("without gpu", timer()-start)

我期望GPU的性能更好,所以它确实做到了。但是,CPU和CPU的某些结果不匹配。

1000000 # input parameter
3.140836 # gpu_out
with gpu 0.2317520289998356
3.14244 # cpu_out
without gpu 0.39849199899981613

我知道Python不能很好地执行长浮点运算,但是这些仅是小数点后6位,而且我并不期望出现如此大的差异。谁能解释为什么会出现这种差异?

乔什·阿德尔

我对您的代码进行了一些重组:

import numpy 
from numba import jit
import random
from timeit import default_timer as timer

@jit(nopython=True)
def monte_carlo_pi(nsamples):
    random.seed(0)
    acc = 0
    for i in range(nsamples):
        x = random.random()
        y = random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples


num = 1000000

# run the jitted code once to remove compile time from timing
monte_carlo_pi(10)

start = timer()
print(monte_carlo_pi(num))
print("jitted code", timer()-start)

start = timer()
print(monte_carlo_pi.py_func(num))
print("non-jitted", timer()-start)

结果是:

3.140936
jitted code 0.01403845699996964
3.14244
non-jitted 0.39901430800000526

请注意,您没有在GPU上运行固定代码。该代码已编译,但适用于您的CPU。Pi的计算值不同的原因可能是由于基础随机数生成器的实现方式不同。Numba实际上并没有使用Python的random模块,而是拥有自己的实现来模仿它。事实上,如果你看看源代码,它看起来好像基于numpy的的随机模块上的numba实现主要设计,然后只需别名random从该模块,所以如果你换出random.randomnp.random.random,使用相同的种子,你会得到相同的结果:

@jit(nopython=True)
def monte_carlo_pi2(nsamples):
    np.random.seed(0)
    acc = 0
    for i in range(nsamples):
        x = np.random.random()
        y = np.random.random()
        if (x ** 2 + y ** 2) < 1.0:
            acc += 1
    return 4.0 * acc / nsamples 

结果是:

3.140936
jitted code 0.013946142999998301
3.140936
non-jitted 0.9277294739999888

还有其他一些注意事项:

  • 对numba jitted函数进行计时时,请始终在执行基准测试之前运行一次该函数以对其进行编译,因此您不会在计时中包括一次性编译时间成本
  • 您可以使用来访问numba jitted函数的纯python版本.py_func,因此不必重复两次代码。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章