Cupy比numpy慢。

4

我尝试使用cupy而不是numpy来加快我的Python代码速度。然而问题在于,使用cupy后,我的代码速度变得更慢了。也许我在这个问题上有点太天真了。

也许有人能够找到我的代码中的瓶颈:

import cupy as np
import time as ti

def f(y, t):
    y_ = np.zeros(2 * N_1*N_2) # n: e-6, c: e-5
    for i in range(0, N_1*N_2):
        y_[i] = y[i + N_1*N_2] # n: e-7, c: e-5 or e-6
    for i in range(N_1*N_2):
        sum = -4*y[i] # n: e-7, c: e-7 after some statements e-5
        if (i + 1 in indexes) and (not (i in indi)):
            sum += y[i+1] # n: e-7, c: e-7 after some statements e-5
        if (i - 1) in indexes and (i % N_1 != 0):
            sum += y[i-1] # n: e-7, c: e-7 after some statements e-5
        if i + N_1 in indexes:
            sum += y[i+N_1] # n: e-7, c: e-7 after some statements e-5
        if i - N_1 in indexes:
            sum += y[i-N_1] # n: e-7, c: e-7 after some statements e-5
        y_[i + N_1*N_2] = sum

    return y_

def k_1(y, t, h):
    return np.asarray(f(y, t)) * h

def k_2(y, t, h):
    return np.asarray(f(np.add(np.asarray(y) , np.multiply(1/2 , k_1(y, t, h))), t + 1/2 * h)) * h

# k_2, k_4 look just like k_2, may be with an 1/2 here or there

# some init stuff is happening here

while t < T_end:
    # also some magic happening here which is just data saving
    y = np.asarray(y) + 1/6*(k_1(y, t, m) + 2*k_2(y, t, m) + 2*k_3(y, t, m) + k_4(y, t, m))
    t += m

编辑 我试图对我的代码进行基准测试,以下是一些结果,它们可以作为代码中的注释查看。每个数字代表一行。单位是秒。n:Numpy,c:CuPy,我主要给出了大致顺序的估计值。 此外,我还进行了其他测试。

np.multiply # n: e-6, c: e-5

and

np.add # n: e-5 or e-6, c: 0.005 or e-5

你有对执行缓慢的部分进行性能分析吗? - syntonym
@syntonym我编辑了问题。结果非常令人惊讶。 - Bomel
2个回答

1
你的代码之所以慢,并不是因为numpy慢,而是因为你调用了许多(Python)函数,而在Python中调用函数(以及迭代、访问对象和基本上所有Python操作)都很慢。因此,cupy对你没有帮助(但可能会损害性能,因为它需要做更多的设置,例如将数据复制到GPU)。如果你可以构思出使用较少Python函数的算法(向另一个答案中的矢量化),这将极大地加快你的代码速度(你可能不需要cupy)。
你还可以查看numba,它使用llvm将你的代码编译成本地代码。如果你这样做,请确保阅读一些文档并使用nopython=True,否则你只会将缓慢的cupy代码替换为缓慢的numba代码。

我也会看看你的建议。你知道返回语句是否会使数组留在GPU中吗? - Bomel
在你提出问题之前,我还没有见过Cupy,但就我所了解的而言,数据将存储在GPU上,而Python只是对它的引用。你还可以尝试编写Cupy的自定义内核代码 - syntonym

0

您的代码示例无法工作,因为您没有在任何地方定义N_1N_2indexesindi。另外,您在代码中的注释似乎并没有帮助其他人理解正在发生的事情。

如果您没有对代码中的操作进行矢量化,那么您的代码可能不会从numba/cupy中受益。在目前您代码的运行方式下,列表可能与numpy数组一样快。

如果您摆脱for循环并进行以下更改:

y_ = np.zeros(2 * N_1*N_2)
for i in range(0, N_1*N_2):
    y_[i] = y[i + N_1*N_2] 

n = N1*N2
y_ = np.zeros(2*n)
y_[:n] = y[n:2*n]

等等,这样做可以大大加快您的代码速度。


我已经注释掉了N_1、N_2、indexes和indi的定义,因为stackoverflow不允许我发布那么多代码。我将尝试实现向量化。 - Bomel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接